@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.
@@ -214,7 +214,8 @@ function model(table, opts) {
214
214
  search: opts.search,
215
215
  defaultWhere: opts.defaultWhere,
216
216
  derived: opts.derived,
217
- validate: opts.validate
217
+ validate: opts.validate,
218
+ branded: opts.branded
218
219
  };
219
220
  }
220
221
  __name(model, "model");
@@ -1766,6 +1767,32 @@ __name(sortTypedJsonFields, "sortTypedJsonFields");
1766
1767
 
1767
1768
  // src/codegen/emit.ts
1768
1769
  var DB_ATTR_RE = /@db\.(\w+)(?:\((\d+)\))?/;
1770
+ function isUuidField(t, fieldName) {
1771
+ const col = t.table[fieldName];
1772
+ if (!col) return false;
1773
+ return col.columnType === "PgUUID";
1774
+ }
1775
+ __name(isUuidField, "isUuidField");
1776
+ function isPkField(t, fieldName) {
1777
+ const col = t.table[fieldName];
1778
+ if (!col) return false;
1779
+ if (col.primary) return true;
1780
+ const sqlName = col.name;
1781
+ return t.cfg.primaryKeys.some((pk) => pk.columns.some((c) => c.name === sqlName));
1782
+ }
1783
+ __name(isPkField, "isPkField");
1784
+ function findFkTarget(t, fieldName, fkRelations) {
1785
+ const modelFks = fkRelations[t.modelName];
1786
+ if (!modelFks) return null;
1787
+ for (const fkInfo of Object.values(modelFks)) {
1788
+ const idx = fkInfo.fields.indexOf(fieldName);
1789
+ if (idx >= 0) {
1790
+ return fkInfo.targetExportName;
1791
+ }
1792
+ }
1793
+ return null;
1794
+ }
1795
+ __name(findFkTarget, "findFkTarget");
1769
1796
  function buildDerivedEnumName(modelName, fieldName) {
1770
1797
  return `${toPascalCase(modelName)}${toPascalCase(fieldName)}`;
1771
1798
  }
