@statezero/core 0.2.16 → 0.2.18

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 (136) hide show
  1. package/LICENSE +116 -116
  2. package/dist/adaptors/vue/composables.js +4 -4
  3. package/dist/cli/commands/syncActions.js +189 -189
  4. package/dist/cli/commands/syncModels.js +391 -391
  5. package/dist/core/eventReceivers.d.ts +1 -2
  6. package/dist/core/eventReceivers.js +16 -16
  7. package/dist/filtering/localFiltering.js +2 -1
  8. package/dist/flavours/django/f.js +1 -1
  9. package/dist/flavours/django/model.js +1 -1
  10. package/dist/flavours/django/operationFactory.d.ts +1 -1
  11. package/dist/flavours/django/operationFactory.js +1 -1
  12. package/dist/syncEngine/metrics/metricOptCalcs.js +1 -1
  13. package/dist/syncEngine/registries/metricRegistry.d.ts +1 -1
  14. package/dist/syncEngine/registries/metricRegistry.js +3 -3
  15. package/dist/syncEngine/stores/metricStore.d.ts +1 -1
  16. package/dist/syncEngine/stores/metricStore.js +1 -1
  17. package/dist/syncEngine/stores/operation.d.ts +1 -1
  18. package/dist/syncEngine/stores/operation.js +1 -1
  19. package/dist/syncEngine/stores/reactivity.d.ts +3 -3
  20. package/dist/syncEngine/stores/utils.js +1 -1
  21. package/dist/syncEngine/sync.d.ts +2 -1
  22. package/dist/syncEngine/sync.js +10 -9
  23. package/package.json +128 -126
  24. package/readme.md +210 -210
  25. package/dist/actions/backend1/django_app/calculate-hash.d.ts +0 -57
  26. package/dist/actions/backend1/django_app/calculate-hash.js +0 -80
  27. package/dist/actions/backend1/django_app/get-current-username.d.ts +0 -29
  28. package/dist/actions/backend1/django_app/get-current-username.js +0 -65
  29. package/dist/actions/backend1/django_app/get-server-status.d.ts +0 -38
  30. package/dist/actions/backend1/django_app/get-server-status.js +0 -68
  31. package/dist/actions/backend1/django_app/get-user-info.d.ts +0 -44
  32. package/dist/actions/backend1/django_app/get-user-info.js +0 -70
  33. package/dist/actions/backend1/django_app/index.d.ts +0 -6
  34. package/dist/actions/backend1/django_app/index.js +0 -6
  35. package/dist/actions/backend1/django_app/process-data.d.ts +0 -51
  36. package/dist/actions/backend1/django_app/process-data.js +0 -78
  37. package/dist/actions/backend1/django_app/send-notification.d.ts +0 -55
  38. package/dist/actions/backend1/django_app/send-notification.js +0 -81
  39. package/dist/actions/backend1/index.d.ts +0 -1
  40. package/dist/actions/backend1/index.js +0 -1
  41. package/dist/actions/default/django_app/calculate-hash.d.ts +0 -57
  42. package/dist/actions/default/django_app/calculate-hash.js +0 -80
  43. package/dist/actions/default/django_app/get-current-username.d.ts +0 -29
  44. package/dist/actions/default/django_app/get-current-username.js +0 -65
  45. package/dist/actions/default/django_app/get-server-status.d.ts +0 -38
  46. package/dist/actions/default/django_app/get-server-status.js +0 -68
  47. package/dist/actions/default/django_app/get-user-info.d.ts +0 -44
  48. package/dist/actions/default/django_app/get-user-info.js +0 -70
  49. package/dist/actions/default/django_app/index.d.ts +0 -6
  50. package/dist/actions/default/django_app/index.js +0 -6
  51. package/dist/actions/default/django_app/process-data.d.ts +0 -51
  52. package/dist/actions/default/django_app/process-data.js +0 -78
  53. package/dist/actions/default/django_app/send-notification.d.ts +0 -55
  54. package/dist/actions/default/django_app/send-notification.js +0 -81
  55. package/dist/actions/default/index.d.ts +0 -1
  56. package/dist/actions/default/index.js +0 -1
  57. package/dist/actions/index.d.ts +0 -1
  58. package/dist/actions/index.js +0 -5
  59. package/dist/models/backend1/django_app/comprehensivemodel.d.ts +0 -47
  60. package/dist/models/backend1/django_app/comprehensivemodel.js +0 -71
  61. package/dist/models/backend1/django_app/custompkmodel.d.ts +0 -44
  62. package/dist/models/backend1/django_app/custompkmodel.js +0 -69
  63. package/dist/models/backend1/django_app/dailyrate.d.ts +0 -47
  64. package/dist/models/backend1/django_app/dailyrate.js +0 -71
  65. package/dist/models/backend1/django_app/deepmodellevel1.d.ts +0 -47
  66. package/dist/models/backend1/django_app/deepmodellevel1.js +0 -72
  67. package/dist/models/backend1/django_app/deepmodellevel2.d.ts +0 -47
  68. package/dist/models/backend1/django_app/deepmodellevel2.js +0 -71
  69. package/dist/models/backend1/django_app/deepmodellevel3.d.ts +0 -44
  70. package/dist/models/backend1/django_app/deepmodellevel3.js +0 -69
  71. package/dist/models/backend1/django_app/dummymodel.d.ts +0 -47
  72. package/dist/models/backend1/django_app/dummymodel.js +0 -71
  73. package/dist/models/backend1/django_app/dummyrelatedmodel.d.ts +0 -44
  74. package/dist/models/backend1/django_app/dummyrelatedmodel.js +0 -69
  75. package/dist/models/backend1/django_app/filetest.d.ts +0 -44
  76. package/dist/models/backend1/django_app/filetest.js +0 -69
  77. package/dist/models/backend1/django_app/index.d.ts +0 -16
  78. package/dist/models/backend1/django_app/index.js +0 -16
  79. package/dist/models/backend1/django_app/modelwithcustompkrelation.d.ts +0 -47
  80. package/dist/models/backend1/django_app/modelwithcustompkrelation.js +0 -71
  81. package/dist/models/backend1/django_app/namefiltercustompkmodel.d.ts +0 -44
  82. package/dist/models/backend1/django_app/namefiltercustompkmodel.js +0 -69
  83. package/dist/models/backend1/django_app/order.d.ts +0 -47
  84. package/dist/models/backend1/django_app/order.js +0 -71
  85. package/dist/models/backend1/django_app/orderitem.d.ts +0 -47
  86. package/dist/models/backend1/django_app/orderitem.js +0 -72
  87. package/dist/models/backend1/django_app/product.d.ts +0 -47
  88. package/dist/models/backend1/django_app/product.js +0 -71
  89. package/dist/models/backend1/django_app/productcategory.d.ts +0 -44
  90. package/dist/models/backend1/django_app/productcategory.js +0 -69
  91. package/dist/models/backend1/django_app/rateplan.d.ts +0 -44
  92. package/dist/models/backend1/django_app/rateplan.js +0 -69
  93. package/dist/models/backend1/fileobject.d.ts +0 -4
  94. package/dist/models/backend1/fileobject.js +0 -9
  95. package/dist/models/backend1/index.d.ts +0 -2
  96. package/dist/models/backend1/index.js +0 -2
  97. package/dist/models/default/django_app/comprehensivemodel.d.ts +0 -47
  98. package/dist/models/default/django_app/comprehensivemodel.js +0 -71
  99. package/dist/models/default/django_app/custompkmodel.d.ts +0 -44
  100. package/dist/models/default/django_app/custompkmodel.js +0 -69
  101. package/dist/models/default/django_app/dailyrate.d.ts +0 -47
  102. package/dist/models/default/django_app/dailyrate.js +0 -71
  103. package/dist/models/default/django_app/deepmodellevel1.d.ts +0 -47
  104. package/dist/models/default/django_app/deepmodellevel1.js +0 -72
  105. package/dist/models/default/django_app/deepmodellevel2.d.ts +0 -47
  106. package/dist/models/default/django_app/deepmodellevel2.js +0 -71
  107. package/dist/models/default/django_app/deepmodellevel3.d.ts +0 -44
  108. package/dist/models/default/django_app/deepmodellevel3.js +0 -69
  109. package/dist/models/default/django_app/dummymodel.d.ts +0 -47
  110. package/dist/models/default/django_app/dummymodel.js +0 -71
  111. package/dist/models/default/django_app/dummyrelatedmodel.d.ts +0 -44
  112. package/dist/models/default/django_app/dummyrelatedmodel.js +0 -69
  113. package/dist/models/default/django_app/filetest.d.ts +0 -44
  114. package/dist/models/default/django_app/filetest.js +0 -69
  115. package/dist/models/default/django_app/index.d.ts +0 -16
  116. package/dist/models/default/django_app/index.js +0 -16
  117. package/dist/models/default/django_app/modelwithcustompkrelation.d.ts +0 -47
  118. package/dist/models/default/django_app/modelwithcustompkrelation.js +0 -71
  119. package/dist/models/default/django_app/namefiltercustompkmodel.d.ts +0 -44
  120. package/dist/models/default/django_app/namefiltercustompkmodel.js +0 -69
  121. package/dist/models/default/django_app/order.d.ts +0 -47
  122. package/dist/models/default/django_app/order.js +0 -71
  123. package/dist/models/default/django_app/orderitem.d.ts +0 -47
  124. package/dist/models/default/django_app/orderitem.js +0 -72
  125. package/dist/models/default/django_app/product.d.ts +0 -47
  126. package/dist/models/default/django_app/product.js +0 -71
  127. package/dist/models/default/django_app/productcategory.d.ts +0 -44
  128. package/dist/models/default/django_app/productcategory.js +0 -69
  129. package/dist/models/default/django_app/rateplan.d.ts +0 -44
  130. package/dist/models/default/django_app/rateplan.js +0 -69
  131. package/dist/models/default/fileobject.d.ts +0 -4
  132. package/dist/models/default/fileobject.js +0 -9
  133. package/dist/models/default/index.d.ts +0 -2
  134. package/dist/models/default/index.js +0 -2
  135. package/dist/models/index.d.ts +0 -1
  136. package/dist/models/index.js +0 -5
