@gzl10/nexus-sdk 0.3.0 → 0.4.1

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.
package/dist/index.d.ts CHANGED
@@ -11,11 +11,29 @@ import { Logger } from 'pino';
11
11
  * que pueden ser escritos a archivos o usados en runtime.
12
12
  */
13
13
 
14
+ /** Directorio estándar para código generado */
15
+ declare const GENERATED_DIR = "__generated__";
14
16
  /**
15
- * Entidades que persisten en BD local
16
- * Excluye: action, external, virtual, computed
17
+ * Entidades que persisten en BD local con tabla propia
18
+ * Excluye: action, external, virtual, computed, single (usa tabla compartida)
17
19
  */
18
- type PersistentEntityDefinition = CollectionEntityDefinition | SingleEntityDefinition | ReferenceEntityDefinition | EventEntityDefinition | ConfigEntityDefinition | TempEntityDefinition | ViewEntityDefinition;
20
+ type PersistentEntityDefinition = CollectionEntityDefinition | ReferenceEntityDefinition | EventEntityDefinition | ConfigEntityDefinition | TempEntityDefinition | ViewEntityDefinition;
21
+ /**
22
+ * Entidades sin persistencia local (read-only o sin BD)
23
+ */
24
+ type NonPersistentEntityDefinition = ActionEntityDefinition | ExternalEntityDefinition | VirtualEntityDefinition | ComputedEntityDefinition;
25
+ /**
26
+ * Type guard para verificar si una entidad persiste en BD local con tabla propia
27
+ */
28
+ declare function isPersistentEntity(entity: EntityDefinition): entity is PersistentEntityDefinition;
29
+ /**
30
+ * Type guard para verificar si es un singleton (usa tabla compartida sys_settings)
31
+ */
32
+ declare function isSingletonEntity(entity: EntityDefinition): entity is SingleEntityDefinition;
33
+ /**
34
+ * Type guard para verificar si una entidad tiene tabla propia (para migraciones)
35
+ */
36
+ declare function hasTable(entity: EntityDefinition): entity is PersistentEntityDefinition;
19
37
  /**
20
38
  * Genera código de migración Knex desde EntityDefinition
21
39
  *
@@ -51,6 +69,15 @@ declare function generateZodSchema(entity: PersistentEntityDefinition): string;
51
69
  * // }
52
70
  */
53
71
  declare function generateModel(entity: PersistentEntityDefinition): string;
72
+ /**
73
+ * Genera schema Zod para entidades read-only
74
+ * Solo genera el schema de output, no create/update
75
+ */
76
+ declare function generateReadOnlySchema(entity: ComputedEntityDefinition | ExternalEntityDefinition | VirtualEntityDefinition): string;
77
+ /**
78
+ * Genera interface TypeScript para entidades read-only
79
+ */
80
+ declare function generateReadOnlyModel(entity: ComputedEntityDefinition | ExternalEntityDefinition | VirtualEntityDefinition): string;
54
81
  /**
55
82
  * Estructura de permiso generado para insertar en BD
56
83
  */
@@ -82,6 +109,38 @@ declare function generateCaslSeed(entities: EntityDefinition[]): string;
82
109
  * Obtiene el subject CASL de una entidad
83
110
  */
84
111
  declare function getEntitySubject(entity: PersistentEntityDefinition): string;
112
+ /**
113
+ * Obtiene el nombre de una entidad en PascalCase singular
114
+ * 'cms_posts' → 'Post', 'rol_role_permissions' → 'RolePermission'
115
+ */
116
+ declare function getEntityName(entity: EntityDefinition): string;
117
+ /**
118
+ * Genera archivo completo de schemas Zod para múltiples entidades
119
+ * Consolida todas las entidades de un módulo en un solo archivo
120
+ *
121
+ * @example
122
+ * const code = generateSchemasFile([userEntity, roleEntity])
123
+ * writeFileSync('users.schemas.ts', code)
124
+ */
125
+ declare function generateSchemasFile(definitions: EntityDefinition[]): string;
126
+ /**
127
+ * Genera archivo completo de modelos TypeScript para múltiples entidades
128
+ * Consolida todas las entidades de un módulo en un solo archivo
129
+ *
130
+ * @example
131
+ * const code = generateModelsFile([userEntity, roleEntity])
132
+ * writeFileSync('users.models.ts', code)
133
+ */
134
+ declare function generateModelsFile(definitions: EntityDefinition[]): string;
135
+ /**
136
+ * Genera archivo completo de migración Knex para múltiples entidades
137
+ * Consolida todas las entidades de un módulo en un solo archivo de migración
138
+ *
139
+ * @example
140
+ * const code = generateMigrationsFile([userEntity, roleEntity])
141
+ * writeFileSync('users.migrate.ts', code)
142
+ */
143
+ declare function generateMigrationsFile(definitions: EntityDefinition[]): string;
85
144
 
