@apso/cli 0.1.0 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const globals_1 = require("@jest/globals");
4
+ const parse_1 = require("./parse");
5
+ (0, globals_1.describe)('parseRelationships', () => {
6
+ // Mock console.warn to prevent test output clutter
7
+ (0, globals_1.beforeEach)(() => {
8
+ globals_1.jest.spyOn(console, 'warn').mockImplementation(() => { });
9
+ });
10
+ (0, globals_1.afterEach)(() => {
11
+ globals_1.jest.restoreAllMocks();
12
+ });
13
+ (0, globals_1.describe)('ManyToMany Relationships', () => {
14
+ (0, globals_1.it)('should parse a single bidirectional ManyToMany definition', () => {
15
+ const relationships = [
16
+ {
17
+ from: 'EntityA',
18
+ to: 'EntityB',
19
+ type: 'ManyToMany',
20
+ // eslint-disable-next-line camelcase
21
+ bi_directional: true,
22
+ },
23
+ ];
24
+ const expected = {
25
+ EntityA: [
26
+ {
27
+ name: 'EntityB',
28
+ type: 'ManyToMany',
29
+ referenceName: 'entitybs',
30
+ join: true,
31
+ biDirectional: true,
32
+ joinTableName: undefined,
33
+ joinColumnName: undefined,
34
+ inverseJoinColumnName: undefined,
35
+ inverseReferenceName: 'entityas', // Simplified default
36
+ },
37
+ ],
38
+ EntityB: [
39
+ {
40
+ name: 'EntityA',
41
+ type: 'ManyToMany',
42
+ referenceName: 'entityas',
43
+ join: false,
44
+ biDirectional: true,
45
+ joinTableName: undefined,
46
+ joinColumnName: undefined,
47
+ inverseJoinColumnName: undefined,
48
+ inverseReferenceName: 'entitybs', // Simplified default
49
+ },
50
+ ],
51
+ };
52
+ const result = (0, parse_1.parseRelationships)(relationships);
53
+ (0, globals_1.expect)(result).toEqual(expected);
54
+ });
55
+ (0, globals_1.it)('should parse a single bidirectional ManyToMany with to_name', () => {
56
+ const relationships = [
57
+ {
58
+ from: 'User',
59
+ to: 'Group',
60
+ type: 'ManyToMany',
61
+ // eslint-disable-next-line camelcase
62
+ bi_directional: true,
63
+ // eslint-disable-next-line camelcase
64
+ to_name: 'userGroups',
65
+ },
66
+ ];
67
+ const expected = {
68
+ User: [
69
+ {
70
+ name: 'Group',
71
+ type: 'ManyToMany',
72
+ referenceName: 'userGroups',
73
+ join: true,
74
+ biDirectional: true,
75
+ joinTableName: undefined,
76
+ joinColumnName: undefined,
77
+ inverseJoinColumnName: undefined,
78
+ inverseReferenceName: 'users', // Simplified default
79
+ },
80
+ ],
81
+ Group: [
82
+ {
83
+ name: 'User',
84
+ type: 'ManyToMany',
85
+ referenceName: 'users',
86
+ join: false,
87
+ biDirectional: true,
88
+ joinTableName: undefined,
89
+ joinColumnName: undefined,
90
+ inverseJoinColumnName: undefined,
91
+ inverseReferenceName: 'userGroups', // Expect preserved camelCase
92
+ },
93
+ ],
94
+ };
95
+ const result = (0, parse_1.parseRelationships)(relationships);
96
+ (0, globals_1.expect)(result).toEqual(expected);
97
+ });
98
+ (0, globals_1.it)('should parse a unidirectional ManyToMany definition', () => {
99
+ const relationships = [
100
+ {
101
+ from: 'Post',
102
+ to: 'Tag',
103
+ type: 'ManyToMany',
104
+ // bi_directional is false or omitted
105
+ },
106
+ ];
107
+ const expected = {
108
+ Post: [
109
+ {
110
+ name: 'Tag',
111
+ type: 'ManyToMany',
112
+ referenceName: 'tags',
113
+ join: true,
114
+ biDirectional: false,
115
+ joinTableName: undefined,
116
+ joinColumnName: undefined,
117
+ inverseJoinColumnName: undefined,
118
+ inverseReferenceName: undefined, // Correct: No inverse name for unidirectional
119
+ },
120
+ ],
121
+ // No entry expected for Tag
122
+ };
123
+ const result = (0, parse_1.parseRelationships)(relationships);
124
+ (0, globals_1.expect)(result).toEqual(expected);
125
+ });
126
+ (0, globals_1.it)('should handle join table details correctly', () => {
127
+ const relationships = [
128
+ {
129
+ from: 'Student',
130
+ to: 'Course',
131
+ type: 'ManyToMany',
132
+ // eslint-disable-next-line camelcase
133
+ bi_directional: true,
134
+ // UNUSED: eslint-disable-next-line camelcase
135
+ joinTableName: 'enrollments',
136
+ // UNUSED: eslint-disable-next-line camelcase
137
+ joinColumnName: 'student_id',
138
+ // UNUSED: eslint-disable-next-line camelcase
139
+ inverseJoinColumnName: 'course_id',
140
+ },
141
+ ];
142
+ const expected = {
143
+ Student: [
144
+ {
145
+ name: 'Course',
146
+ type: 'ManyToMany',
147
+ referenceName: 'courses',
148
+ join: true,
149
+ biDirectional: true,
150
+ joinTableName: 'enrollments',
151
+ joinColumnName: 'student_id',
152
+ inverseJoinColumnName: 'course_id',
153
+ inverseReferenceName: 'students', // Simplified default
154
+ },
155
+ ],
156
+ Course: [
157
+ {
158
+ name: 'Student',
159
+ type: 'ManyToMany',
160
+ referenceName: 'students',
161
+ join: false,
162
+ biDirectional: true,
163
+ joinTableName: undefined,
164
+ joinColumnName: undefined,
165
+ inverseJoinColumnName: undefined,
166
+ inverseReferenceName: 'courses', // Simplified default
167
+ },
168
+ ],
169
+ };
170
+ const result = (0, parse_1.parseRelationships)(relationships);
171
+ (0, globals_1.expect)(result).toEqual(expected);
172
+ });
173
+ });
174
+ (0, globals_1.describe)('Mixed Relationship Types', () => {
175
+ (0, globals_1.it)('should correctly parse ManyToMany alongside other types', () => {
176
+ const relationships = [
177
+ {
178
+ from: 'User',
179
+ to: 'Profile',
180
+ type: 'OneToOne',
181
+ // eslint-disable-next-line camelcase
182
+ bi_directional: true,
183
+ // eslint-disable-next-line camelcase
184
+ to_name: 'userProfile'
185
+ },
186
+ {
187
+ from: 'User',
188
+ to: 'Post',
189
+ type: 'OneToMany',
190
+ // eslint-disable-next-line camelcase
191
+ bi_directional: true // Implies ManyToOne on Post
192
+ },
193
+ {
194
+ from: 'Role',
195
+ to: 'User',
196
+ type: 'ManyToMany',
197
+ // eslint-disable-next-line camelcase
198
+ bi_directional: true
199
+ }
200
+ ];
201
+ const result = (0, parse_1.parseRelationships)(relationships);
202
+ // Check User relationships
203
+ (0, globals_1.expect)(result.User).toHaveLength(3);
204
+ (0, globals_1.expect)(result.User).toContainEqual(globals_1.expect.objectContaining({ name: 'Profile', type: 'OneToOne', referenceName: 'userProfile', biDirectional: true, join: false })); // Expect preserved camelCase
205
+ (0, globals_1.expect)(result.User).toContainEqual(globals_1.expect.objectContaining({ name: 'Post', type: 'OneToMany', referenceName: 'posts', biDirectional: true })); // Simplified default
206
+ (0, globals_1.expect)(result.User).toContainEqual(globals_1.expect.objectContaining({ name: 'Role', type: 'ManyToMany', referenceName: 'roles', biDirectional: true, join: false })); // Simplified default
207
+ // Check Profile relationship
208
+ (0, globals_1.expect)(result.Profile).toHaveLength(1);
209
+ (0, globals_1.expect)(result.Profile).toContainEqual(globals_1.expect.objectContaining({ name: 'User', type: 'OneToOne', referenceName: 'user', biDirectional: true, join: true })); // Simplified default singular
210
+ // Check Post relationship
211
+ (0, globals_1.expect)(result.Post).toHaveLength(1);
212
+ (0, globals_1.expect)(result.Post).toContainEqual(globals_1.expect.objectContaining({ name: 'User', type: 'ManyToOne', referenceName: 'user', biDirectional: true })); // Simplified default singular
213
+ // Check Role relationship
214
+ (0, globals_1.expect)(result.Role).toHaveLength(1);
215
+ (0, globals_1.expect)(result.Role).toContainEqual(globals_1.expect.objectContaining({ name: 'User', type: 'ManyToMany', referenceName: 'users', biDirectional: true, join: true })); // Simplified default
216
+ });
217
+ });
218
+ });
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const globals_1 = require("@jest/globals");
4
+ const parse_1 = require("../../lib/utils/relationships/parse");
5
+ (0, globals_1.describe)("getRelationshipForTemplate deduplication", () => {
6
+ (0, globals_1.test)("should deduplicate ManyToMany relationships", () => {
7
+ // Mock entity name
8
+ const entityName = "CustomerCard";
9
+ // Mock relationships - simulating bidirectional ManyToMany where
10
+ // both sides are added to the relationships array for the same entity
11
+ const mockRelationships = [
12
+ // First ManyToMany relationship (non-join side)
13
+ {
14
+ name: "Subscription",
15
+ type: "ManyToMany",
16
+ referenceName: "subscriptions",
17
+ biDirectional: true,
18
+ join: false,
19
+ inverseReferenceName: "customercards"
20
+ },
21
+ // Duplicate relationship (join side) - similar to what happens in bidirectional ManyToMany
22
+ {
23
+ name: "Subscription",
24
+ type: "ManyToMany",
25
+ referenceName: "subscriptions",
26
+ biDirectional: true,
27
+ join: true,
28
+ inverseReferenceName: "customercards"
29
+ }
30
+ ];
31
+ // Run the function
32
+ const result = (0, parse_1.getRelationshipForTemplate)(entityName, mockRelationships);
33
+ // Assertions
34
+ // 1. Should only have one relationship
35
+ (0, globals_1.expect)(result.length).toBe(1);
36
+ // 2. The remaining relationship should be the one with join=true
37
+ (0, globals_1.expect)(result[0].name).toBe("Subscription");
38
+ (0, globals_1.expect)(result[0].joinTable).toBe(true);
39
+ });
40
+ (0, globals_1.test)("should keep first relationship when reference names differ", () => {
41
+ // Mock entity name
42
+ const entityName = "User";
43
+ // Create mocked relationships with same target but different reference names
44
+ const mockRelationships = [
45
+ {
46
+ name: "Workspace",
47
+ type: "ManyToMany",
48
+ referenceName: "workspaces",
49
+ biDirectional: true,
50
+ join: true
51
+ },
52
+ {
53
+ name: "Workspace",
54
+ type: "ManyToMany",
55
+ referenceName: "ownedWorkspaces",
56
+ biDirectional: true,
57
+ join: true
58
+ }
59
+ ];
60
+ // Run the function
61
+ const result = (0, parse_1.getRelationshipForTemplate)(entityName, mockRelationships);
62
+ // Assertions
63
+ // Current behavior: Only one relationship is kept during name-based deduplication (second phase)
64
+ (0, globals_1.expect)(result.length).toBe(1);
65
+ // The first one is kept in the Set processing
66
+ (0, globals_1.expect)(result[0].relationshipName).toBe("workspaces");
67
+ });
68
+ (0, globals_1.test)("should prioritize owner side (join=true) when deduplicating", () => {
69
+ // Scenario based on real issue: two ManyToMany relationships to same entity
70
+ const entityName = "Tag";
71
+ // Create relationships where one has join=true and one has join=false (non-owning side)
72
+ const mockRelationships = [
73
+ {
74
+ name: "WorkspaceService",
75
+ type: "ManyToMany",
76
+ biDirectional: true,
77
+ join: false,
78
+ referenceName: "workspaceservices"
79
+ },
80
+ {
81
+ name: "WorkspaceService",
82
+ type: "ManyToMany",
83
+ biDirectional: true,
84
+ join: true,
85
+ referenceName: "workspaceservices"
86
+ }
87
+ ];
88
+ // Run the function
89
+ const result = (0, parse_1.getRelationshipForTemplate)(entityName, mockRelationships);
90
+ // Assertions
91
+ // Should only have one relationship
92
+ (0, globals_1.expect)(result.length).toBe(1);
93
+ // Should be the one with join=true
94
+ (0, globals_1.expect)(result[0].name).toBe("WorkspaceService");
95
+ (0, globals_1.expect)(result[0].joinTable).toBe(true); // joinTable corresponds to join
96
+ });
97
+ });
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.0",
2
+ "version": "0.1.4",
3
3
  "commands": {
4
4
  "server:new": {
5
5
  "id": "server:new",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apso/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.4",
4
4
  "description": "Apso CLI",
5
5
  "author": "Apso by Mavric - @mavric",
6
6
  "bin": {
@@ -56,6 +56,7 @@
56
56
  "ts-jest": "^29.1.0",
57
57
  "ts-node": "^10.9.1",
58
58
  "tslib": "^2.5.0",
59
+ "typedoc": "^0.28.3",
59
60
  "typescript": "^5"
60
61
  },
61
62
  "oclif": {
@@ -86,6 +87,7 @@
86
87
  "test": "jest",
87
88
  "test:watch": "jest --watch",
88
89
  "test:cov": "jest --coverage",
90
+ "docs:generate": "typedoc src/lib/index.ts --out docs",
89
91
  "version": "oclif readme && git add README.md"
90
92
  },
91
93
  "engines": {