@@ -2261,8 +2288,9 @@ function emitSchemaTs({ tables, enumMap, modelRelations, inverseRelations, searc
2261
2288
  return out.join("\n");
2262
2289
  }
2263
2290
  __name(emitSchemaTs, "emitSchemaTs");
2264
- function emitModelsTs(tables, typedJsonFields = []) {
2291
+ function emitModelsTs(tables, typedJsonFields = [], branding) {
2265
2292
  const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
2293
+ const hasBranding = branding && (Object.keys(branding.brandedFields).length > 0 || tables.some((t) => getEntityFieldNames(t).some((f) => isUuidField(t, f) && isPkField(t, f))));
2266
2294
  const out = [
2267
2295
  ...emitGeneratedFileBanner()
2268
2296
  ];
@@ -2270,6 +2298,10 @@ function emitModelsTs(tables, typedJsonFields = []) {
2270
2298
  out.push('import type * as $ from "@zenstackhq/orm";');
2271
2299
  out.push('import type * as Json from "./json";');
2272
2300
  out.push('import { type SchemaType as Schema } from "./schema";');
2301
+ if (hasBranding) {
2302
+ out.push("");
2303
+ out.push("declare const __brand: unique symbol;");
2304
+ }
2273
2305
  out.push("");
2274
2306
  for (const t of tables) {
2275
2307
  out.push(`export interface ${t.typeName} extends $.ModelResult<Schema, ${esc(t.modelName)}> {}`);
@@ -2280,7 +2312,12 @@ function emitModelsTs(tables, typedJsonFields = []) {
2280
2312
  if (jsonAlias) {
2281
2313
  out.push(` export interface ${exportName} extends Json.${jsonAlias} {}`);
2282
2314
  } else {
2283
- out.push(` export type ${exportName} = ${t.typeName}[${esc(fieldName)}];`);
2315
+ const brandedLine = branding ? emitBrandedFieldLine(t, fieldName, exportName, branding, " ") : null;
2316
+ if (brandedLine) {
2317
+ out.push(...brandedLine);
2318
+ } else {
2319
+ out.push(` export type ${exportName} = ${t.typeName}[${esc(fieldName)}];`);
2320
+ }
2284
2321
  }
2285
2322
  }
2286
2323
  out.push("}");
@@ -2289,6 +2326,33 @@ function emitModelsTs(tables, typedJsonFields = []) {
2289
2326
  return out.join("\n");
2290
2327
  }
2291
2328
  __name(emitModelsTs, "emitModelsTs");
2329
+ function emitBrandedFieldLine(t, fieldName, exportName, branding, indent) {
2330
+ const customBranded = branding.brandedFields[t.modelName]?.[fieldName];
2331
+ if (isUuidField(t, fieldName) && isPkField(t, fieldName)) {
2332
+ const brand = `${t.modelName}.${fieldName}`;
2333
+ return [
2334
+ `${indent}export type ${exportName} = string & { [__brand]: '${brand}' };`,
2335
+ `${indent}export const ${exportName} = (id: string): ${exportName} => id as ${exportName};`
2336
+ ];
2337
+ }
2338
+ if (isUuidField(t, fieldName)) {
2339
+ const targetExportName = findFkTarget(t, fieldName, branding.fkRelations);
2340
+ if (targetExportName) {
2341
+ return [
2342
+ `${indent}export type ${exportName} = ${targetExportName}.Id;`
2343
+ ];
2344
+ }
2345
+ }
2346
+ if (customBranded) {
2347
+ const brand = `${t.modelName}.${fieldName}`;
2348
+ return [
2349
+ `${indent}export type ${exportName} = string & { [__brand]: '${brand}' };`,
2350
+ `${indent}export const ${exportName} = (id: string): ${exportName} => id as ${exportName};`
2351
+ ];
2352
+ }
2353
+ return null;
2354
+ }
2355
+ __name(emitBrandedFieldLine, "emitBrandedFieldLine");
2292
2356
  function emitViewsTs(views, typedJsonFields = []) {
2293
2357
  const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
2294
2358
  const out = [
@@ -2354,12 +2418,13 @@ function emitInputTs(tables) {
2354
2418
  return out.join("\n");
2355
2419
  }
2356
2420
  __name(emitInputTs, "emitInputTs");
2357
- function emitIndexTs({ tables, views, enumMap, typeDefs, typedJsonFields }) {
2421
+ function emitIndexTs({ tables, views, enumMap, typeDefs, typedJsonFields, branding }) {
2358
2422
  const allEnums = new Map([
2359
2423
  ...enumMap,
2360
2424
  ...collectDerivedEnums(tables, enumMap)
2361
2425
  ]);
2362
2426
  const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
2427
+ const hasBranding = branding && (Object.keys(branding.brandedFields).length > 0 || tables.some((t) => getEntityFieldNames(t).some((f) => isUuidField(t, f) && isPkField(t, f))));
2363
2428
  const out = [
2364
2429
  ...emitGeneratedFileBanner()
2365
2430
  ];
@@ -2367,6 +2432,10 @@ function emitIndexTs({ tables, views, enumMap, typeDefs, typedJsonFields }) {
2367
2432
  out.push('import type * as $ from "@zenstackhq/orm";');
2368
2433
  out.push('import type * as RawJson from "../../supabase/schema/types";');
2369
2434
  out.push('import { type SchemaType as Schema } from "./schema";');
2435
+ if (hasBranding) {
2436
+ out.push("");
2437
+ out.push("declare const __brand: unique symbol;");
2438
+ }
2370
2439
  out.push("");
2371
2440
  out.push("export namespace Json {");
2372
2441
  out.push(...emitJsonNamespaceBlock(typeDefs, typedJsonFields, " "));
@@ -2381,7 +2450,7 @@ function emitIndexTs({ tables, views, enumMap, typeDefs, typedJsonFields }) {
2381
2450
  out.push("");
2382
2451
  out.push("export namespace Table {");
2383
2452
  for (const table of tables) {
2384
- out.push(...emitEntityNamespaceBlock(table, table.modelName, jsonFieldAliases, " "));
2453
+ out.push(...emitEntityNamespaceBlock(table, table.modelName, jsonFieldAliases, " ", branding));
2385
2454
  out.push("");
2386
2455
  }
2387
2456
  out.push("}");
@@ -2540,7 +2609,7 @@ function createJsonFieldAliasMap(typedJsonFields) {
2540
2609
  ]));
2541
2610
  }
2542
2611
  __name(createJsonFieldAliasMap, "createJsonFieldAliasMap");
2543
- function emitEntityNamespaceBlock(entity, modelName, jsonFieldAliases, indent = "") {
2612
+ function emitEntityNamespaceBlock(entity, modelName, jsonFieldAliases, indent = "", branding) {
2544
2613
  const out = [];
2545
2614
  out.push(`${indent}export interface ${entity.typeName} extends $.ModelResult<Schema, ${esc(modelName)}> {}`);
2546
2615
  out.push(`${indent}export namespace ${entity.typeName} {`);
@@ -2550,7 +2619,13 @@ function emitEntityNamespaceBlock(entity, modelName, jsonFieldAliases, indent =
2550
2619
  if (jsonAlias) {
2551
2620
  out.push(`${indent} export interface ${exportName} extends Json.${jsonAlias} {}`);
2552
2621
  } else {
2553
- out.push(`${indent} export type ${exportName} = ${entity.typeName}[${esc(fieldName)}];`);
2622
+ const isTable = "table" in entity;
2623
+ const brandedLine = isTable && branding ? emitBrandedFieldLine(entity, fieldName, exportName, branding, `${indent} `) : null;
2624
+ if (brandedLine) {
2625
+ out.push(...brandedLine);
2626
+ } else {
2627
+ out.push(`${indent} export type ${exportName} = ${entity.typeName}[${esc(fieldName)}];`);
2628
+ }
2554
2629
  }
2555
2630
  }
2556
2631
  out.push(`${indent}}`);