@danielhritcu/zenstack-custom 1.1.0 → 1.2.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.
@@ -57,6 +57,7 @@ interface ModelConfig {
57
57
  defaultWhere?: Record<string, unknown>;
58
58
  derived?: Record<string, DerivedField>;
59
59
  validate?: Record<string, unknown>;
60
+ branded?: Record<string, true>;
60
61
  }
61
62
  interface ExtendedSchema {
62
63
  tables: Record<string, PgTable>;
@@ -91,7 +92,9 @@ declare function defineConfig<T extends Record<string, PgTable>, D extends Recor
91
92
  derived?: D;
92
93
  models: (orm: T & {
93
94
  [K in keyof D]: D[K] extends DerivedModelDescriptor<infer TBase> ? TBase & D[K] : D[K];
94
- }) => Record<string, ModelConfig>;
95
+ }) => {
96
+ [K in keyof T]: ModelConfig;
97
+ };
95
98
  }): ZenConfig;
96
99
 
97
100
  export { type AnyRelation as A, type DerivedField as D, type ExtendedSchema as E, type GlobalConfig as G, type ManyRelation as M, type OneRelation as O, type SchemaConfig as S, type ThroughPath as T, type ZenConfig as Z, type DerivedModelDescriptor as a, type ModelConfig as b, type ModelsOutput as c, type SearchField as d, type SearchProfile as e, type ThroughRelation as f, defineConfig as g };
@@ -57,6 +57,7 @@ interface ModelConfig {
57
57
  defaultWhere?: Record<string, unknown>;
58
58
  derived?: Record<string, DerivedField>;
59
59
  validate?: Record<string, unknown>;
60
+ branded?: Record<string, true>;
60
61
  }
61
62
  interface ExtendedSchema {
62
63
  tables: Record<string, PgTable>;
@@ -91,7 +92,9 @@ declare function defineConfig<T extends Record<string, PgTable>, D extends Recor
91
92
  derived?: D;
92
93
  models: (orm: T & {
93
94
  [K in keyof D]: D[K] extends DerivedModelDescriptor<infer TBase> ? TBase & D[K] : D[K];
94
- }) => Record<string, ModelConfig>;
95
+ }) => {
96
+ [K in keyof T]: ModelConfig;
97
+ };
95
98
  }): ZenConfig;
96
99
 
97
100
  export { type AnyRelation as A, type DerivedField as D, type ExtendedSchema as E, type GlobalConfig as G, type ManyRelation as M, type OneRelation as O, type SchemaConfig as S, type ThroughPath as T, type ZenConfig as Z, type DerivedModelDescriptor as a, type ModelConfig as b, type ModelsOutput as c, type SearchField as d, type SearchProfile as e, type ThroughRelation as f, defineConfig as g };
package/dist/index.cjs CHANGED
@@ -267,7 +267,8 @@ function model(table, opts) {
267
267
  search: opts.search,
268
268
  defaultWhere: opts.defaultWhere,
269
269
  derived: opts.derived,
270
- validate: opts.validate
270
+ validate: opts.validate,
271
+ branded: opts.branded
271
272
  };
272
273
  }
273
274
  __name(model, "model");
@@ -1979,6 +1980,32 @@ __name(sortTypedJsonFields, "sortTypedJsonFields");
1979
1980
 
1980
1981
  // src/codegen/emit.ts
1981
1982
  var DB_ATTR_RE = /@db\.(\w+)(?:\((\d+)\))?/;
1983
+ function isUuidField(t, fieldName) {
1984
+ const col = t.table[fieldName];
1985
+ if (!col) return false;
1986
+ return col.columnType === "PgUUID";
1987
+ }
1988
+ __name(isUuidField, "isUuidField");
1989
+ function isPkField(t, fieldName) {
1990
+ const col = t.table[fieldName];
1991
+ if (!col) return false;
1992
+ if (col.primary) return true;
1993
+ const sqlName = col.name;
1994
+ return t.cfg.primaryKeys.some((pk) => pk.columns.some((c) => c.name === sqlName));
1995
+ }
1996
+ __name(isPkField, "isPkField");
1997
+ function findFkTarget(t, fieldName, fkRelations) {
1998
+ const modelFks = fkRelations[t.modelName];
1999
+ if (!modelFks) return null;
2000
+ for (const fkInfo of Object.values(modelFks)) {
2001
+ const idx = fkInfo.fields.indexOf(fieldName);
2002
+ if (idx >= 0) {
2003
+ return fkInfo.targetExportName;
2004
+ }
2005
+ }
2006
+ return null;
2007
+ }
2008
+ __name(findFkTarget, "findFkTarget");
1982
2009
  function buildDerivedEnumName(modelName, fieldName) {
1983
2010
  return `${toPascalCase(modelName)}${toPascalCase(fieldName)}`;
1984
2011
  }
