Skip to content

Commit f2dd856

Browse files
committed
refactor(typeorm-database): restructure seeders and factories
add seed for acl e2e test
1 parent f81f419 commit f2dd856

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+2280
-347
lines changed
Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
import { DataSource } from 'typeorm';
22

3-
const configSeeder = {
4-
seeders: ['./libs/database/src/lib/seeders/*.ts'],
5-
defaultSeeder: 'RootSeeder',
6-
};
7-
83
import { join } from 'node:path';
94
import { pgConfig } from './config-db';
105

116
export default new DataSource({
127
...pgConfig,
13-
...configSeeder,
148
migrations: [join(__dirname, '/migrations-pg/**/*{.ts,.js}')],
159
});
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import {
2+
Entity,
3+
PrimaryGeneratedColumn,
4+
Column,
5+
ManyToOne,
6+
JoinColumn,
7+
UpdateDateColumn,
8+
} from 'typeorm';
9+
import { UsersAcl, IUsersAcl } from './user.entity';
10+
11+
export enum ArticleStatus {
12+
DRAFT = 'draft',
13+
REVIEW = 'review',
14+
PUBLISHED = 'published',
15+
}
16+
17+
export enum ArticleVisibility {
18+
PUBLIC = 'public',
19+
PRIVATE = 'private',
20+
UNLISTED = 'unlisted',
21+
}
22+
23+
export interface ArticleMetadata {
24+
readTime: number;
25+
featured: boolean;
26+
premium: boolean;
27+
}
28+
29+
export type IArticleAcl = ArticleAcl;
30+
31+
/**
32+
* Article entity for ACL testing - Complex scenarios
33+
*
34+
* ACL Test Cases:
35+
* - Multiple owners (authorId OR coAuthorIds.includes(userId))
36+
* - Array conditions (checking if userId in coAuthorIds array)
37+
* - Nested object conditions (metadata.premium)
38+
* - Time-based access (expiresAt > now)
39+
* - Complex workflows (draft -> review -> published)
40+
* - Editor role (separate from author)
41+
* - Template: ${@input.coAuthorIds}, ${metadata.premium}, ${currentTime}
42+
*/
43+
@Entity('acl_articles')
44+
export class ArticleAcl {
45+
@PrimaryGeneratedColumn()
46+
public id!: number;
47+
48+
@Column({
49+
type: 'varchar',
50+
length: 255,
51+
nullable: false,
52+
})
53+
public title!: string;
54+
55+
@Column({
56+
type: 'text',
57+
nullable: false,
58+
})
59+
public content!: string;
60+
61+
/**
62+
* Primary author (ownership)
63+
*/
64+
@ManyToOne(() => UsersAcl, (user) => user.authoredArticles, {
65+
nullable: false,
66+
})
67+
@JoinColumn({
68+
name: 'author_id',
69+
})
70+
public author!: IUsersAcl;
71+
72+
/**
73+
* Co-authors array for multiple ownership testing
74+
* ACL: Check if currentUserId in this array
75+
*/
76+
@Column({
77+
name: 'co_author_ids',
78+
type: 'int',
79+
array: true,
80+
nullable: false,
81+
default: () => "'{}'",
82+
})
83+
public coAuthorIds!: number[];
84+
85+
/**
86+
* Editor (different from author/co-authors)
87+
* Can edit but not delete
88+
*/
89+
@ManyToOne(() => UsersAcl, (user) => user.editedArticles, {
90+
nullable: true,
91+
})
92+
@JoinColumn({
93+
name: 'editor_id',
94+
})
95+
public editor!: IUsersAcl | null;
96+
97+
/**
98+
* Workflow status
99+
*/
100+
@Column({
101+
type: 'enum',
102+
enum: ArticleStatus,
103+
default: ArticleStatus.DRAFT,
104+
})
105+
public status!: ArticleStatus;
106+
107+
/**
108+
* Visibility control
109+
*/
110+
@Column({
111+
type: 'enum',
112+
enum: ArticleVisibility,
113+
default: ArticleVisibility.PUBLIC,
114+
})
115+
public visibility!: ArticleVisibility;
116+
117+
/**
118+
* Metadata as JSON object
119+
* ACL: Check nested properties like metadata.premium
120+
*/
121+
@Column({
122+
type: 'json',
123+
nullable: false,
124+
default: '{"readTime": 0, "featured": false, "premium": false}',
125+
})
126+
public metadata!: ArticleMetadata;
127+
128+
/**
129+
* Publish date for time-based access
130+
*/
131+
@Column({
132+
name: 'published_at',
133+
type: 'timestamp',
134+
nullable: true,
135+
})
136+
public publishedAt!: Date | null;
137+
138+
/**
139+
* Expiration date for temporary access
140+
* ACL: Check if current time < expiresAt
141+
*/
142+
@Column({
143+
name: 'expires_at',
144+
type: 'timestamp',
145+
nullable: true,
146+
})
147+
public expiresAt!: Date | null;
148+
149+
@Column({
150+
name: 'created_at',
151+
type: 'timestamp',
152+
nullable: false,
153+
default: () => 'CURRENT_TIMESTAMP',
154+
})
155+
createdAt: Date = new Date();
156+
157+
@UpdateDateColumn({
158+
name: 'updated_at',
159+
type: 'timestamp',
160+
nullable: false,
161+
default: () => 'CURRENT_TIMESTAMP',
162+
})
163+
updatedAt: Date = new Date();
164+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import {
2+
Entity,
3+
PrimaryGeneratedColumn,
4+
Column,
5+
ManyToOne,
6+
OneToMany,
7+
JoinColumn,
8+
UpdateDateColumn,
9+
} from 'typeorm';
10+
11+
export type ICategoryAcl = CategoryAcl;
12+
13+
/**
14+
* Category entity for ACL testing
15+
* Self-referencing hierarchical structure
16+
*
17+
* ACL Test Cases:
18+
* - Hierarchical permissions (parent -> children access)
19+
* - Self-referencing relationships
20+
* - Depth-based access control (level)
21+
* - Active/inactive categories
22+
* - Template: ${@input.parentId}, ${category.parent.id}
23+
*/
24+
@Entity('acl_categories')
25+
export class CategoryAcl {
26+
@PrimaryGeneratedColumn()
27+
public id!: number;
28+
29+
@Column({
30+
type: 'varchar',
31+
length: 100,
32+
nullable: false,
33+
})
34+
public name!: string;
35+
36+
@Column({
37+
type: 'varchar',
38+
length: 150,
39+
nullable: false,
40+
unique: true,
41+
})
42+
public slug!: string;
43+
44+
/**
45+
* Self-referencing parent category
46+
*/
47+
@ManyToOne(() => CategoryAcl, (category) => category.children, {
48+
nullable: true,
49+
})
50+
@JoinColumn({
51+
name: 'parent_id',
52+
})
53+
public parent!: CategoryAcl | null;
54+
55+
/**
56+
* Self-referencing children categories
57+
*/
58+
@OneToMany(() => CategoryAcl, (category) => category.parent)
59+
public children!: CategoryAcl[];
60+
61+
/**
62+
* Depth level in hierarchy
63+
* 0 = root category, 1 = first level child, etc.
64+
*/
65+
@Column({
66+
type: 'integer',
67+
default: 0,
68+
})
69+
public level!: number;
70+
71+
/**
72+
* Active/inactive flag for access control
73+
*/
74+
@Column({
75+
name: 'is_active',
76+
type: 'boolean',
77+
default: true,
78+
})
79+
public isActive!: boolean;
80+
81+
@Column({
82+
type: 'text',
83+
nullable: true,
84+
})
85+
public description!: string | null;
86+
87+
@Column({
88+
name: 'created_at',
89+
type: 'timestamp',
90+
nullable: false,
91+
default: () => 'CURRENT_TIMESTAMP',
92+
})
93+
createdAt: Date = new Date();
94+
95+
@UpdateDateColumn({
96+
name: 'updated_at',
97+
type: 'timestamp',
98+
nullable: false,
99+
default: () => 'CURRENT_TIMESTAMP',
100+
})
101+
updatedAt: Date = new Date();
102+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import {
2+
Entity,
3+
PrimaryGeneratedColumn,
4+
Column,
5+
ManyToOne,
6+
JoinColumn,
7+
UpdateDateColumn,
8+
} from 'typeorm';
9+
import { UsersAcl, IUsersAcl } from './user.entity';
10+
import { PostAcl } from './post.entity';
11+
12+
export type ICommentAcl = CommentAcl;
13+
14+
/**
15+
* Comment entity for ACL testing
16+
* Many-to-One with Post and Users
17+
*
18+
* ACL Test Cases:
19+
* - Nested ownership (comment.authorId === currentUserId)
20+
* - Moderation (isApproved - only moderator/admin can approve)
21+
* - Relationship chain (User -> Comment -> Post)
22+
* - Template: ${@input.postId}, ${post.authorId}
23+
*/
24+
@Entity('acl_comments')
25+
export class CommentAcl {
26+
@PrimaryGeneratedColumn()
27+
public id!: number;
28+
29+
/**
30+
* Post that this comment belongs to
31+
*/
32+
@ManyToOne(() => PostAcl, (post) => post.comments, {
33+
nullable: false,
34+
})
35+
@JoinColumn({
36+
name: 'post_id',
37+
})
38+
public post!: PostAcl;
39+
40+
/**
41+
* Author of the comment (ownership)
42+
*/
43+
@ManyToOne(() => UsersAcl, (user) => user.aclComments, {
44+
nullable: false,
45+
})
46+
@JoinColumn({
47+
name: 'author_id',
48+
})
49+
public author!: IUsersAcl;
50+
51+
@Column({
52+
type: 'text',
53+
nullable: false,
54+
})
55+
public content!: string;
56+
57+
/**
58+
* Moderation flag - only moderator/admin can approve
59+
*/
60+
@Column({
61+
name: 'is_approved',
62+
type: 'boolean',
63+
default: false,
64+
})
65+
public isApproved!: boolean;
66+
67+
/**
68+
* Edit flag to track if comment was modified
69+
*/
70+
@Column({
71+
name: 'is_edited',
72+
type: 'boolean',
73+
default: false,
74+
})
75+
public isEdited!: boolean;
76+
77+
@Column({
78+
name: 'created_at',
79+
type: 'timestamp',
80+
nullable: false,
81+
default: () => 'CURRENT_TIMESTAMP',
82+
})
83+
createdAt: Date = new Date();
84+
85+
@UpdateDateColumn({
86+
name: 'updated_at',
87+
type: 'timestamp',
88+
nullable: false,
89+
default: () => 'CURRENT_TIMESTAMP',
90+
})
91+
updatedAt: Date = new Date();
92+
}

0 commit comments

Comments
 (0)