86
145
  /**
87
146
  * @gzl10/nexus-sdk
@@ -370,14 +429,24 @@ interface CollectionEntityDefinition extends BaseEntityDefinition {
370
429
  indexes?: EntityIndex[];
371
430
  }
372
431
  /**
373
- * Entidad singleton - Solo Update/Read, sin lista (site_config)
432
+ * Entidad singleton - Un solo registro en tabla compartida sys_settings
433
+ * Usa key-value: key identifica el registro, value es JSON con la estructura de fields
434
+ *
435
+ * @example
436
+ * // site_config singleton
437
+ * { type: 'single', key: 'site_config', label: 'Site Config', fields: { siteName: {...}, logo: {...} } }
438
+ * // Se guarda en sys_settings como: { key: 'site_config', value: { siteName: 'Mi App', logo: '...' } }
374
439
  */
375
- interface SingleEntityDefinition extends BaseEntityDefinition {
440
+ interface SingleEntityDefinition {
376
441
  type: 'single';
377
- /** Añadir updated_at */
378
- timestamps?: boolean;
379
- /** Añadir updated_by */
380
- audit?: boolean;
442
+ /** Clave única en tabla sys_settings (ej: 'site_config', 'smtp_settings') */
443
+ key: string;
444
+ /** Nombre para mostrar en UI */
445
+ label: string;
446
+ /** Definición de campos (estructura del JSON value) */
447
+ fields: Record<string, FieldDefinition>;
448
+ /** Autorización CASL */
449
+ casl?: EntityCaslConfig;
381
450
  }
382
451
  /**
383
452
  * Entidad de referencia - Catálogos con CRUD admin (countries, currencies)
@@ -576,21 +645,6 @@ interface ModuleAbilities {
576
645
  * Usa BaseUser y AbilityLike para tipado básico sin depender del backend
577
646
  */
578
647
  type PluginAuthRequest = AuthRequest<BaseUser, AbilityLike>;
579
- /**
580
- * Resolver de usuarios para plugins
581
- * Permite acceder a usuarios sin conocer la implementación interna
582
- */
583
- interface UsersResolver {
584
- findById: (id: string) => Promise<BaseUser | null>;
585
- findByIds: (ids: string[]) => Promise<BaseUser[]>;
586
- }
587
- /**
588
- * Servicios core inyectados por el backend
589
- * Los plugins acceden a estos servicios via ctx.services
590
- */
591
- interface CoreServices {
592
- users?: UsersResolver;
593
- }
594
648
  /**
595
649
  * Helpers para migraciones de base de datos
596
650
  */
@@ -655,8 +709,8 @@ interface ModuleContext {
655
709
  data?: Record<string, unknown>;
656
710
  }) => Promise<unknown>;
657
711
  };
658
- /** Servicios de módulos core (users, etc.) */
659
- services: CoreServices & Record<string, unknown>;
712
+ /** Servicios de módulos (inyectados por backend) */
713
+ services: Record<string, unknown>;
660
714
  }
661
715
  /**
662
716
  * Manifest de un módulo Nexus
@@ -664,8 +718,6 @@ interface ModuleContext {
664
718
  interface ModuleManifest {
665
719
  /** Identificador único del módulo (ej: 'users', 'posts') */
666
720
  name: string;
667
- /** Código único del módulo (ej: 'USR', 'PST'). Opcional si pertenece a un plugin */
668
- code?: string;
669
721
  /** Nombre para mostrar en UI. Opcional si pertenece a un plugin */
670
722
  label?: string;
671
723
  /** Icono del módulo (Iconify MDI: 'mdi:account-group') */