@@ -2474,8 +2501,9 @@ function emitSchemaTs({ tables, enumMap, modelRelations, inverseRelations, searc
2474
2501
  return out.join("\n");
2475
2502
  }
2476
2503
  __name(emitSchemaTs, "emitSchemaTs");
2477
- function emitModelsTs(tables, typedJsonFields = []) {
2504
+ function emitModelsTs(tables, typedJsonFields = [], branding) {
2478
2505
  const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
2506
+ const hasBranding = branding && (Object.keys(branding.brandedFields).length > 0 || tables.some((t) => getEntityFieldNames(t).some((f) => isUuidField(t, f) && isPkField(t, f))));
2479
2507
  const out = [
2480
2508
  ...emitGeneratedFileBanner()
2481
2509
  ];
@@ -2483,6 +2511,10 @@ function emitModelsTs(tables, typedJsonFields = []) {
2483
2511
  out.push('import type * as $ from "@zenstackhq/orm";');
2484
2512
  out.push('import type * as Json from "./json";');
2485
2513
  out.push('import { type SchemaType as Schema } from "./schema";');
2514
+ if (hasBranding) {
2515
+ out.push("");
2516
+ out.push("declare const __brand: unique symbol;");
2517
+ }
2486
2518
  out.push("");
2487
2519
  for (const t of tables) {
2488
2520
  out.push(`export interface ${t.typeName} extends $.ModelResult<Schema, ${esc(t.modelName)}> {}`);
@@ -2493,7 +2525,12 @@ function emitModelsTs(tables, typedJsonFields = []) {
2493
2525
  if (jsonAlias) {
2494
2526
  out.push(` export interface ${exportName} extends Json.${jsonAlias} {}`);
2495
2527
  } else {
2496
- out.push(` export type ${exportName} = ${t.typeName}[${esc(fieldName)}];`);
2528
+ const brandedLine = branding ? emitBrandedFieldLine(t, fieldName, exportName, branding, " ") : null;
2529
+ if (brandedLine) {
2530
+ out.push(...brandedLine);
2531
+ } else {
2532
+ out.push(` export type ${exportName} = ${t.typeName}[${esc(fieldName)}];`);
2533
+ }
2497
2534
  }
2498
2535
  }
2499
2536
  out.push("}");
@@ -2502,6 +2539,33 @@ function emitModelsTs(tables, typedJsonFields = []) {
2502
2539
  return out.join("\n");
2503
2540
  }
2504
2541
  __name(emitModelsTs, "emitModelsTs");
2542
+ function emitBrandedFieldLine(t, fieldName, exportName, branding, indent2) {
2543
+ const customBranded = branding.brandedFields[t.modelName]?.[fieldName];
2544
+ if (isUuidField(t, fieldName) && isPkField(t, fieldName)) {
2545
+ const brand = `${t.modelName}.${fieldName}`;
2546
+ return [
2547
+ `${indent2}export type ${exportName} = string & { [__brand]: '${brand}' };`,
2548
+ `${indent2}export const ${exportName} = (id: string): ${exportName} => id as ${exportName};`
2549
+ ];
2550
+ }
2551
+ if (isUuidField(t, fieldName)) {
2552
+ const targetExportName = findFkTarget(t, fieldName, branding.fkRelations);
2553
+ if (targetExportName) {
2554
+ return [
2555
+ `${indent2}export type ${exportName} = ${targetExportName}.Id;`
2556
+ ];
2557
+ }
2558
+ }
2559
+ if (customBranded) {
2560
+ const brand = `${t.modelName}.${fieldName}`;
2561
+ return [
2562
+ `${indent2}export type ${exportName} = string & { [__brand]: '${brand}' };`,
2563
+ `${indent2}export const ${exportName} = (id: string): ${exportName} => id as ${exportName};`
2564
+ ];
2565
+ }
2566
+ return null;
2567
+ }
2568
+ __name(emitBrandedFieldLine, "emitBrandedFieldLine");
2505
2569
  function emitViewsTs(views, typedJsonFields = []) {
2506
2570
  const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
2507
2571
  const out = [
@@ -2567,12 +2631,13 @@ function emitInputTs(tables) {
2567
2631
  return out.join("\n");
2568
2632
  }
2569
2633
  __name(emitInputTs, "emitInputTs");
2570
- function emitIndexTs({ tables, views, enumMap, typeDefs, typedJsonFields }) {
2634
+ function emitIndexTs({ tables, views, enumMap, typeDefs, typedJsonFields, branding }) {
2571
2635
  const allEnums = new Map([
2572
2636
  ...enumMap,
2573
2637
  ...collectDerivedEnums(tables, enumMap)
2574
2638
  ]);
2575
2639
  const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
2640
+ const hasBranding = branding && (Object.keys(branding.brandedFields).length > 0 || tables.some((t) => getEntityFieldNames(t).some((f) => isUuidField(t, f) && isPkField(t, f))));
2576
2641
  const out = [
2577
2642
  ...emitGeneratedFileBanner()
2578
2643
  ];
@@ -2580,6 +2645,10 @@ function emitIndexTs({ tables, views, enumMap, typeDefs, typedJsonFields }) {
2580
2645
  out.push('import type * as $ from "@zenstackhq/orm";');
2581
2646
  out.push('import type * as RawJson from "../../supabase/schema/types";');
2582
2647
  out.push('import { type SchemaType as Schema } from "./schema";');
2648
+ if (hasBranding) {
2649
+ out.push("");
2650
+ out.push("declare const __brand: unique symbol;");
2651
+ }
2583
2652
  out.push("");
2584
2653
  out.push("export namespace Json {");
2585
2654
  out.push(...emitJsonNamespaceBlock(typeDefs, typedJsonFields, " "));
@@ -2594,7 +2663,7 @@ function emitIndexTs({ tables, views, enumMap, typeDefs, typedJsonFields }) {
2594
2663
  out.push("");
2595
2664
  out.push("export namespace Table {");
2596
2665
  for (const table of tables) {
2597
- out.push(...emitEntityNamespaceBlock(table, table.modelName, jsonFieldAliases, " "));
2666
+ out.push(...emitEntityNamespaceBlock(table, table.modelName, jsonFieldAliases, " ", branding));
2598
2667
  out.push("");
2599
2668
  }
2600
2669
  out.push("}");
@@ -2753,7 +2822,7 @@ function createJsonFieldAliasMap(typedJsonFields) {
2753
2822
  ]));
2754
2823
  }
2755
2824
  __name(createJsonFieldAliasMap, "createJsonFieldAliasMap");
2756
- function emitEntityNamespaceBlock(entity, modelName, jsonFieldAliases, indent2 = "") {
2825
+ function emitEntityNamespaceBlock(entity, modelName, jsonFieldAliases, indent2 = "", branding) {
2757
2826
  const out = [];
2758
2827
  out.push(`${indent2}export interface ${entity.typeName} extends $.ModelResult<Schema, ${esc(modelName)}> {}`);
2759
2828
  out.push(`${indent2}export namespace ${entity.typeName} {`);
@@ -2763,7 +2832,13 @@ function emitEntityNamespaceBlock(entity, modelName, jsonFieldAliases, indent2 =
2763
2832
  if (jsonAlias) {
2764
2833
  out.push(`${indent2} export interface ${exportName} extends Json.${jsonAlias} {}`);
2765
2834
  } else {
2766
- out.push(`${indent2} export type ${exportName} = ${entity.typeName}[${esc(fieldName)}];`);
2835
+ const isTable = "table" in entity;
2836
+ const brandedLine = isTable && branding ? emitBrandedFieldLine(entity, fieldName, exportName, branding, `${indent2} `) : null;
2837
+ if (brandedLine) {
2838
+ out.push(...brandedLine);
2839
+ } else {
2840
+ out.push(`${indent2} export type ${exportName} = ${entity.typeName}[${esc(fieldName)}];`);
2841
+ }
2767
2842
  }
2768
2843
  }
2769
2844
  out.push(`${indent2}}`);