create-phoenixjs 0.1.4 → 0.1.6

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.
Files changed (52) hide show
  1. package/package.json +1 -1
  2. package/template/config/database.ts +13 -1
  3. package/template/database/migrations/2024_01_01_000000_create_test_users_cli_table.ts +16 -0
  4. package/template/database/migrations/20260108165704_TestCliMigration.ts +16 -0
  5. package/template/database/migrations/2026_01_08_16_57_04_CreateTestMigrationsTable.ts +21 -0
  6. package/template/framework/cli/artisan.ts +12 -0
  7. package/template/framework/cli/commands/MakeModelCommand.ts +33 -3
  8. package/template/framework/database/DatabaseManager.ts +133 -0
  9. package/template/framework/database/connection/Connection.ts +71 -0
  10. package/template/framework/database/connection/ConnectionFactory.ts +30 -0
  11. package/template/framework/database/connection/PostgresConnection.ts +159 -0
  12. package/template/framework/database/console/MakeMigrationCommand.ts +58 -0
  13. package/template/framework/database/console/MigrateCommand.ts +32 -0
  14. package/template/framework/database/console/MigrateResetCommand.ts +31 -0
  15. package/template/framework/database/console/MigrateRollbackCommand.ts +31 -0
  16. package/template/framework/database/console/MigrateStatusCommand.ts +38 -0
  17. package/template/framework/database/migrations/DatabaseMigrationRepository.ts +122 -0
  18. package/template/framework/database/migrations/Migration.ts +5 -0
  19. package/template/framework/database/migrations/MigrationRepository.ts +46 -0
  20. package/template/framework/database/migrations/Migrator.ts +249 -0
  21. package/template/framework/database/migrations/index.ts +4 -0
  22. package/template/framework/database/orm/BelongsTo.ts +246 -0
  23. package/template/framework/database/orm/BelongsToMany.ts +570 -0
  24. package/template/framework/database/orm/Builder.ts +160 -0
  25. package/template/framework/database/orm/EagerLoadingBuilder.ts +324 -0
  26. package/template/framework/database/orm/HasMany.ts +303 -0
  27. package/template/framework/database/orm/HasManyThrough.ts +282 -0
  28. package/template/framework/database/orm/HasOne.ts +201 -0
  29. package/template/framework/database/orm/HasOneThrough.ts +281 -0
  30. package/template/framework/database/orm/Model.ts +1802 -0
  31. package/template/framework/database/orm/Relation.ts +342 -0
  32. package/template/framework/database/orm/Scope.ts +14 -0
  33. package/template/framework/database/orm/SoftDeletes.ts +160 -0
  34. package/template/framework/database/orm/index.ts +54 -0
  35. package/template/framework/database/orm/scopes/SoftDeletingScope.ts +58 -0
  36. package/template/framework/database/pagination/LengthAwarePaginator.ts +55 -0
  37. package/template/framework/database/pagination/Paginator.ts +110 -0
  38. package/template/framework/database/pagination/index.ts +2 -0
  39. package/template/framework/database/query/Builder.ts +918 -0
  40. package/template/framework/database/query/DB.ts +139 -0
  41. package/template/framework/database/query/grammars/Grammar.ts +430 -0
  42. package/template/framework/database/query/grammars/PostgresGrammar.ts +224 -0
  43. package/template/framework/database/query/grammars/index.ts +6 -0
  44. package/template/framework/database/query/index.ts +8 -0
  45. package/template/framework/database/query/types.ts +196 -0
  46. package/template/framework/database/schema/Blueprint.ts +478 -0
  47. package/template/framework/database/schema/Schema.ts +149 -0
  48. package/template/framework/database/schema/SchemaBuilder.ts +152 -0
  49. package/template/framework/database/schema/grammars/PostgresSchemaGrammar.ts +293 -0
  50. package/template/framework/database/schema/grammars/index.ts +5 -0
  51. package/template/framework/database/schema/index.ts +9 -0
  52. package/template/package.json +4 -1