@@ -678,7 +730,7 @@ interface ModuleManifest {
678
730
  dependencies?: string[];
679
731
  /** Requisitos para activar el módulo */
680
732
  required?: ModuleRequirements;
681
- /** Función de migración de base de datos */
733
+ /** Función de migración de base de datos. Normalmente se genera desde definitions (EntityDefinition) */
682
734
  migrate?: (ctx: ModuleContext) => Promise<void>;
683
735
  /** Función de seed de datos iniciales */
684
736
  seed?: (ctx: ModuleContext) => Promise<void>;
@@ -723,4 +775,4 @@ interface PluginManifest {
723
775
  modules: ModuleManifest[];
724
776
  }
725
777
 
726
- export { type AbilityLike, type ActionEntityDefinition, type AuthRequest, type BaseUser, type CaslAction, type CollectionEntityDefinition, type ComputedEntityDefinition, type ConfigEntityDefinition, type CoreServices, type DbType, type EntityCaslConfig, type EntityDefinition, type EntityIndex, type EventEntityDefinition, type ExternalEntityDefinition, type FieldCaslAccess, type FieldDbConfig, type FieldDefinition, type FieldMeta, type FieldOptions, type FieldRelation, type FieldValidation, type FieldValidationConfig, type ForbiddenErrorConstructor, type ForbiddenErrorInstance, type FormField, type FormFieldType, type GeneratedPermission, type InputType, type KnexAlterTableBuilder, type KnexCreateTableBuilder, type KnexTransaction, type ListType, type MigrationHelpers, type ModuleAbilities, type ModuleContext, type ModuleManifest, type ModuleMiddlewares, type ModuleRequirements, type OwnershipCondition, type PaginatedResult, type PaginationParams, type PluginAuthRequest, type PluginCategory, type PluginManifest, type ReferenceEntityDefinition, type RolePermission, type SingleEntityDefinition, type TempEntityDefinition, type UsersResolver, type ValidateSchemas, type ValidationSchema, type ViewEntityDefinition, type VirtualEntityDefinition, generateCaslPermissions, generateCaslSeed, generateMigration, generateModel, generateZodSchema, getEntitySubject };
778
+ export { type AbilityLike, type ActionEntityDefinition, type AuthRequest, type BaseUser, type CaslAction, type CollectionEntityDefinition, type ComputedEntityDefinition, type ConfigEntityDefinition, type DbType, type EntityCaslConfig, type EntityDefinition, type EntityIndex, type EventEntityDefinition, type ExternalEntityDefinition, type FieldCaslAccess, type FieldDbConfig, type FieldDefinition, type FieldMeta, type FieldOptions, type FieldRelation, type FieldValidation, type FieldValidationConfig, type ForbiddenErrorConstructor, type ForbiddenErrorInstance, type FormField, type FormFieldType, GENERATED_DIR, type GeneratedPermission, type InputType, type KnexAlterTableBuilder, type KnexCreateTableBuilder, type KnexTransaction, type ListType, type MigrationHelpers, type ModuleAbilities, type ModuleContext, type ModuleManifest, type ModuleMiddlewares, type ModuleRequirements, type NonPersistentEntityDefinition, type OwnershipCondition, type PaginatedResult, type PaginationParams, type PersistentEntityDefinition, type PluginAuthRequest, type PluginCategory, type PluginManifest, type ReferenceEntityDefinition, type RolePermission, type SingleEntityDefinition, type TempEntityDefinition, type ValidateSchemas, type ValidationSchema, type ViewEntityDefinition, type VirtualEntityDefinition, generateCaslPermissions, generateCaslSeed, generateMigration, generateMigrationsFile, generateModel, generateModelsFile, generateReadOnlyModel, generateReadOnlySchema, generateSchemasFile, generateZodSchema, getEntityName, getEntitySubject, hasTable, isPersistentEntity, isSingletonEntity };
package/dist/index.js CHANGED
@@ -1,7 +1,14 @@
1
1
  // src/generators.ts
2
+ var GENERATED_DIR = "__generated__";
2
3
  function isPersistentEntity(entity) {
3
- const nonPersistent = ["action", "external", "virtual", "computed"];
4
- return !nonPersistent.includes(entity.type ?? "collection");
4
+ const withoutOwnTable = ["action", "external", "virtual", "computed", "single"];
5
+ return !withoutOwnTable.includes(entity.type ?? "collection");
6
+ }
7
+ function isSingletonEntity(entity) {
8
+ return entity.type === "single";
9
+ }
10
+ function hasTable(entity) {
11
+ return "table" in entity && typeof entity.table === "string";
5
12
  }
6
13
  function generateMigration(entity) {
7
14
  const { table, fields } = entity;
@@ -291,19 +298,81 @@ function dbTypeToTsType(db) {
291
298
  return "unknown";
292
299
  }
293
300
  }
301
+ function toPascalCase(str) {
302
+ return str.split("_").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
303
+ }
304
+ function toSingular(str) {
305
+ if (str.endsWith("ies")) return str.slice(0, -3) + "y";
306
+ if (str.endsWith("s")) return str.slice(0, -1);
307
+ return str;
308
+ }
294
309
  function tableToEntityName(table) {
295
310
  const withoutPrefix = table.replace(/^[a-z]{2,4}_/, "");
296
- const singular = withoutPrefix.endsWith("ies") ? withoutPrefix.slice(0, -3) + "y" : withoutPrefix.endsWith("s") ? withoutPrefix.slice(0, -1) : withoutPrefix;
297
- return singular.charAt(0).toUpperCase() + singular.slice(1);
311
+ return toPascalCase(toSingular(withoutPrefix));
298
312
  }
299
313
  function tableToSubject(table) {
300
314
  const match = table.match(/^([a-z]{2,4})_(.+)$/);
301
315
  if (!match) return tableToEntityName(table);
302
316
  const [, prefix, rest] = match;
303
317
  const prefixPascal = prefix.charAt(0).toUpperCase() + prefix.slice(1);
304
- const singular = rest.endsWith("ies") ? rest.slice(0, -3) + "y" : rest.endsWith("s") ? rest.slice(0, -1) : rest;
305
- const restPascal = singular.charAt(0).toUpperCase() + singular.slice(1);
306
- return prefixPascal + restPascal;
318
+ return prefixPascal + toPascalCase(toSingular(rest));
319
+ }
320
+ function labelToEntityName(label) {
321
+ const singular = label.endsWith("ies") ? label.slice(0, -3) + "y" : label.endsWith("s") ? label.slice(0, -1) : label;
322
+ return singular.charAt(0).toUpperCase() + singular.slice(1).replace(/\s+/g, "");
323
+ }
324
+ function generateReadOnlySchema(entity) {
325
+ const { label, fields } = entity;
326
+ const entityName = labelToEntityName(label);
327
+ const lines = [
328
+ `import { z } from 'zod'`,
329
+ ``,
330
+ `// === OUTPUT SCHEMA ===`,
331
+ `export const ${entityName.toLowerCase()}Schema = z.object({`
332
+ ];
333
+ for (const [name, field] of Object.entries(fields)) {
334
+ const zodType = dbTypeToZodType(field.db.type);
335
+ const nullable = field.db.nullable ? `.nullable()` : "";
336
+ lines.push(` ${name}: ${zodType}${nullable},`);
337
+ }
338
+ lines.push(`})`);
339
+ lines.push(``);
340
+ lines.push(`// === QUERY ===`);
341
+ lines.push(`export const ${entityName.toLowerCase()}QuerySchema = z.object({`);
342
+ lines.push(` page: z.coerce.number().int().min(1).default(1),`);
343
+ lines.push(` limit: z.coerce.number().int().min(1).max(100).default(20),`);
344
+ for (const [name, field] of Object.entries(fields)) {
345
+ if (field.meta?.searchable) {
346
+ const zodType = dbTypeToZodType(field.db.type);
347
+ lines.push(` ${name}: ${zodType}.optional(),`);
348
+ }
349
+ }
350
+ lines.push(`})`);
351
+ lines.push(``);
352
+ lines.push(`// === INFERRED TYPES ===`);
353
+ lines.push(`export type ${entityName} = z.infer<typeof ${entityName.toLowerCase()}Schema>`);
354
+ lines.push(`export type ${entityName}Query = z.infer<typeof ${entityName.toLowerCase()}QuerySchema>`);
355
+ lines.push(``);
356
+ return lines.join("\n");
357
+ }
358
+ function generateReadOnlyModel(entity) {
359
+ const { label, fields } = entity;
360
+ const entityName = labelToEntityName(label);
361
+ const lines = [
362
+ `/**`,
363
+ ` * ${label}`,
364
+ ` * Generated from EntityDefinition (${entity.type})`,
365
+ ` */`,
366
+ `export interface ${entityName} {`
367
+ ];
368
+ for (const [name, field] of Object.entries(fields)) {
369
+ const tsType = dbTypeToTsType(field.db);
370
+ const optional = field.db.nullable ? "?" : "";
371
+ lines.push(` ${name}${optional}: ${tsType}`);
372
+ }
373
+ lines.push(`}`);
374
+ lines.push(``);
375
+ return lines.join("\n");
307
376
  }
308
377
  function getFieldsForRole(entity, role, action) {
309
378
  const { fields, casl } = entity;
@@ -441,11 +510,296 @@ function generateCaslSeed(entities) {
441
510
  function getEntitySubject(entity) {
442
511
  return entity.casl?.subject ?? tableToSubject(entity.table);
443
512
  }
513
+ function getEntityName(entity) {
514
+ if ("table" in entity) {
515
+ const withoutPrefix = entity.table.replace(/^[a-z]{2,4}_/, "");
516
+ return toPascalCase(toSingular(withoutPrefix));
517
+ } else if ("key" in entity) {
518
+ return toPascalCase(entity.key);
519
+ } else {
520
+ return toSingular(entity.label).replace(/\s+/g, "");
521
+ }
522
+ }
523
+ function dbTypeToZodSimple(type, nullable) {
524
+ let zod = "";
525
+ switch (type) {
526
+ case "string":
527
+ case "text":
528
+ case "uuid":
529
+ zod = "z.string()";
530
+ break;
531
+ case "integer":
532
+ zod = "z.number().int()";
533
+ break;
534
+ case "decimal":
535
+ zod = "z.number()";
536
+ break;
537
+ case "boolean":
538
+ zod = "z.boolean()";
539
+ break;
540
+ case "date":
541
+ case "datetime":
542
+ zod = "z.string().datetime()";
543
+ break;
544
+ case "json":
545
+ zod = "z.record(z.unknown())";
546
+ break;
547
+ default:
548
+ zod = "z.unknown()";
549
+ }
550
+ return nullable ? `${zod}.nullable()` : zod;
551
+ }
552
+ function dbTypeToTsSimple(type) {
553
+ switch (type) {
554
+ case "string":
555
+ case "text":
556
+ case "uuid":
557
+ return "string";
558
+ case "integer":
559
+ case "decimal":
560
+ return "number";
561
+ case "boolean":
562
+ return "boolean";
563
+ case "date":
564
+ case "datetime":
565
+ return "Date";
566
+ case "json":
567
+ return "Record<string, unknown>";
568
+ default:
569
+ return "unknown";
570
+ }
571
+ }
572
+ function generateSchemasFile(definitions) {
573
+ const lines = [
574
+ "/**",
575
+ " * AUTO-GENERATED - Do not edit manually",
576
+ " * Generated from EntityDefinition via @gzl10/nexus-sdk generators",
577
+ " */",
578
+ "",
579
+ "import { z } from 'zod'",
580
+ ""
581
+ ];
582
+ for (const entity of definitions) {
583
+ const name = getEntityName(entity);
584
+ lines.push(`// ============================================================================`);
585
+ lines.push(`// ${name.toUpperCase()} (${entity.type ?? "collection"})`);
586
+ lines.push(`// ============================================================================`);
587
+ lines.push("");
588
+ if (isPersistentEntity(entity)) {
589
+ const schema = generateZodSchema(entity);
590
+ const schemaLines = schema.split("\n").filter(
591
+ (l) => !l.startsWith("import") && l.trim() !== ""
592
+ );
593
+ lines.push(...schemaLines);
594
+ } else if (entity.type === "single") {
595
+ lines.push(`export const ${name.toLowerCase()}Schema = z.object({`);
596
+ for (const [fieldName, field] of Object.entries(entity.fields)) {
597
+ const zodType = dbTypeToZodSimple(field.db.type, field.db.nullable);
598
+ lines.push(` ${fieldName}: ${zodType},`);
599
+ }
600
+ lines.push("})");
601
+ lines.push("");
602
+ lines.push(`export type ${name} = z.infer<typeof ${name.toLowerCase()}Schema>`);
603
+ } else {
604
+ const schema = generateReadOnlySchema(entity);
605
+ const schemaLines = schema.split("\n").filter(
606
+ (l) => !l.startsWith("import") && l.trim() !== ""
607
+ );
608
+ lines.push(...schemaLines);
609
+ }
610
+ lines.push("");
611
+ }
612
+ return lines.join("\n");
613
+ }
614
+ function generateModelsFile(definitions) {
615
+ const lines = [
616
+ "/**",
617
+ " * AUTO-GENERATED - Do not edit manually",
618
+ " * Generated from EntityDefinition via @gzl10/nexus-sdk generators",
619
+ " */",
620
+ ""
621
+ ];
622
+ for (const entity of definitions) {
623
+ const name = getEntityName(entity);
624
+ lines.push(`// ============================================================================`);
625
+ lines.push(`// ${name.toUpperCase()} (${entity.type ?? "collection"})`);
626
+ lines.push(`// ============================================================================`);
627
+ lines.push("");
628
+ if (isPersistentEntity(entity)) {
629
+ const model = generateModel(entity);
630
+ const modelLines = model.split("\n");
631
+ lines.push(...modelLines);
632
+ } else if (entity.type === "single") {
633
+ lines.push(`/**`);
634
+ lines.push(` * ${entity.label}`);
635
+ lines.push(` * Generated from EntityDefinition (single)`);
636
+ lines.push(` */`);
637
+ lines.push(`export interface ${name} {`);
638
+ for (const [fieldName, field] of Object.entries(entity.fields)) {
639
+ const tsType = dbTypeToTsSimple(field.db.type);
640
+ const optional = field.db.nullable ? "?" : "";
641
+ lines.push(` ${fieldName}${optional}: ${tsType}`);
642
+ }
643
+ lines.push("}");
644
+ } else {
645
+ const model = generateReadOnlyModel(entity);
646
+ lines.push(model);
647
+ }
648
+ lines.push("");
649
+ }
650
+ return lines.join("\n");
651
+ }
652
+ function generateMigrationsFile(definitions) {
653
+ const persistentEntities = definitions.filter(isPersistentEntity);
654
+ if (persistentEntities.length === 0) {
655
+ return [
656
+ "/**",
657
+ " * AUTO-GENERATED - Do not edit manually",
658
+ " * Generated from EntityDefinition via @gzl10/nexus-sdk generators",
659
+ " */",
660
+ "",
661
+ "import type { ModuleContext } from '@gzl10/nexus-sdk'",
662
+ "",
663
+ "// No persistent entities to migrate",
664
+ "export async function migrate(_ctx: ModuleContext): Promise<void> {}",
665
+ ""
666
+ ].join("\n");
667
+ }
668
+ const lines = [
669
+ "/**",
670
+ " * AUTO-GENERATED - Do not edit manually",
671
+ " * Generated from EntityDefinition via @gzl10/nexus-sdk generators",
672
+ " */",
673
+ "",
674
+ "import type { ModuleContext, Knex } from '@gzl10/nexus-sdk'",
675
+ "",
676
+ "export async function migrate(ctx: ModuleContext): Promise<void> {",
677
+ " const { db, logger, helpers } = ctx",
678
+ " const { addTimestamps, addAuditFieldsIfMissing } = helpers",
679
+ ""
680
+ ];
681
+ for (const entity of persistentEntities) {
682
+ const { table, fields } = entity;
683
+ const timestamps = "timestamps" in entity ? entity.timestamps : false;
684
+ const audit = "audit" in entity ? entity.audit : false;
685
+ const indexes = "indexes" in entity ? entity.indexes : void 0;
686
+ const name = getEntityName(entity);
687
+ lines.push(` // === ${name.toUpperCase()} ===`);
688
+ lines.push(` if (!(await db.schema.hasTable('${table}'))) {`);
689
+ lines.push(` await db.schema.createTable('${table}', (table: Knex.CreateTableBuilder) => {`);
690
+ for (const [fieldName, field] of Object.entries(fields)) {
691
+ const columnCode = generateColumnCodeInline(fieldName, field);
692
+ lines.push(` ${columnCode}`);
693
+ }
694
+ if (timestamps) {
695
+ lines.push(` addTimestamps(table, db)`);
696
+ }
697
+ if (indexes?.length) {
698
+ lines.push("");
699
+ for (const idx of indexes) {
700
+ if (idx.unique) {
701
+ lines.push(` table.unique([${idx.columns.map((c) => `'${c}'`).join(", ")}])`);
702
+ } else {
703
+ lines.push(` table.index([${idx.columns.map((c) => `'${c}'`).join(", ")}])`);
704
+ }
705
+ }
706
+ }
707
+ lines.push(` })`);
708
+ lines.push(` logger.info('Created table: ${table}')`);
709
+ lines.push(` }`);
710
+ if (audit) {
711
+ lines.push(` await addAuditFieldsIfMissing(db, '${table}')`);
712
+ }
713
+ lines.push("");
714
+ }
715
+ lines.push("}");
716
+ lines.push("");
717
+ return lines.join("\n");
718
+ }
719
+ function generateColumnCodeInline(name, field) {
720
+ const { db } = field;
721
+ let code = "";
722
+ switch (db.type) {
723
+ case "string":
724
+ code = db.size ? `table.string('${name}', ${db.size})` : `table.string('${name}')`;
725
+ break;
726
+ case "text":
727
+ code = `table.text('${name}')`;
728
+ break;
729
+ case "integer":
730
+ code = `table.integer('${name}')`;
731
+ break;
732
+ case "decimal":
733
+ if (db.precision) {
734
+ code = `table.decimal('${name}', ${db.precision[0]}, ${db.precision[1]})`;
735
+ } else {
736
+ code = `table.decimal('${name}')`;
737
+ }
738
+ break;
739
+ case "boolean":
740
+ code = `table.boolean('${name}')`;
741
+ break;
742
+ case "date":
743
+ code = `table.date('${name}')`;
744
+ break;
745
+ case "datetime":
746
+ code = `table.datetime('${name}')`;
747
+ break;
748
+ case "json":
749
+ code = `table.json('${name}')`;
750
+ break;
751
+ case "uuid":
752
+ code = `table.uuid('${name}')`;
753
+ break;
754
+ default:
755
+ code = `table.string('${name}')`;
756
+ }
757
+ if (name === "id") {
758
+ code += ".primary()";
759
+ }
760
+ if (!db.nullable) {
761
+ code += ".notNullable()";
762
+ } else {
763
+ code += ".nullable()";
764
+ }
765
+ if (db.unique) {
766
+ code += ".unique()";
767
+ }
768
+ if (db.default !== void 0) {
769
+ if (typeof db.default === "string") {
770
+ code += `.defaultTo('${db.default}')`;
771
+ } else if (typeof db.default === "boolean") {
772
+ code += `.defaultTo(${db.default})`;
773
+ } else {
774
+ code += `.defaultTo(${db.default})`;
775
+ }
776
+ }
777
+ if (db.index) {
778
+ code += ".index()";
779
+ }
780
+ if (field.relation) {
781
+ code += `.references('${field.relation.column ?? "id"}').inTable('${field.relation.table}')`;
782
+ if (field.relation.onDelete) {
783
+ code += `.onDelete('${field.relation.onDelete}')`;
784
+ }
785
+ }
786
+ return code;
787
+ }
444
788
  export {
789
+ GENERATED_DIR,
445
790
  generateCaslPermissions,
446
791
  generateCaslSeed,
447
792
  generateMigration,
793
+ generateMigrationsFile,
448
794
  generateModel,
795
+ generateModelsFile,
796
+ generateReadOnlyModel,
797
+ generateReadOnlySchema,
798
+ generateSchemasFile,
449
799
  generateZodSchema,
450
- getEntitySubject
800
+ getEntityName,
801
+ getEntitySubject,
802
+ hasTable,
803
+ isPersistentEntity,
804
+ isSingletonEntity
451
805
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gzl10/nexus-sdk",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "SDK types for creating Nexus plugins and modules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",