@@ -150,333 +150,333 @@ async function selectModels(choices, message) {
150
150
  // Handlebars Templates & Helpers
151
151
  // --------------------
152
152
  // Updated JS_MODEL_TEMPLATE with getters and setters
153
- const JS_MODEL_TEMPLATE = `/**
154
- * This file was auto-generated. Do not make direct changes to the file.
155
- {{#if description}}
156
- * {{description}}
157
- {{/if}}
158
- */
159
-
160
- import { Model, Manager, QuerySet, getModelClass } from '{{modulePath}}';
161
- import { wrapReactiveModel } from '{{modulePath}}';
162
- import schemaData from './{{toLowerCase className}}.schema.json';
163
-
164
- /**
165
- * Model-specific QuerySet implementation
166
- */
167
- export class {{className}}QuerySet extends QuerySet {
168
- // QuerySet implementation with model-specific typing
169
- }
170
-
171
- /**
172
- * Model-specific Manager implementation
173
- */
174
- export class {{className}}Manager extends Manager {
175
- constructor(ModelClass) {
176
- super(ModelClass, {{className}}QuerySet);
177
- }
178
-
179
- newQuerySet() {
180
- return new {{className}}QuerySet(this.ModelClass);
181
- }
182
- }
183
-
184
- /**
185
- * Implementation of the {{className}} model
186
- */
187
- export class {{className}} extends Model {
188
- // Bind this model to its backend
189
- static configKey = '{{configKey}}';
190
- static modelName = '{{modelName}}';
191
- static primaryKeyField = '{{primaryKeyField}}';
192
- static objects = new {{className}}Manager({{className}});
193
- static fields = [{{#each properties}}'{{name}}'{{#unless @last}}, {{/unless}}{{/each}}];
194
- static schema = schemaData;
195
- static relationshipFields = new Map([
196
- {{#each relationshipFields}}
197
- ['{{field}}', { 'ModelClass': () => getModelClass('{{modelName}}', '{{../configKey}}'), 'relationshipType': '{{relationshipType}}' }]{{#unless @last}},{{/unless}}
198
- {{/each}}
199
- ]);
200
-
201
- constructor(data) {
202
- {{className}}.validateFields(data);
203
- super(data);
204
-
205
- // Define getters and setters for all fields
206
- this._defineProperties();
207
-
208
- return wrapReactiveModel(this);
209
- }
210
-
211
- /**
212
- * Define property getters and setters for all model fields
213
- * @private
214
- */
215
- _defineProperties() {
216
- // For each field, define a property that gets/sets from internal storage
217
- {{className}}.fields.forEach(field => {
218
- Object.defineProperty(this, field, {
219
- get: function() {
220
- return this.getField(field);
221
- },
222
- set: function(value) {
223
- this.setField(field, value);
224
- },
225
- enumerable: true, // Make sure fields are enumerable for serialization
226
- configurable: true
227
- });
228
- });
229
-
230
- // Add a special read-only getter for the repr field
231
- Object.defineProperty(this, 'repr', {
232
- get: function() {
233
- return this.getField('repr');
234
- },
235
- enumerable: true, // Make sure repr is enumerable
236
- configurable: true
237
- });
238
- }
239
- }
153
+ const JS_MODEL_TEMPLATE = `/**
154
+ * This file was auto-generated. Do not make direct changes to the file.
155
+ {{#if description}}
156
+ * {{description}}
157
+ {{/if}}
158
+ */
159
+
160
+ import { Model, Manager, QuerySet, getModelClass } from '{{modulePath}}';
161
+ import { wrapReactiveModel } from '{{modulePath}}';
162
+ import schemaData from './{{toLowerCase className}}.schema.json';
163
+
164
+ /**
165
+ * Model-specific QuerySet implementation
166
+ */
167
+ export class {{className}}QuerySet extends QuerySet {
168
+ // QuerySet implementation with model-specific typing
169
+ }
170
+
171
+ /**
172
+ * Model-specific Manager implementation
173
+ */
174
+ export class {{className}}Manager extends Manager {
175
+ constructor(ModelClass) {
176
+ super(ModelClass, {{className}}QuerySet);
177
+ }
178
+
179
+ newQuerySet() {
180
+ return new {{className}}QuerySet(this.ModelClass);
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Implementation of the {{className}} model
186
+ */
187
+ export class {{className}} extends Model {
188
+ // Bind this model to its backend
189
+ static configKey = '{{configKey}}';
190
+ static modelName = '{{modelName}}';
191
+ static primaryKeyField = '{{primaryKeyField}}';
192
+ static objects = new {{className}}Manager({{className}});
193
+ static fields = [{{#each properties}}'{{name}}'{{#unless @last}}, {{/unless}}{{/each}}];
194
+ static schema = schemaData;
195
+ static relationshipFields = new Map([
196
+ {{#each relationshipFields}}
197
+ ['{{field}}', { 'ModelClass': () => getModelClass('{{modelName}}', '{{../configKey}}'), 'relationshipType': '{{relationshipType}}' }]{{#unless @last}},{{/unless}}
198
+ {{/each}}
199
+ ]);
200
+
201
+ constructor(data) {
202
+ {{className}}.validateFields(data);
203
+ super(data);
204
+
205
+ // Define getters and setters for all fields
206
+ this._defineProperties();
207
+
208
+ return wrapReactiveModel(this);
209
+ }
210
+
211
+ /**
212
+ * Define property getters and setters for all model fields
213
+ * @private
214
+ */
215
+ _defineProperties() {
216
+ // For each field, define a property that gets/sets from internal storage
217
+ {{className}}.fields.forEach(field => {
218
+ Object.defineProperty(this, field, {
219
+ get: function() {
220
+ return this.getField(field);
221
+ },
222
+ set: function(value) {
223
+ this.setField(field, value);
224
+ },
225
+ enumerable: true, // Make sure fields are enumerable for serialization
226
+ configurable: true
227
+ });
228
+ });
229
+
230
+ // Add a special read-only getter for the repr field
231
+ Object.defineProperty(this, 'repr', {
232
+ get: function() {
233
+ return this.getField('repr');
234
+ },
235
+ enumerable: true, // Make sure repr is enumerable
236
+ configurable: true
237
+ });
238
+ }
239
+ }
240
240
  `;
241
241
  // Updated TS_DECLARATION_TEMPLATE with improved relationship handling
242
- const TS_DECLARATION_TEMPLATE = `/**
243
- * This file was auto-generated. Do not make direct changes to the file.
244
- {{#if description}}
245
- * {{description}}
246
- {{/if}}
247
- */
248
-
249
- import { Model, Manager } from '{{modulePath}}';
250
- import { StringOperators, NumberOperators, BooleanOperators, DateOperators } from '{{modulePath}}';
251
- import { QuerySet, LiveQuerySet, LiveQuerySetOptions, MetricResult, ResultTuple, SerializerOptions, NestedPaths } from '{{modulePath}}';
252
-
253
- // Re-export the real Manager for runtime use
254
- import { Manager as RuntimeManager } from '{{modulePath}}';
255
- {{#if tsImports}}
256
- {{#each tsImports}}
257
- {{{this}}}
258
- {{/each}}
259
- {{/if}}
260
-
261
- /**
262
- * Base fields interface - defines the shape of a model instance
263
- * This is the single source of truth for the model's data structure
264
- */
265
- export interface {{interfaceName}} {
266
- {{#each properties}}
267
- {{name}}{{#unless required}}?{{/unless}}: {{{type}}};
268
- {{/each}}
269
- // Read-only representation field
270
- readonly repr: {
271
- str: string;
272
- img: string | null;
273
- };
274
- }
275
-
276
- /**
277
- * Relationship field structure
278
- */
279
- export interface RelationshipField {
280
- ModelClass: any;
281
- relationshipType: string;
282
- }
283
-
284
- /**
285
- * Relationship fields map type
286
- */
287
- export type RelationshipFieldsMap = Map<string, RelationshipField>;
288
-
289
- /**
290
- * Type for creating new instances
291
- * Similar to base fields but makes ID fields optional
292
- */
293
- export type {{className}}CreateData = {
294
- {{#each properties}}
295
- {{name}}{{#unless isPrimaryKey}}{{#unless required}}?{{/unless}}{{else}}?{{/unless}}: {{{type}}};
296
- {{/each}}
297
- };
298
-
299
- /**
300
- * Type for updating instances
301
- * All fields are optional since updates can be partial
302
- */
303
- export type {{className}}UpdateData = Partial<{{interfaceName}}>;
304
-
305
- /**
306
- * Type for filtering with field lookups
307
- * Supports advanced filtering with operators like __gte, __contains, etc.
308
- */
309
- export interface {{className}}FilterData {
310
- {{#each properties}}
311
- {{#if isRelationship}}
312
- {{#if isArrayRelationship}}
313
- // Many-to-many relationship field
314
- {{name}}?: number; // Exact match by ID
315
- {{name}}__in?: number[]; // Match any of these IDs
316
- {{name}}__isnull?: boolean; // Check if relation exists
317
- {{else}}
318
- // Foreign key relationship field
319
- {{name}}?: number; // Exact match by ID
320
- {{name}}__isnull?: boolean; // Check if relation exists
321
- {{/if}}
322
- {{else}}
323
- {{#if isString}}
324
- {{name}}?: string | StringOperators;
325
- {{name}}__contains?: string;
326
- {{name}}__icontains?: string;
327
- {{name}}__startswith?: string;
328
- {{name}}__istartswith?: string;
329
- {{name}}__endswith?: string;
330
- {{name}}__iendswith?: string;
331
- {{name}}__exact?: string;
332
- {{name}}__iexact?: string;
333
- {{name}}__in?: string[];
334
- {{name}}__isnull?: boolean;
335
- {{/if}}
336
- {{#if isNumber}}
337
- {{name}}?: number | NumberOperators;
338
- {{name}}__gt?: number;
339
- {{name}}__gte?: number;
340
- {{name}}__lt?: number;
341
- {{name}}__lte?: number;
342
- {{name}}__exact?: number;
343
- {{name}}__in?: number[];
344
- {{name}}__isnull?: boolean;
345
- {{/if}}
346
- {{#if isBoolean}}
347
- {{name}}?: boolean | BooleanOperators;
348
- {{name}}__exact?: boolean;
349
- {{name}}__isnull?: boolean;
350
- {{/if}}
351
- {{#if isDate}}
352
- {{name}}?: Date | DateOperators;
353
- {{name}}__gt?: Date;
354
- {{name}}__gte?: Date;
355
- {{name}}__lt?: Date;
356
- {{name}}__lte?: Date;
357
- {{name}}__exact?: Date;
358
- {{name}}__in?: Date[];
359
- {{name}}__isnull?: boolean;
360
- {{/if}}
361
- {{/if}}
362
- {{/each}}
363
- // Support for nested filtering on related fields
364
- [key: string]: any;
365
-
366
- // Support for Q objects
367
- Q?: Array<any>;
368
- }
369
-
370
- /**
371
- * Model-specific QuerySet with strictly typed methods
372
- */
373
- export declare class {{className}}QuerySet extends QuerySet<any> {
374
- // Chain methods
375
- filter(conditions: {{className}}FilterData): {{className}}QuerySet;
376
- exclude(conditions: {{className}}FilterData): {{className}}QuerySet;
377
- orderBy(...fields: Array<keyof {{interfaceName}} | string>): {{className}}QuerySet;
378
- search(searchQuery: string, searchFields?: Array<string>): {{className}}QuerySet;
379
-
380
- // Terminal methods
381
- get(filters?: {{className}}FilterData, serializerOptions?: SerializerOptions): Promise<{{className}}>;
382
- first(serializerOptions?: SerializerOptions): Promise<{{className}} | null>;
383
- last(serializerOptions?: SerializerOptions): Promise<{{className}} | null>;
384
- all(): {{className}}QuerySet;
385
- count(field?: string): Promise<number>;
386
- update(updates: {{className}}UpdateData): Promise<[number, Record<string, number>]>;
387
- delete(): Promise<[number, Record<string, number>]>;
388
- exists(): Promise<boolean>;
389
- fetch(serializerOptions?: SerializerOptions): Promise<{{className}}[]>;
390
- }
391
-
392
- /**
393
- * Model-specific Manager with strictly typed methods
394
- */
395
- export declare class {{className}}Manager extends Manager {
396
- newQuerySet(): {{className}}QuerySet;
397
- filter(conditions: {{className}}FilterData): {{className}}QuerySet;
398
- exclude(conditions: {{className}}FilterData): {{className}}QuerySet;
399
- all(): {{className}}QuerySet;
400
- get(filters?: {{className}}FilterData, serializerOptions?: SerializerOptions): Promise<{{className}}>;
401
- create(data: {{className}}CreateData): Promise<{{className}}>;
402
- delete(): Promise<[number, Record<string, number>]>;
403
- }
404
-
405
- /**
406
- * Model-specific LiveQuerySet with strictly typed methods
407
- */
408
- export declare class {{className}}LiveQuerySet extends LiveQuerySet {
409
- // Data access
410
- get data(): {{className}}[];
411
-
412
- // Chain methods
413
- filter(conditions: {{className}}FilterData): {{className}}LiveQuerySet;
414
-
415
- // Terminal methods
416
- fetch(serializerOptions?: SerializerOptions): Promise<{{className}}[]>;
417
- get(filters?: {{className}}FilterData, serializerOptions?: SerializerOptions): Promise<{{className}}>;
418
- create(item: {{className}}CreateData): Promise<{{className}}>;
419
- update(updates: {{className}}UpdateData): Promise<{{className}}[]>;
420
- delete(): Promise<void>;
421
- count(field?: string): Promise<MetricResult<number>>;
422
- sum(field: string): Promise<MetricResult<number>>;
423
- avg(field: string): Promise<MetricResult<number>>;
424
- min(field: string): Promise<MetricResult<any>>;
425
- max(field: string): Promise<MetricResult<any>>;
426
- }
427
-
428
- /**
429
- * Enhanced RuntimeManager to provide TypeScript typings
430
- * This creates a concrete class that both extends RuntimeManager and matches type expectations
431
- */
432
- export class {{className}}Manager extends RuntimeManager {
433
- filter(conditions: {{className}}FilterData): ReturnType<RuntimeManager['filter']> {
434
- return super.filter(conditions as any);
435
- }
436
-
437
- get(filters?: {{className}}FilterData, serializerOptions?: SerializerOptions): Promise<{{className}}> {
438
- return super.get(filters as any, serializerOptions);
439
- }
440
-
441
- all() {
442
- return super.all();
443
- }
444
-
445
- create(data: {{className}}CreateData): Promise<{{className}}> {
446
- return super.create(data);
447
- }
448
-
449
- update(data: {{className}}UpdateData): Promise<any> {
450
- return super.update(data);
451
- }
452
- }
453
-
454
- // Class declarations
455
- export declare class {{className}} extends Model implements {{interfaceName}} {
456
- {{#each properties}}
457
- {{name}}{{#unless required}}?:{{else}}:{{/unless}} {{{type}}};
458
- {{/each}}
459
- readonly repr: {
460
- str: string;
461
- img: string | null;
462
- };
463
-
464
- static configKey: string;
465
- static modelName: string;
466
- static primaryKeyField: string;
467
- static relationshipFields: RelationshipFieldsMap;
468
-
469
- // Use model-specific manager class instead of generic manager
470
- static objects: {{className}}Manager;
471
-
472
- constructor(data: Partial<{{interfaceName}}>);
473
- serialize(): Partial<{{interfaceName}}>;
474
- }
475
-
476
- /**
477
- * Runtime initialization
478
- */
479
- {{className}}.objects = new {{className}}Manager({{className}});
242
+ const TS_DECLARATION_TEMPLATE = `/**
243
+ * This file was auto-generated. Do not make direct changes to the file.
244
+ {{#if description}}
245
+ * {{description}}
246
+ {{/if}}
247
+ */
248
+
249
+ import { Model, Manager } from '{{modulePath}}';
250
+ import { StringOperators, NumberOperators, BooleanOperators, DateOperators } from '{{modulePath}}';
251
+ import { QuerySet, LiveQuerySet, LiveQuerySetOptions, MetricResult, ResultTuple, SerializerOptions, NestedPaths } from '{{modulePath}}';
252
+
253
+ // Re-export the real Manager for runtime use
254
+ import { Manager as RuntimeManager } from '{{modulePath}}';
255
+ {{#if tsImports}}
256
+ {{#each tsImports}}
257
+ {{{this}}}
258
+ {{/each}}
259
+ {{/if}}
260
+
261
+ /**
262
+ * Base fields interface - defines the shape of a model instance
263
+ * This is the single source of truth for the model's data structure
264
+ */
265
+ export interface {{interfaceName}} {
266
+ {{#each properties}}
267
+ {{name}}{{#unless required}}?{{/unless}}: {{{type}}};
268
+ {{/each}}
269
+ // Read-only representation field
270
+ readonly repr: {
271
+ str: string;
272
+ img: string | null;
273
+ };
274
+ }
275
+
276
+ /**
277
+ * Relationship field structure
278
+ */
279
+ export interface RelationshipField {
280
+ ModelClass: any;
281
+ relationshipType: string;
282
+ }
283
+
284
+ /**
285
+ * Relationship fields map type
286
+ */
287
+ export type RelationshipFieldsMap = Map<string, RelationshipField>;
288
+
289
+ /**
290
+ * Type for creating new instances
291
+ * Similar to base fields but makes ID fields optional
292
+ */
293
+ export type {{className}}CreateData = {
294
+ {{#each properties}}
295
+ {{name}}{{#unless isPrimaryKey}}{{#unless required}}?{{/unless}}{{else}}?{{/unless}}: {{{type}}};
296
+ {{/each}}
297
+ };
298
+
299
+ /**
300
+ * Type for updating instances
301
+ * All fields are optional since updates can be partial
302
+ */
303
+ export type {{className}}UpdateData = Partial<{{interfaceName}}>;
304
+
305
+ /**
306
+ * Type for filtering with field lookups
307
+ * Supports advanced filtering with operators like __gte, __contains, etc.
308
+ */
309
+ export interface {{className}}FilterData {
310
+ {{#each properties}}
311
+ {{#if isRelationship}}
312
+ {{#if isArrayRelationship}}
313
+ // Many-to-many relationship field
314
+ {{name}}?: number; // Exact match by ID
315
+ {{name}}__in?: number[]; // Match any of these IDs
316
+ {{name}}__isnull?: boolean; // Check if relation exists
317
+ {{else}}
318
+ // Foreign key relationship field
319
+ {{name}}?: number; // Exact match by ID
320
+ {{name}}__isnull?: boolean; // Check if relation exists
321
+ {{/if}}
322
+ {{else}}
323
+ {{#if isString}}
324
+ {{name}}?: string | StringOperators;
325
+ {{name}}__contains?: string;
326
+ {{name}}__icontains?: string;
327
+ {{name}}__startswith?: string;
328
+ {{name}}__istartswith?: string;
329
+ {{name}}__endswith?: string;
330
+ {{name}}__iendswith?: string;
331
+ {{name}}__exact?: string;
332
+ {{name}}__iexact?: string;
333
+ {{name}}__in?: string[];
334
+ {{name}}__isnull?: boolean;
335
+ {{/if}}
336
+ {{#if isNumber}}
337
+ {{name}}?: number | NumberOperators;
338
+ {{name}}__gt?: number;
339
+ {{name}}__gte?: number;
340
+ {{name}}__lt?: number;
341
+ {{name}}__lte?: number;
342
+ {{name}}__exact?: number;
343
+ {{name}}__in?: number[];
344
+ {{name}}__isnull?: boolean;
345
+ {{/if}}
346
+ {{#if isBoolean}}
347
+ {{name}}?: boolean | BooleanOperators;
348
+ {{name}}__exact?: boolean;
349
+ {{name}}__isnull?: boolean;
350
+ {{/if}}
351
+ {{#if isDate}}
352
+ {{name}}?: Date | DateOperators;
353
+ {{name}}__gt?: Date;
354
+ {{name}}__gte?: Date;
355
+ {{name}}__lt?: Date;
356
+ {{name}}__lte?: Date;
357
+ {{name}}__exact?: Date;
358
+ {{name}}__in?: Date[];
359
+ {{name}}__isnull?: boolean;
360
+ {{/if}}
361
+ {{/if}}
362
+ {{/each}}
363
+ // Support for nested filtering on related fields
364
+ [key: string]: any;
365
+
366
+ // Support for Q objects
367
+ Q?: Array<any>;
368
+ }
369
+
370
+ /**
371
+ * Model-specific QuerySet with strictly typed methods
372
+ */
373
+ export declare class {{className}}QuerySet extends QuerySet<any> {
374
+ // Chain methods
375
+ filter(conditions: {{className}}FilterData): {{className}}QuerySet;
376
+ exclude(conditions: {{className}}FilterData): {{className}}QuerySet;
377
+ orderBy(...fields: Array<keyof {{interfaceName}} | string>): {{className}}QuerySet;
378
+ search(searchQuery: string, searchFields?: Array<string>): {{className}}QuerySet;
379
+
380
+ // Terminal methods
381
+ get(filters?: {{className}}FilterData, serializerOptions?: SerializerOptions): Promise<{{className}}>;
382
+ first(serializerOptions?: SerializerOptions): Promise<{{className}} | null>;
383
+ last(serializerOptions?: SerializerOptions): Promise<{{className}} | null>;
384
+ all(): {{className}}QuerySet;
385
+ count(field?: string): Promise<number>;
386
+ update(updates: {{className}}UpdateData): Promise<[number, Record<string, number>]>;
387
+ delete(): Promise<[number, Record<string, number>]>;
388
+ exists(): Promise<boolean>;
389
+ fetch(serializerOptions?: SerializerOptions): Promise<{{className}}[]>;
390
+ }
391
+
392
+ /**
393
+ * Model-specific Manager with strictly typed methods
394
+ */
395
+ export declare class {{className}}Manager extends Manager {
396
+ newQuerySet(): {{className}}QuerySet;
397
+ filter(conditions: {{className}}FilterData): {{className}}QuerySet;
398
+ exclude(conditions: {{className}}FilterData): {{className}}QuerySet;
399
+ all(): {{className}}QuerySet;
400
+ get(filters?: {{className}}FilterData, serializerOptions?: SerializerOptions): Promise<{{className}}>;
401
+ create(data: {{className}}CreateData): Promise<{{className}}>;
402
+ delete(): Promise<[number, Record<string, number>]>;
403
+ }
404
+
405
+ /**
406
+ * Model-specific LiveQuerySet with strictly typed methods
407
+ */
408
+ export declare class {{className}}LiveQuerySet extends LiveQuerySet {
409
+ // Data access
410
+ get data(): {{className}}[];
411
+
412
+ // Chain methods
413
+ filter(conditions: {{className}}FilterData): {{className}}LiveQuerySet;
414
+
415
+ // Terminal methods
416
+ fetch(serializerOptions?: SerializerOptions): Promise<{{className}}[]>;
417
+ get(filters?: {{className}}FilterData, serializerOptions?: SerializerOptions): Promise<{{className}}>;
418
+ create(item: {{className}}CreateData): Promise<{{className}}>;
419
+ update(updates: {{className}}UpdateData): Promise<{{className}}[]>;
420
+ delete(): Promise<void>;
421
+ count(field?: string): Promise<MetricResult<number>>;
422
+ sum(field: string): Promise<MetricResult<number>>;
423
+ avg(field: string): Promise<MetricResult<number>>;
424
+ min(field: string): Promise<MetricResult<any>>;
425
+ max(field: string): Promise<MetricResult<any>>;
426
+ }
427
+
428
+ /**
429
+ * Enhanced RuntimeManager to provide TypeScript typings
430
+ * This creates a concrete class that both extends RuntimeManager and matches type expectations
431
+ */
432
+ export class {{className}}Manager extends RuntimeManager {
433
+ filter(conditions: {{className}}FilterData): ReturnType<RuntimeManager['filter']> {
434
+ return super.filter(conditions as any);
435
+ }
436
+
437
+ get(filters?: {{className}}FilterData, serializerOptions?: SerializerOptions): Promise<{{className}}> {
438
+ return super.get(filters as any, serializerOptions);
439
+ }
440
+
441
+ all() {
442
+ return super.all();
443
+ }
444
+
445
+ create(data: {{className}}CreateData): Promise<{{className}}> {
446
+ return super.create(data);
447
+ }
448
+
449
+ update(data: {{className}}UpdateData): Promise<any> {
450
+ return super.update(data);
451
+ }
452
+ }
453
+
454
+ // Class declarations
455
+ export declare class {{className}} extends Model implements {{interfaceName}} {
456
+ {{#each properties}}
457
+ {{name}}{{#unless required}}?:{{else}}:{{/unless}} {{{type}}};
458
+ {{/each}}
459
+ readonly repr: {
460
+ str: string;
461
+ img: string | null;
462
+ };
463
+
464
+ static configKey: string;
465
+ static modelName: string;
466
+ static primaryKeyField: string;
467
+ static relationshipFields: RelationshipFieldsMap;
468
+
469
+ // Use model-specific manager class instead of generic manager
470
+ static objects: {{className}}Manager;
471
+
472
+ constructor(data: Partial<{{interfaceName}}>);
473
+ serialize(): Partial<{{interfaceName}}>;
474
+ }
475
+
476
+ /**
477
+ * Runtime initialization
478
+ */
479
+ {{className}}.objects = new {{className}}Manager({{className}});
480
480
  `;
481
481
  // --------------------
482
482
  // Handlebars Helpers
@@ -818,24 +818,24 @@ async function generateModelRegistry(generatedFiles, backendConfigs) {
818
818
  registryByBackend[backendKey].models[modelName] = importAlias; // Store mapping: 'django_app.dummymodel': 'Default__django_app__DummyModel'
819
819
  }
820
820
  // --- Generate registry content ---
821
- let registryContent = `/**
822
- * This file was auto-generated. Do not make direct changes to the file.
823
- * It provides a registry of all models organized by config key and model name.
824
- * Uses import aliases incorporating model paths to ensure uniqueness.
825
- */
826
-
827
- // --- Imports ---
821
+ let registryContent = `/**
822
+ * This file was auto-generated. Do not make direct changes to the file.
823
+ * It provides a registry of all models organized by config key and model name.
824
+ * Uses import aliases incorporating model paths to ensure uniqueness.
825
+ */
826
+
827
+ // --- Imports ---
828
828
  `;
829
829
  // Add all unique import statements collected
830
830
  registryContent += Array.from(allUniqueImports).sort().join("\n");
831
831
  registryContent += "\n\n";
832
832
  // --- Create the registry object ---
833
- registryContent += `/**
834
- * Model registry mapped by configKey and modelName.
835
- * Values are the aliased imported classes.
836
- * @type {Object.<string, Object.<string, Function>>}
837
- */
838
- export const MODEL_REGISTRY = {
833
+ registryContent += `/**
834
+ * Model registry mapped by configKey and modelName.
835
+ * Values are the aliased imported classes.
836
+ * @type {Object.<string, Object.<string, Function>>}
837
+ */
838
+ export const MODEL_REGISTRY = {
839
839
  `;
840
840
  // Add entries for each backend
841
841
  const backendEntries = Object.entries(registryByBackend);
@@ -856,25 +856,25 @@ export const MODEL_REGISTRY = {
856
856
  }
857
857
  registryContent += "\n";
858
858
  });
859
- registryContent += `};
860
-
861
- /**
862
- * Get a model class by name.
863
- * This remains synchronous.
864
- *
865
- * @param {string} modelName - The model name (e.g., 'django_app.dummymodel')
866
- * @param {string} configKey - The config key (backend name, e.g., 'default')
867
- * @returns {Function|null} - The model class (via its alias) or null if not found.
868
- */
869
- export function getModelClass(modelName, configKey) {
870
- if (MODEL_REGISTRY[configKey] && MODEL_REGISTRY[configKey][modelName]) {
871
- // Returns the specific aliased class for that backend/model combination
872
- return MODEL_REGISTRY[configKey][modelName];
873
- }
874
-
875
- console.warn(\`Model class not found for '\${modelName}' in config '\${configKey}'\`);
876
- return null;
877
- }
859
+ registryContent += `};
860
+
861
+ /**
862
+ * Get a model class by name.
863
+ * This remains synchronous.
864
+ *
865
+ * @param {string} modelName - The model name (e.g., 'django_app.dummymodel')
866
+ * @param {string} configKey - The config key (backend name, e.g., 'default')
867
+ * @returns {Function|null} - The model class (via its alias) or null if not found.
868
+ */
869
+ export function getModelClass(modelName, configKey) {
870
+ if (MODEL_REGISTRY[configKey] && MODEL_REGISTRY[configKey][modelName]) {
871
+ // Returns the specific aliased class for that backend/model combination
872
+ return MODEL_REGISTRY[configKey][modelName];
873
+ }
874
+
875
+ console.warn(\`Model class not found for '\${modelName}' in config '\${configKey}'\`);
876
+ return null;
877
+ }
878
878
  `;
879
879
  // --- Write the file ---
880
880
  const rootDir = process.cwd();
@@ -904,8 +904,8 @@ async function generateAppLevelIndexFiles(generatedFiles, backendConfigs) {
904
904
  acc[backend][app].push(file);
905
905
  return acc;
906
906
  }, {});
907
- const indexTemplate = Handlebars.compile(`{{#each files}}
908
- export * from '{{this.relativePath}}';
907
+ const indexTemplate = Handlebars.compile(`{{#each files}}
908
+ export * from '{{this.relativePath}}';
909
909
  {{/each}}`);
910
910
  // Generate app-level index files for each backend and app
911
911
  for (const [backendName, appGroups] of Object.entries(filesByBackendAndApp)) {
@@ -936,12 +936,12 @@ export * from '{{this.relativePath}}';
936
936
  await fs.writeFile(path.join(appDir, "index.js"), indexContent.trim());
937
937
  await fs.writeFile(path.join(appDir, "index.d.ts"), indexContent.trim());
938
938
  // Add an export for this app's index to the backend root index
939
- rootExports.push(`export * from './${app.toLowerCase()}/index';`);
939
+ rootExports.push(`export * from './${app.toLowerCase()}/index.js';`);
940
940
  }
941
941
  }
942
942
  // Write the backend root index file (add FileObject export)
943
943
  const backendIndexContent = [
944
- "export * from './fileobject';", // Add this line
944
+ "export * from './fileobject.js';", // Add this line
945
945
  ...rootExports,
946
946
  ].join("\n");
947
947
  // Include backend key in the path for index files
@@ -951,18 +951,18 @@ export * from '{{this.relativePath}}';
951
951
  }
952
952
  }
953
953
  // FileObject template
954
- const FILEOBJECT_TEMPLATE = `/**
955
- * This file was auto-generated. Do not make direct changes to the file.
956
- * Backend-specific FileObject class for {{backendName}}
957
- */
958
-
959
- import { FileObject as BaseFileObject } from '{{modulePath}}';
960
-
961
- export class {{backendName}}FileObject extends BaseFileObject {
962
- static configKey = '{{backendName}}';
963
- }
964
-
965
- export const FileObject = {{backendName}}FileObject;
954
+ const FILEOBJECT_TEMPLATE = `/**
955
+ * This file was auto-generated. Do not make direct changes to the file.
956
+ * Backend-specific FileObject class for {{backendName}}
957
+ */
958
+
959
+ import { FileObject as BaseFileObject } from '{{modulePath}}';
960
+
961
+ export class {{backendName}}FileObject extends BaseFileObject {
962
+ static configKey = '{{backendName}}';
963
+ }
964
+
965
+ export const FileObject = {{backendName}}FileObject;
966
966
  `;
967
967
  const fileObjectTemplate = Handlebars.compile(FILEOBJECT_TEMPLATE);
968
968
  /**
@@ -983,18 +983,18 @@ async function generateFileObjectForBackend(backend) {
983
983
  const fileObjectPath = path.join(backendDir, "fileobject.js");
984
984
  await fs.writeFile(fileObjectPath, fileObjectContent);
985
985
  // Also generate TypeScript declaration
986
- const dtsContent = `/**
987
- * This file was auto-generated. Do not make direct changes to the file.
988
- * Backend-specific FileObject class for ${backend.NAME}
989
- */
990
-
991
- import { FileObject as BaseFileObject } from '${modulePath}';
992
-
993
- export declare class ${backend.NAME}FileObject extends BaseFileObject {
994
- static configKey: string;
995
- }
996
-
997
- export declare const FileObject: typeof ${backend.NAME}FileObject;
986
+ const dtsContent = `/**
987
+ * This file was auto-generated. Do not make direct changes to the file.
988
+ * Backend-specific FileObject class for ${backend.NAME}
989
+ */
990
+
991
+ import { FileObject as BaseFileObject } from '${modulePath}';
992
+
993
+ export declare class ${backend.NAME}FileObject extends BaseFileObject {
994
+ static configKey: string;
995
+ }
996
+
997
+ export declare const FileObject: typeof ${backend.NAME}FileObject;
998
998
  `;
999
999
  const dtsPath = path.join(backendDir, "fileobject.d.ts");
1000
1000
  await fs.writeFile(dtsPath, dtsContent);
@@ -1013,12 +1013,12 @@ async function generateDefaultBackendIndex(backendConfigs) {
1013
1013
  const defaultBackend = backendConfigs['default'];
1014
1014
  const typesDir = defaultBackend.GENERATED_TYPES_DIR;
1015
1015
  // Create top-level index files that re-export from default
1016
- const indexContent = `/**
1017
- * This file was auto-generated. Do not make direct changes to the file.
1018
- * Re-exports from the 'default' backend for backwards compatibility.
1019
- */
1020
-
1021
- export * from './default/index';
1016
+ const indexContent = `/**
1017
+ * This file was auto-generated. Do not make direct changes to the file.
1018
+ * Re-exports from the 'default' backend for backwards compatibility.
1019
+ */
1020
+
1021
+ export * from './default/index.js';
1022
1022
  `;
1023
1023
  const jsIndexPath = path.join(typesDir, 'index.js');
1024
1024
  const dtsIndexPath = path.join(typesDir, 'index.d.ts');