@@ -0,0 +1,246 @@
1
+ import { Relation } from './Relation';
2
+ import type { Model } from './Model';
3
+ import type { Binding } from '../query/types';
4
+
5
+ /**
6
+ * BelongsTo Relationship - Represents the inverse of a one-to-one or one-to-many.
7
+ *
8
+ * The foreign key is on the CURRENT model's table, referencing the parent.
9
+ *
10
+ * Example Schema:
11
+ * - users table: id, name, email
12
+ * - profiles table: id, user_id, bio
13
+ *
14
+ * The `user_id` column on `profiles` references `users.id`.
15
+ * Profile "belongs to" User.
16
+ *
17
+ * Usage:
18
+ * ```typescript
19
+ * class Profile extends Model {
20
+ * user() {
21
+ * return this.belongsTo(User, 'user_id', 'id');
22
+ * }
23
+ * }
24
+ *
25
+ * // Get the profile's user
26
+ * const profile = await Profile.find(1);
27
+ * const user = await profile.user().get();
28
+ * ```
29
+ *
30
+ * Also used for the inverse of HasMany:
31
+ * ```typescript
32
+ * class Post extends Model {
33
+ * author() {
34
+ * return this.belongsTo(User, 'user_id', 'id');
35
+ * }
36
+ * }
37
+ * ```
38
+ *
39
+ * @template TRelated - The type of the related (parent) model
40
+ */
41
+ export class BelongsTo<TRelated extends Model> extends Relation<TRelated> {
42
+ /**
43
+ * The foreign key on the child (current) model's table.
44
+ * Example: 'user_id' on profiles/posts table
45
+ */
46
+ protected foreignKey: string;
47
+
48
+ /**
49
+ * The owner (primary) key on the parent model's table.
50
+ * Example: 'id' on users table
51
+ */
52
+ protected ownerKey: string;
53
+
54
+ /**
55
+ * Create a new BelongsTo relationship instance.
56
+ *
57
+ * @param parent - The child model instance (the one with the foreign key)
58
+ * @param related - An instance of the parent model class
59
+ * @param foreignKey - The foreign key column on the child model (e.g., 'user_id')
60
+ * @param ownerKey - The owner key column on the parent model (e.g., 'id')
61
+ */
62
+ constructor(
63
+ parent: Model,
64
+ related: TRelated,
65
+ foreignKey: string,
66
+ ownerKey: string
67
+ ) {
68
+ super(parent, related);
69
+
70
+ this.foreignKey = foreignKey;
71
+ this.ownerKey = ownerKey;
72
+
73
+ // Re-add constraints now that keys are set
74
+ this.reinitializeConstraints();
75
+ }
76
+
77
+ /**
78
+ * Re-initialize constraints after keys are set.
79
+ */
80
+ private reinitializeConstraints(): void {
81
+ this.query = this.newQuery();
82
+ const foreignKeyValue = this.parent.getAttribute(this.foreignKey);
83
+
84
+ if (foreignKeyValue !== undefined && foreignKeyValue !== null) {
85
+ this.query.where(this.ownerKey, '=', foreignKeyValue as Binding);
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Add the constraints for the BelongsTo relationship.
91
+ * Called by parent constructor - keys may not be set yet.
92
+ */
93
+ public addConstraints(): void {
94
+ // Constraints are added in reinitializeConstraints after keys are set
95
+ }
96
+
97
+ /**
98
+ * Get the results of the BelongsTo relationship.
99
+ *
100
+ * Returns the parent model or null if none exists.
101
+ *
102
+ * @returns The parent model or null
103
+ */
104
+ public async getResults(): Promise<TRelated | null> {
105
+ const foreignKeyValue = this.parent.getAttribute(this.foreignKey);
106
+
107
+ // If child doesn't have a foreign key value, return null
108
+ if (foreignKeyValue === undefined || foreignKeyValue === null) {
109
+ return null;
110
+ }
111
+
112
+ return this.first();
113
+ }
114
+
115
+ /**
116
+ * Associate a parent model with this child model.
117
+ *
118
+ * This sets the foreign key on the child model to the parent's primary key.
119
+ * Note: This does NOT save the child model - you must call save() yourself.
120
+ *
121
+ * Usage:
122
+ * ```typescript
123
+ * const profile = new Profile({ bio: 'Hello' });
124
+ * const user = await User.find(1);
125
+ * profile.user().associate(user);
126
+ * await profile.save();
127
+ * ```
128
+ *
129
+ * @param model - The parent model to associate
130
+ * @returns The child model for chaining
131
+ */
132
+ public associate(model: TRelated): Model {
133
+ const ownerKeyValue = model.getAttribute(this.ownerKey);
134
+ this.parent.setAttribute(this.foreignKey, ownerKeyValue);
135
+ return this.parent;
136
+ }
137
+
138
+ /**
139
+ * Dissociate the parent model from this child model.
140
+ *
141
+ * This sets the foreign key on the child model to null.
142
+ * Note: This does NOT save the child model - you must call save() yourself.
143
+ *
144
+ * Usage:
145
+ * ```typescript
146
+ * const profile = await Profile.find(1);
147
+ * profile.user().dissociate();
148
+ * await profile.save();
149
+ * ```
150
+ *
151
+ * @returns The child model for chaining
152
+ */
153
+ public dissociate(): Model {
154
+ this.parent.setAttribute(this.foreignKey, null);
155
+ return this.parent;
156
+ }
157
+
158
+ /**
159
+ * Get the foreign key column name.
160
+ *
161
+ * @returns The foreign key column name
162
+ */
163
+ public getForeignKeyName(): string {
164
+ return this.foreignKey;
165
+ }
166
+
167
+ /**
168
+ * Get the fully qualified foreign key name (table.column).
169
+ *
170
+ * @returns The qualified foreign key name
171
+ */
172
+ public getQualifiedForeignKeyName(): string {
173
+ return this.qualifyColumn(this.parent.getTable(), this.foreignKey);
174
+ }
175
+
176
+ /**
177
+ * Get the owner key column name.
178
+ *
179
+ * @returns The owner key column name
180
+ */
181
+ public getOwnerKeyName(): string {
182
+ return this.ownerKey;
183
+ }
184
+
185
+ /**
186
+ * Get the value of the child's foreign key.
187
+ *
188
+ * @returns The foreign key value
189
+ */
190
+ public getForeignKeyValue(): unknown {
191
+ return this.parent.getAttribute(this.foreignKey);
192
+ }
193
+
194
+ // ==========================================
195
+ // Eager Loading Methods
196
+ // ==========================================
197
+
198
+ /**
199
+ * Add constraints for eager loading.
200
+ * Uses WHERE IN to fetch all parent models for multiple children at once.
201
+ *
202
+ * @param models - Array of child models to load parents for
203
+ */
204
+ public addEagerConstraints(models: Model[]): void {
205
+ // Collect all foreign key values from child models
206
+ const keys: unknown[] = [];
207
+ for (const model of models) {
208
+ const key = model.getAttribute(this.foreignKey);
209
+ if (key !== undefined && key !== null) {
210
+ keys.push(key);
211
+ }
212
+ }
213
+
214
+ // Remove duplicates
215
+ const uniqueKeys = [...new Set(keys)];
216
+
217
+ // Add WHERE IN constraint on the owner key
218
+ if (uniqueKeys.length > 0) {
219
+ this.query.whereIn(this.ownerKey, uniqueKeys as (string | number | boolean)[]);
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Match the eagerly loaded results to their child models.
225
+ * For BelongsTo, each child gets at most one parent model.
226
+ *
227
+ * @param models - Array of child models
228
+ * @param results - Array of parent models that were loaded
229
+ * @param relation - The name of the relationship being matched
230
+ */
231
+ public match(models: Model[], results: TRelated[], relation: string): void {
232
+ // Build a dictionary for O(1) lookup: ownerKey value -> parent model
233
+ const dictionary = new Map<unknown, TRelated>();
234
+ for (const result of results) {
235
+ const ownerKeyValue = result.getAttribute(this.ownerKey);
236
+ dictionary.set(ownerKeyValue, result);
237
+ }
238
+
239
+ // Match each child model with its parent model
240
+ for (const model of models) {
241
+ const foreignKeyValue = model.getAttribute(this.foreignKey);
242
+ const match = dictionary.get(foreignKeyValue) || null;
243
+ model.setRelation(relation, match);
244
+ }
245
+ }
246
+ }