@prisma-next/target-postgres 0.14.0-dev.53 → 0.14.0-dev.55

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 (63) hide show
  1. package/dist/{authoring-ohGMgi8g.mjs → authoring-BBIGcFZM.mjs} +27 -4
  2. package/dist/authoring-BBIGcFZM.mjs.map +1 -0
  3. package/dist/contract-free.mjs +2 -2
  4. package/dist/{control-policy-CafkzSUC.mjs → control-policy-DievMCOV.mjs} +4 -4
  5. package/dist/{control-policy-CafkzSUC.mjs.map → control-policy-DievMCOV.mjs.map} +1 -1
  6. package/dist/control.mjs +174 -31
  7. package/dist/control.mjs.map +1 -1
  8. package/dist/{ddl-CZNFMoCp.mjs → ddl-D5j4JiAB.mjs} +2 -2
  9. package/dist/{ddl-CZNFMoCp.mjs.map → ddl-D5j4JiAB.mjs.map} +1 -1
  10. package/dist/{descriptor-meta-Cok-1QEK.mjs → descriptor-meta-C-tyS25s.mjs} +3 -3
  11. package/dist/{descriptor-meta-Cok-1QEK.mjs.map → descriptor-meta-C-tyS25s.mjs.map} +1 -1
  12. package/dist/{diff-database-schema-BivMht-X.mjs → diff-database-schema-ff3ioNtK.mjs} +7 -6
  13. package/dist/diff-database-schema-ff3ioNtK.mjs.map +1 -0
  14. package/dist/diff-database-schema.d.mts +1 -1
  15. package/dist/diff-database-schema.d.mts.map +1 -1
  16. package/dist/diff-database-schema.mjs +1 -1
  17. package/dist/issue-planner.mjs +1 -1
  18. package/dist/migration.mjs +2 -2
  19. package/dist/{op-factory-call-zo3HqJiO.mjs → op-factory-call-DZWTTjKM.mjs} +3 -3
  20. package/dist/{op-factory-call-zo3HqJiO.mjs.map → op-factory-call-DZWTTjKM.mjs.map} +1 -1
  21. package/dist/op-factory-call.mjs +1 -1
  22. package/dist/pack.mjs +1 -1
  23. package/dist/{planner-r4iLpxD7.mjs → planner-DWQYPxP8.mjs} +8 -8
  24. package/dist/{planner-r4iLpxD7.mjs.map → planner-DWQYPxP8.mjs.map} +1 -1
  25. package/dist/{planner-produced-postgres-migration-kVlK1Dts.mjs → planner-produced-postgres-migration-Ch1L8RiV.mjs} +2 -2
  26. package/dist/{planner-produced-postgres-migration-kVlK1Dts.mjs.map → planner-produced-postgres-migration-Ch1L8RiV.mjs.map} +1 -1
  27. package/dist/planner-produced-postgres-migration.mjs +1 -1
  28. package/dist/{planner-sql-checks-q58sWl7M.mjs → planner-sql-checks-D8Q5ck4o.mjs} +2 -2
  29. package/dist/{planner-sql-checks-q58sWl7M.mjs.map → planner-sql-checks-D8Q5ck4o.mjs.map} +1 -1
  30. package/dist/planner-sql-checks.mjs +1 -1
  31. package/dist/planner.d.mts +1 -1
  32. package/dist/planner.mjs +2 -2
  33. package/dist/{postgres-contract-view-C5RSIHFm.mjs → postgres-contract-view-C-By7rOB.mjs} +3 -3
  34. package/dist/postgres-contract-view-C-By7rOB.mjs.map +1 -0
  35. package/dist/{postgres-database-schema-node-C9bTuMrd.d.mts → postgres-database-schema-node-UpzA0Ug5.d.mts} +15 -2
  36. package/dist/{postgres-database-schema-node-C9bTuMrd.d.mts.map → postgres-database-schema-node-UpzA0Ug5.d.mts.map} +1 -1
  37. package/dist/{postgres-migration-CiA7wpQD.mjs → postgres-migration-D3XACWKM.mjs} +3 -3
  38. package/dist/{postgres-migration-CiA7wpQD.mjs.map → postgres-migration-D3XACWKM.mjs.map} +1 -1
  39. package/dist/postgres-schema-9vFZLwGo.d.mts.map +1 -1
  40. package/dist/{postgres-schema-CsOBpCwV.mjs → postgres-schema-DcG72fcT.mjs} +3 -12
  41. package/dist/postgres-schema-DcG72fcT.mjs.map +1 -0
  42. package/dist/{postgres-table-schema-node-BgaSrxYN.mjs → postgres-table-schema-node-BZWWEo7B.mjs} +12 -1
  43. package/dist/postgres-table-schema-node-BZWWEo7B.mjs.map +1 -0
  44. package/dist/{resolve-ddl-schema-gmgUaHK3.mjs → resolve-ddl-schema-BOtCoeKV.mjs} +2 -2
  45. package/dist/{resolve-ddl-schema-gmgUaHK3.mjs.map → resolve-ddl-schema-BOtCoeKV.mjs.map} +1 -1
  46. package/dist/runtime.mjs +1 -1
  47. package/dist/schema-ir-annotations.mjs +1 -1
  48. package/dist/types.d.mts +2 -2
  49. package/dist/types.mjs +2 -2
  50. package/package.json +20 -20
  51. package/src/core/authoring.ts +29 -3
  52. package/src/core/migrations/diff-database-schema.ts +1 -0
  53. package/src/core/postgres-contract-serializer.ts +2 -3
  54. package/src/core/postgres-schema.ts +0 -18
  55. package/src/core/psl-infer/infer-psl-contract.ts +288 -31
  56. package/src/core/psl-infer/postgres-type-map.ts +0 -29
  57. package/src/core/schema-ir/postgres-namespace-schema-node.ts +19 -0
  58. package/src/exports/types.ts +1 -0
  59. package/dist/authoring-ohGMgi8g.mjs.map +0 -1
  60. package/dist/diff-database-schema-BivMht-X.mjs.map +0 -1
  61. package/dist/postgres-contract-view-C5RSIHFm.mjs.map +0 -1
  62. package/dist/postgres-schema-CsOBpCwV.mjs.map +0 -1
  63. package/dist/postgres-table-schema-node-BgaSrxYN.mjs.map +0 -1
@@ -2,6 +2,7 @@ import type { ColumnDefault } from '@prisma-next/contract/types';
2
2
  import type { SqlDescribedContractSpace } from '@prisma-next/family-sql/control';
3
3
  import type {
4
4
  DefaultMappingOptions,
5
+ EnumInfo,
5
6
  PslNativeTypeAttribute,
6
7
  PslPrinterOptions,
7
8
  PslTypeMap,
@@ -13,21 +14,30 @@ import {
13
14
  inferRelations,
14
15
  mapDefault,
15
16
  parseRawDefault,
17
+ toEnumMemberName,
18
+ toEnumName,
16
19
  toFieldName,
17
20
  toModelName,
18
21
  toNamedTypeName,
19
22
  } from '@prisma-next/family-sql/psl-infer';
20
- import { coordinateKey, elementCoordinates } from '@prisma-next/framework-components/ir';
23
+ import {
24
+ coordinateKey,
25
+ elementCoordinates,
26
+ isPlainRecord,
27
+ } from '@prisma-next/framework-components/ir';
21
28
  import type {
22
29
  PslAttribute,
23
30
  PslAttributeArgument,
24
31
  PslDocumentAst,
32
+ PslExtensionBlock,
33
+ PslExtensionBlockParamValue,
25
34
  PslField,
26
35
  PslFieldAttribute,
27
36
  PslModel,
28
37
  PslModelAttribute,
29
38
  PslNamedTypeDeclaration,
30
39
  PslSpan,
40
+ PslTypeConstructorCall,
31
41
  PslTypesBlock,
32
42
  } from '@prisma-next/framework-components/psl-ast';
33
43
  import {
@@ -40,6 +50,7 @@ import type { SqlColumnIR, SqlForeignKeyIR } from '@prisma-next/sql-schema-ir/ty
40
50
  import { SqlSchemaIR, SqlTableIR } from '@prisma-next/sql-schema-ir/types';
41
51
  import { blindCast } from '@prisma-next/utils/casts';
42
52
  import { ifDefined } from '@prisma-next/utils/defined';
53
+ import { PostgresNativeEnum } from '../postgres-native-enum';
43
54
  import type { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';
44
55
  import { createPostgresDefaultMapping } from './postgres-default-mapping';
45
56
  import { createPostgresTypeMap } from './postgres-type-map';
@@ -287,20 +298,52 @@ export function inferPostgresPslContract(
287
298
  ): PslDocumentAst {
288
299
  const namespaces = Object.values(tree.namespaces);
289
300
  const owners = describedContractOwners(describedContracts ?? []);
290
-
291
- // Native Postgres enums (CREATE TYPE … AS ENUM) are not adoptable by
292
- // `contract infer`; throw an actionable diagnostic naming the type(s). Enum
293
- // names live on each namespace node's `nativeEnumTypeNames`.
294
- const enumTypeNames = [...new Set(namespaces.flatMap((ns) => ns.nativeEnumTypeNames))];
295
- if (enumTypeNames.length > 0) {
296
- const names = enumTypeNames.join(', ');
297
- throw new Error(
298
- `contract infer: the database contains native Postgres enum type(s): ${names}. ` +
299
- 'Native Postgres enums (CREATE TYPE AS ENUM) are not adoptable by contract infer. ' +
300
- 'Drop the native type and replace each column with a text column carrying a CHECK constraint, ' +
301
- `then re-run contract infer. The domain enum (enum Name { @@type("pg/text@1") … }) authoring ` +
302
- 'surface generates the required check automatically.',
303
- );
301
+ const enumOwners = describedNativeEnumOwnersByTypeName(describedContracts ?? []);
302
+
303
+ // Native enum adoption: each namespace's introspected `{ typeName, values }`
304
+ // entries become `native_enum` blocks + `pg.enum(<Name>)` columns, minus the
305
+ // types a described pack contract already declares (matched by TYPE NAME —
306
+ // see describedNativeEnumOwnersByTypeName). Transitional grade gap: an
307
+ // inferred block carries no explicit `control` and inherits the contract's
308
+ // `defaultControl`; under `defaultControl: 'managed'` the planner does not
309
+ // yet enforce the native enum lifecycle (CREATE TYPE / DROP TYPE / ADD
310
+ // VALUE) that lands with Phase 2 of projects/native-postgres-enums/spec.md,
311
+ // making the grade true retroactively with no contract change.
312
+ const enumDefinitions = new Map<string, readonly string[]>();
313
+ const packOwnedEnumTypesByNamespace = new Map<string, Map<string, string>>();
314
+ const enumNamespaceNames = new Set<string>();
315
+ for (const namespace of namespaces) {
316
+ const definitionsForNamespace = new Set(namespace.nativeEnums.map((e) => e.typeName));
317
+ for (const typeName of namespace.nativeEnumTypeNames) {
318
+ if (!definitionsForNamespace.has(typeName)) {
319
+ throw new Error(
320
+ `contract infer: introspection reported native enum type "${typeName}" in schema ` +
321
+ `"${namespace.schemaName}" without member values — the introspected tree's ` +
322
+ '`nativeEnumTypeNames` and `nativeEnums` are out of sync (internal invariant).',
323
+ );
324
+ }
325
+ }
326
+ for (const { typeName, values } of namespace.nativeEnums) {
327
+ const owner = enumOwners.get(
328
+ coordinateKey({
329
+ namespaceId: namespace.schemaName,
330
+ entityKind: 'native_enum',
331
+ entityName: typeName,
332
+ }),
333
+ );
334
+ if (owner !== undefined) {
335
+ const owned = packOwnedEnumTypesByNamespace.get(namespace.schemaName) ?? new Map();
336
+ // Columns reference the type either bare or schema-qualified —
337
+ // `format_type` qualifies a type outside the connection's
338
+ // search_path — so both spellings are owned.
339
+ owned.set(typeName, owner.spaceId);
340
+ owned.set(`${namespace.schemaName}.${typeName}`, owner.spaceId);
341
+ packOwnedEnumTypesByNamespace.set(namespace.schemaName, owned);
342
+ continue;
343
+ }
344
+ enumDefinitions.set(typeName, values);
345
+ enumNamespaceNames.add(namespace.schemaName);
346
+ }
304
347
  }
305
348
 
306
349
  // Stopgap (TML-2958): flatten the schema-IR *tree* into the single `{ tables }`
@@ -311,7 +354,9 @@ export function inferPostgresPslContract(
311
354
  // single introspected namespace, and a same-named table in two schemas has no
312
355
  // unambiguous single-bucket model, so we throw rather than silently drop one.
313
356
  const tables: Record<string, SqlTableIR> = {};
357
+ const tableNamespaceNames = new Set<string>();
314
358
  for (const namespace of namespaces) {
359
+ const ownedEnumTypes = packOwnedEnumTypesByNamespace.get(namespace.schemaName);
315
360
  for (const [tableName, table] of Object.entries(namespace.tables)) {
316
361
  if (
317
362
  owners.has(
@@ -331,9 +376,45 @@ export function inferPostgresPslContract(
331
376
  'output is a later slice).',
332
377
  );
333
378
  }
379
+ if (ownedEnumTypes !== undefined) {
380
+ for (const column of Object.values(table.columns)) {
381
+ const owningSpaceId = ownedEnumTypes.get(column.nativeType);
382
+ if (owningSpaceId !== undefined) {
383
+ throw new Error(
384
+ `contract infer: column "${tableName}"."${column.name}" is typed by native enum ` +
385
+ `type "${column.nativeType}", which extension pack space "${owningSpaceId}" ` +
386
+ 'already describes. A cross-space enum-typed column has no authorable PSL form ' +
387
+ "yet; describe the table in that pack's contract or retype the column before " +
388
+ 're-running contract infer.',
389
+ );
390
+ }
391
+ }
392
+ }
334
393
  tables[tableName] = new SqlTableIR(table);
394
+ tableNamespaceNames.add(namespace.schemaName);
395
+ }
396
+ }
397
+
398
+ // Namespace wrap (pinned during shaping): a `native_enum` block only lowers
399
+ // inside an explicit `namespace { … }` block — the interpreter skips
400
+ // extension entities in the unspecified top-level bucket — so enum-bearing
401
+ // output wraps everything in the introspected schema's name. Enum-free
402
+ // output stays flat and byte-identical to the prior inference.
403
+ let wrapNamespaceName: string | undefined;
404
+ if (enumDefinitions.size > 0) {
405
+ const contentNamespaces = new Set([...enumNamespaceNames, ...tableNamespaceNames]);
406
+ if (contentNamespaces.size > 1) {
407
+ throw new Error(
408
+ 'contract infer: native enum adoption with content across multiple schemas is not yet ' +
409
+ 'supported (single-namespace PSL inference emits one `namespace { … }` block; ' +
410
+ `multi-namespace output is a later slice). Schemas: ${[...contentNamespaces]
411
+ .sort()
412
+ .join(', ')}.`,
413
+ );
335
414
  }
415
+ wrapNamespaceName = [...contentNamespaces][0];
336
416
  }
417
+
337
418
  const {
338
419
  tables: resolvedTables,
339
420
  extraRelationsByTable,
@@ -341,25 +422,87 @@ export function inferPostgresPslContract(
341
422
  } = resolveForeignKeys(tables, owners);
342
423
  const schemaIR = new SqlSchemaIR({ tables: resolvedTables });
343
424
 
425
+ // Live introspection reports an enum column's nativeType schema-qualified
426
+ // whenever the type sits outside the connection's search_path (`format_type`
427
+ // semantics; e.g. `auth.aal_level`), while `pg_type.typname` — the
428
+ // definitions key — is always bare. Register the qualified spelling as an
429
+ // alias so those columns resolve; block emission stays keyed on the bare
430
+ // name (one block per type).
431
+ const enumTypeNames = new Set(enumDefinitions.keys());
432
+ if (wrapNamespaceName !== undefined) {
433
+ for (const typeName of enumDefinitions.keys()) {
434
+ enumTypeNames.add(`${wrapNamespaceName}.${typeName}`);
435
+ }
436
+ }
437
+ const enumInfo: EnumInfo = {
438
+ typeNames: enumTypeNames,
439
+ definitions: enumDefinitions,
440
+ };
344
441
  const options: PslPrinterOptions = {
345
- typeMap: createPostgresTypeMap(new Set()),
442
+ typeMap: createPostgresTypeMap(enumInfo.typeNames),
346
443
  defaultMapping: createPostgresDefaultMapping(),
347
444
  parseRawDefault,
445
+ ...(enumDefinitions.size > 0 ? { enumInfo } : {}),
348
446
  };
349
447
 
350
- return buildPslDocumentAst(schemaIR, options, {
351
- extraRelationsByTable,
352
- crossSpaceFieldNamesByTable,
353
- });
448
+ return buildPslDocumentAst(
449
+ schemaIR,
450
+ options,
451
+ {
452
+ extraRelationsByTable,
453
+ crossSpaceFieldNamesByTable,
454
+ },
455
+ wrapNamespaceName,
456
+ );
354
457
  }
355
458
 
356
- function buildPslDocumentAst(
459
+ /**
460
+ * Native-enum ownership index for pack subtraction, keyed by TYPE NAME
461
+ * coordinate. A pack contract keys `entries.native_enum` by HANDLE name
462
+ * (`AalLevel`) while introspection sees the Postgres type name (`aal_level`);
463
+ * the entity's `typeName` field carries the mapping, so this walk indexes by
464
+ * it rather than reusing {@link describedContractOwners}' entries-key
465
+ * coordinates.
466
+ *
467
+ * Reads `entries.native_enum` directly: the kind map is carried
468
+ * non-enumerable on `PostgresSchema.entries`, so the generic
469
+ * `elementCoordinates` walk never yields it. Serialized pack contracts do
470
+ * not carry `native_enum` entries at all (`PostgresContractSerializer`
471
+ * strips them; only the derived `valueSet` survives), so this subtraction
472
+ * currently matches in-memory described contracts only.
473
+ */
474
+ function describedNativeEnumOwnersByTypeName(
475
+ describedContracts: readonly SqlDescribedContractSpace[],
476
+ ): ReadonlyMap<string, SqlDescribedContractSpace> {
477
+ const owners = new Map<string, SqlDescribedContractSpace>();
478
+ for (const entry of describedContracts) {
479
+ for (const [namespaceId, ns] of Object.entries(entry.contract.storage.namespaces)) {
480
+ const kindMap = ns.entries['native_enum'];
481
+ if (!isPlainRecord(kindMap)) continue;
482
+ for (const entity of Object.values(kindMap)) {
483
+ if (!PostgresNativeEnum.is(entity)) continue;
484
+ owners.set(
485
+ coordinateKey({
486
+ namespaceId,
487
+ entityKind: 'native_enum',
488
+ entityName: entity.typeName,
489
+ }),
490
+ entry,
491
+ );
492
+ }
493
+ }
494
+ }
495
+ return owners;
496
+ }
497
+
498
+ export function buildPslDocumentAst(
357
499
  schemaIR: SqlSchemaIR,
358
500
  options: PslPrinterOptions,
359
501
  foreignKeyExtras: Pick<
360
502
  ForeignKeyResolution,
361
503
  'extraRelationsByTable' | 'crossSpaceFieldNamesByTable'
362
504
  >,
505
+ namespaceName?: string,
363
506
  ): PslDocumentAst {
364
507
  const { typeMap, defaultMapping, parseRawDefault: rawDefaultParser } = options;
365
508
  const { extraRelationsByTable, crossSpaceFieldNamesByTable } = foreignKeyExtras;
@@ -374,7 +517,23 @@ function buildPslDocumentAst(
374
517
  const modelNameMap = new Map(
375
518
  [...modelNames].map(([tableName, result]) => [tableName, result.name]),
376
519
  );
377
- const reservedNamedTypeNames = createReservedNamedTypeNames(modelNames);
520
+
521
+ const { enumNameMap: bareEnumNameMap, enumBlocks } = buildNativeEnumBlocks(
522
+ options.enumInfo?.definitions ?? new Map(),
523
+ modelNames,
524
+ );
525
+
526
+ // Columns reference an enum type bare or schema-qualified (`format_type`
527
+ // qualifies types outside the search_path); alias the qualified spelling
528
+ // onto the same PSL name. Blocks stay keyed on the bare name.
529
+ const enumNameMap = new Map(bareEnumNameMap);
530
+ if (namespaceName !== undefined) {
531
+ for (const [typeName, pslName] of bareEnumNameMap) {
532
+ enumNameMap.set(`${namespaceName}.${typeName}`, pslName);
533
+ }
534
+ }
535
+
536
+ const reservedNamedTypeNames = createReservedNamedTypeNames(modelNames, enumNameMap);
378
537
 
379
538
  // Cross-space entries are seeded first so a real local table of the same
380
539
  // bare name (an existing single-namespace-flat-bucket limitation, not new
@@ -385,7 +544,7 @@ function buildPslDocumentAst(
385
544
  ...buildFieldNamesByTable(schemaIR.tables),
386
545
  ]);
387
546
  const { relationsByTable } = inferRelations(schemaIR.tables, modelNameMap);
388
- const namedTypes = seedNamedTypeRegistry(schemaIR, typeMap, new Map(), reservedNamedTypeNames);
547
+ const namedTypes = seedNamedTypeRegistry(schemaIR, typeMap, enumNameMap, reservedNamedTypeNames);
389
548
 
390
549
  const models: PslModel[] = [];
391
550
  for (const table of Object.values(schemaIR.tables)) {
@@ -393,7 +552,7 @@ function buildPslDocumentAst(
393
552
  buildModel(
394
553
  table,
395
554
  typeMap,
396
- new Map(),
555
+ enumNameMap,
397
556
  fieldNamesByTable,
398
557
  namedTypes,
399
558
  defaultMapping,
@@ -421,19 +580,20 @@ function buildPslDocumentAst(
421
580
  : undefined;
422
581
 
423
582
  // Inferred PSL nodes will eventually be routed into per-namespace buckets
424
- // matching the source storage; for now we synthesise a single
425
- // `__unspecified__` bucket so round-tripping the AST through the framework
426
- // printer (which emits the synthesised bucket at top level with no
427
- // `namespace { … }` wrapper) preserves the existing introspection output
428
- // verbatim.
583
+ // matching the source storage; for now everything lands in a single bucket.
584
+ // Without a `namespaceName` that bucket is the synthesised `__unspecified__`
585
+ // one, which the framework printer emits at top level with no
586
+ // `namespace { … }` wrapper preserving the existing flat introspection
587
+ // output verbatim. With a `namespaceName` (enum-bearing output) the bucket
588
+ // is a real named namespace, printed as an explicit block.
429
589
  const ast: PslDocumentAst = {
430
590
  kind: 'document',
431
591
  sourceId: '<sql-schema-ir>',
432
592
  namespaces: [
433
593
  makePslNamespace({
434
594
  kind: 'namespace',
435
- name: UNSPECIFIED_PSL_NAMESPACE_ID,
436
- entries: makePslNamespaceEntries(sortedModels, [], []),
595
+ name: namespaceName ?? UNSPECIFIED_PSL_NAMESPACE_ID,
596
+ entries: makePslNamespaceEntries(sortedModels, [], enumBlocks),
437
597
  span: SYNTHETIC_SPAN,
438
598
  }),
439
599
  ],
@@ -444,6 +604,87 @@ function buildPslDocumentAst(
444
604
  return ast;
445
605
  }
446
606
 
607
+ type NativeEnumBlockResult = {
608
+ /** Native enum type name → PSL block name, for `pg.enum(<Name>)` field refs. */
609
+ readonly enumNameMap: ReadonlyMap<string, string>;
610
+ readonly enumBlocks: readonly PslExtensionBlock[];
611
+ };
612
+
613
+ /**
614
+ * Builds one `native_enum` extension-block AST node per introspected enum
615
+ * definition. Block names go through the shared top-level transform
616
+ * (`toEnumName`, intra-enum collisions throw like model collisions) and are
617
+ * then reserved against the model names — an enum whose PSL name a model
618
+ * already claims gets a numeric suffix, with `@@map` carrying the real type
619
+ * name. Members print as explicit `member = "value"` pairs: the member name
620
+ * is the sanitized value (deduplicated within the block), the JSON-encoded
621
+ * value carries the truth verbatim.
622
+ */
623
+ function buildNativeEnumBlocks(
624
+ definitions: ReadonlyMap<string, readonly string[]>,
625
+ modelNames: ReadonlyMap<string, TopLevelNameResult>,
626
+ ): NativeEnumBlockResult {
627
+ const enumNames = buildTopLevelNameMap(
628
+ [...definitions.keys()].sort(),
629
+ toEnumName,
630
+ 'enum',
631
+ 'enum type',
632
+ );
633
+
634
+ const usedTopLevelNames = new Set<string>(PSL_SCALAR_TYPE_NAMES);
635
+ for (const result of modelNames.values()) {
636
+ usedTopLevelNames.add(result.name);
637
+ }
638
+
639
+ const enumNameMap = new Map<string, string>();
640
+ const enumBlocks: PslExtensionBlock[] = [];
641
+ for (const [typeName, result] of enumNames) {
642
+ const name = createUniqueFieldName(result.name, usedTopLevelNames);
643
+ usedTopLevelNames.add(name);
644
+ enumNameMap.set(typeName, name);
645
+ enumBlocks.push(buildNativeEnumBlock(name, typeName, definitions.get(typeName) ?? []));
646
+ }
647
+
648
+ return { enumNameMap, enumBlocks };
649
+ }
650
+
651
+ function buildNativeEnumBlock(
652
+ name: string,
653
+ typeName: string,
654
+ values: readonly string[],
655
+ ): PslExtensionBlock {
656
+ const usedMemberNames = new Set<string>();
657
+ const parameters: Record<string, PslExtensionBlockParamValue> = {};
658
+ for (const value of values) {
659
+ const memberName = createUniqueFieldName(toEnumMemberName(value), usedMemberNames);
660
+ usedMemberNames.add(memberName);
661
+ parameters[memberName] = { kind: 'value', raw: JSON.stringify(value), span: SYNTHETIC_SPAN };
662
+ }
663
+
664
+ return {
665
+ kind: 'native_enum',
666
+ name,
667
+ parameters,
668
+ blockAttributes:
669
+ name === typeName
670
+ ? []
671
+ : [
672
+ {
673
+ name: 'map',
674
+ args: [
675
+ {
676
+ kind: 'positional',
677
+ value: `"${escapePslString(typeName)}"`,
678
+ span: SYNTHETIC_SPAN,
679
+ },
680
+ ],
681
+ span: SYNTHETIC_SPAN,
682
+ },
683
+ ],
684
+ span: SYNTHETIC_SPAN,
685
+ };
686
+ }
687
+
447
688
  function buildModel(
448
689
  table: SqlTableIR,
449
690
  typeMap: PslTypeMap,
@@ -582,10 +823,21 @@ function buildScalarField(
582
823
  };
583
824
  }
584
825
 
826
+ // An enum-typed column emits the `pg.enum(<Name>)` type-constructor call —
827
+ // the Phase-1 authoring form a `native_enum` ref field takes — not a bare
828
+ // name substitution. The printer renders `typeConstructor` when present and
829
+ // composes `?`/`[]` exactly like any other field type.
585
830
  let typeName = resolution.pslType;
831
+ let typeConstructor: PslTypeConstructorCall | undefined;
586
832
  const enumPslName = enumNameMap.get(column.nativeType);
587
833
  if (enumPslName) {
588
834
  typeName = enumPslName;
835
+ typeConstructor = {
836
+ kind: 'typeConstructor',
837
+ path: ['pg', 'enum'],
838
+ args: [positionalArg(enumPslName)],
839
+ span: SYNTHETIC_SPAN,
840
+ };
589
841
  }
590
842
  if (resolution.nativeTypeAttribute && !enumPslName) {
591
843
  typeName = resolveNamedTypeName(namedTypes, resolution);
@@ -624,6 +876,7 @@ function buildScalarField(
624
876
  kind: 'field',
625
877
  name: fieldName,
626
878
  typeName,
879
+ ...ifDefined('typeConstructor', typeConstructor),
627
880
  optional: column.nullable,
628
881
  list: column.many === true,
629
882
  attributes,
@@ -894,12 +1147,16 @@ function buildTopLevelNameMap(
894
1147
 
895
1148
  function createReservedNamedTypeNames(
896
1149
  modelNames: ReadonlyMap<string, TopLevelNameResult>,
1150
+ enumNameMap: ReadonlyMap<string, string>,
897
1151
  ): Set<string> {
898
1152
  const reservedNames = new Set<string>(PSL_SCALAR_TYPE_NAMES);
899
1153
 
900
1154
  for (const result of modelNames.values()) {
901
1155
  reservedNames.add(result.name);
902
1156
  }
1157
+ for (const enumPslName of enumNameMap.values()) {
1158
+ reservedNames.add(enumPslName);
1159
+ }
903
1160
 
904
1161
  return reservedNames;
905
1162
  }
@@ -1,5 +1,4 @@
1
1
  import type {
2
- EnumInfo,
3
2
  PslNativeTypeAttribute,
4
3
  PslTypeMap,
5
4
  PslTypeResolution,
@@ -127,31 +126,3 @@ export function createPostgresTypeMap(enumTypeNames?: ReadonlySet<string>): PslT
127
126
  },
128
127
  };
129
128
  }
130
-
131
- export function extractEnumInfo(annotations?: Record<string, unknown>): EnumInfo {
132
- const pgAnnotations = annotations?.['pg'] as Record<string, unknown> | undefined;
133
- const nativeEnumTypeNames = pgAnnotations?.['nativeEnumTypeNames'];
134
-
135
- const typeNames = new Set<string>();
136
- const definitions = new Map<string, readonly string[]>();
137
-
138
- if (Array.isArray(nativeEnumTypeNames)) {
139
- for (const name of nativeEnumTypeNames) {
140
- if (typeof name === 'string') {
141
- typeNames.add(name);
142
- }
143
- }
144
- }
145
-
146
- return { typeNames, definitions };
147
- }
148
-
149
- export function extractEnumTypeNames(annotations?: Record<string, unknown>): ReadonlySet<string> {
150
- return extractEnumInfo(annotations).typeNames;
151
- }
152
-
153
- export function extractEnumDefinitions(
154
- annotations?: Record<string, unknown>,
155
- ): ReadonlyMap<string, readonly string[]> {
156
- return extractEnumInfo(annotations).definitions;
157
- }
@@ -4,10 +4,17 @@ import { assertNode, SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
4
4
  import type { PostgresTableSchemaNode } from './postgres-table-schema-node';
5
5
  import { PostgresSchemaNodeKind } from './schema-node-kinds';
6
6
 
7
+ /** One introspected native Postgres enum type, in `pg_enum.enumsortorder` (declaration) order. */
8
+ export interface PostgresNativeEnumIntrospection {
9
+ readonly typeName: string;
10
+ readonly values: readonly string[];
11
+ }
12
+
7
13
  export interface PostgresNamespaceSchemaNodeInput {
8
14
  readonly schemaName: string;
9
15
  readonly tables: Readonly<Record<string, PostgresTableSchemaNode>>;
10
16
  readonly nativeEnumTypeNames: readonly string[];
17
+ readonly nativeEnums?: readonly PostgresNativeEnumIntrospection[];
11
18
  }
12
19
 
13
20
  /**
@@ -22,6 +29,12 @@ export interface PostgresNamespaceSchemaNodeInput {
22
29
  * equal iff their ids (schema names) match. `children()` returns the table
23
30
  * nodes. Per-schema metadata is carried on the typed `nativeEnumTypeNames`
24
31
  * field, not an annotations bag.
32
+ *
33
+ * `nativeEnums` carries the same enum types with their ordered member
34
+ * values (`{ typeName, values }`), for consumers that need the values
35
+ * (PSL inference, the printer). `nativeEnumTypeNames` stays a plain name
36
+ * list read independently by existing consumers (codec `planTypeOperations`
37
+ * hooks, the infer throw) so none of them need the values to keep working.
25
38
  */
26
39
  export class PostgresNamespaceSchemaNode extends SqlSchemaIRNode implements DiffableNode {
27
40
  override readonly nodeKind = PostgresSchemaNodeKind.namespace;
@@ -29,12 +42,18 @@ export class PostgresNamespaceSchemaNode extends SqlSchemaIRNode implements Diff
29
42
  readonly schemaName: string;
30
43
  readonly tables: Readonly<Record<string, PostgresTableSchemaNode>>;
31
44
  readonly nativeEnumTypeNames: readonly string[];
45
+ readonly nativeEnums: readonly PostgresNativeEnumIntrospection[];
32
46
 
33
47
  constructor(input: PostgresNamespaceSchemaNodeInput) {
34
48
  super();
35
49
  this.schemaName = input.schemaName;
36
50
  this.tables = Object.freeze({ ...input.tables });
37
51
  this.nativeEnumTypeNames = Object.freeze([...input.nativeEnumTypeNames]);
52
+ this.nativeEnums = Object.freeze(
53
+ (input.nativeEnums ?? []).map((entry) =>
54
+ Object.freeze({ typeName: entry.typeName, values: Object.freeze([...entry.values]) }),
55
+ ),
56
+ );
38
57
  freezeNode(this);
39
58
  }
40
59
 
@@ -19,6 +19,7 @@ export {
19
19
  export {
20
20
  PostgresNamespaceSchemaNode,
21
21
  type PostgresNamespaceSchemaNodeInput,
22
+ type PostgresNativeEnumIntrospection,
22
23
  } from '../core/schema-ir/postgres-namespace-schema-node';
23
24
  export {
24
25
  PostgresPolicySchemaNode,
@@ -1 +0,0 @@
1
- {"version":3,"file":"authoring-ohGMgi8g.mjs","names":[],"sources":["../src/core/authoring.ts"],"sourcesContent":["import { temporalAuthoringPresets } from '@prisma-next/family-sql/control';\nimport type {\n AuthoringEntityContext,\n AuthoringEntityTypeFactoryOutput,\n AuthoringEntityTypeNamespace,\n AuthoringFieldNamespace,\n AuthoringPslBlockDescriptorNamespace,\n AuthoringTypeNamespace,\n PslExtensionBlock,\n} from '@prisma-next/framework-components/authoring';\nimport type { SqlValueSetDerivingEntityTypeOutput } from '@prisma-next/sql-contract/value-set-derivation-hook';\nimport { PG_ENUM_CODEC_ID } from './codec-ids';\nimport { PostgresNativeEnum } from './postgres-native-enum';\nimport { PostgresRlsPolicy } from './postgres-rls-policy';\nimport { PostgresRole, type PostgresRoleInput } from './postgres-role';\nimport {\n PostgresNativeEnumSchema,\n PostgresRlsPolicySchema,\n PostgresRoleSchema,\n} from './postgres-validators';\nimport { computeContentHash, normalizePredicate } from './rls/canonicalize';\n\n/**\n * `pg.enum(<ref>)` registers as an ordinary type constructor whose sole\n * positional argument names a `native_enum` entity instead of carrying a\n * literal value. The interpreter resolves the ref to the `native_enum`\n * entity generically (driven by `entityRefArg`); the `pg/enum@1` codec\n * descriptor's `columnFromEntity` hook (see `codecs.ts`) converts that\n * entity into the column's `typeParams` and native type.\n */\nexport const postgresAuthoringTypes = {\n pg: {\n enum: {\n kind: 'typeConstructor',\n entityRefArg: { index: 0, entityKind: 'native_enum' },\n output: {\n codecId: PG_ENUM_CODEC_ID,\n },\n },\n },\n} as const satisfies AuthoringTypeNamespace;\n\nexport interface RlsPolicyExtensionBlock extends PslExtensionBlock {\n readonly namespaceId: string;\n}\n\nfunction readRefParam(block: PslExtensionBlock, key: string): string | undefined {\n const param = block.parameters[key];\n return param?.kind === 'ref' ? param.identifier : undefined;\n}\n\nfunction readValueParam(block: PslExtensionBlock, key: string): string | undefined {\n const param = block.parameters[key];\n return param?.kind === 'value' ? param.raw : undefined;\n}\n\nfunction readListRefParams(block: PslExtensionBlock, key: string): string[] {\n const param = block.parameters[key];\n if (param?.kind !== 'list') return [];\n return param.items.flatMap((item) => (item.kind === 'ref' ? [item.identifier] : []));\n}\n\nfunction unwrapQuotedString(raw: string): string {\n if (raw.startsWith('\"') && raw.endsWith('\"') && raw.length >= 2) {\n return raw.slice(1, -1).replace(/\\\\\"/g, '\"');\n }\n return raw;\n}\n\nfunction lowerRlsPolicyFromBlock(\n block: RlsPolicyExtensionBlock,\n _ctx: AuthoringEntityContext,\n): PostgresRlsPolicy {\n const prefix = block.name;\n const targetModelName = readRefParam(block, 'target') ?? '';\n const tableName = targetModelName.charAt(0).toLowerCase() + targetModelName.slice(1);\n const roles = [...readListRefParams(block, 'roles')].sort();\n const using = unwrapQuotedString(readValueParam(block, 'using') ?? '');\n\n const wireHash = computeContentHash({\n using: normalizePredicate(using),\n roles,\n operation: 'select',\n permissive: true,\n });\n const wireName = `${prefix}_${wireHash}`;\n\n return new PostgresRlsPolicy({\n name: wireName,\n prefix,\n tableName,\n namespaceId: block.namespaceId,\n operation: 'select',\n roles,\n using,\n permissive: true,\n });\n}\n\n/**\n * Lowers a `native_enum { memberName = \"value\" … @@map(\"type_name\") }` block\n * into a {@link PostgresNativeEnum}. Members must be authored as explicit\n * `key = \"value\"` pairs — a bare (value-less) member is a diagnostic, not\n * accepted (authoring-design.md §2.1). The parsed `memberName` is only used\n * to duplicate-check and report diagnostics; the lowered entity carries just\n * the member values (a native enum is value-only — the member \"name\" isn't\n * a separate authoring concept from the value). `typeName` comes from\n * `@@map` or defaults to the block name verbatim.\n */\nfunction lowerNativeEnumFromBlock(\n block: PslExtensionBlock,\n ctx: AuthoringEntityContext,\n): PostgresNativeEnum | undefined {\n const sourceId = ctx.sourceId ?? 'unknown';\n const diagnostics = ctx.diagnostics;\n\n const mapAttr = block.blockAttributes.find((a) => a.name === 'map');\n let typeName = block.name;\n if (mapAttr) {\n const rawArg = mapAttr.args[0]?.value;\n const mapped = rawArg !== undefined ? unwrapQuotedString(rawArg) : undefined;\n if (mapped === undefined) {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_INVALID_MAP',\n message: `native_enum \"${block.name}\" @@map attribute must have a quoted type-name argument`,\n sourceId,\n span: mapAttr.span,\n });\n return undefined;\n }\n typeName = mapped;\n }\n\n let memberError = false;\n const seenValues = new Set<string>();\n const members: string[] = [];\n for (const [memberName, paramValue] of Object.entries(block.parameters)) {\n if (paramValue.kind === 'bare') {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_BARE_MEMBER',\n message: `native_enum \"${block.name}\" member \"${memberName}\" has no value; members must be authored as \"${memberName} = \\\\\"value\\\\\"\"`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n if (paramValue.kind !== 'value') continue;\n\n let jsonValue: unknown;\n try {\n jsonValue = JSON.parse(paramValue.raw);\n } catch {\n diagnostics?.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `native_enum \"${block.name}\" member \"${memberName}\" value \"${paramValue.raw}\" is not valid JSON`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n if (typeof jsonValue !== 'string') {\n diagnostics?.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `native_enum \"${block.name}\" member \"${memberName}\" value must be a string`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n if (seenValues.has(jsonValue)) {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_DUPLICATE_MEMBER_VALUE',\n message: `native_enum \"${block.name}\": duplicate member value \"${jsonValue}\"`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n seenValues.add(jsonValue);\n members.push(jsonValue);\n }\n\n if (memberError) return undefined;\n\n if (members.length === 0) {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_MISSING_MEMBERS',\n message: `native_enum \"${block.name}\" must have at least one member`,\n sourceId,\n span: block.span,\n });\n return undefined;\n }\n\n // `control` stays unset — the effective grade is resolved at read time via `effectiveControlPolicy`, like `StorageTable`/`StorageColumn`.\n return new PostgresNativeEnum({ typeName, members });\n}\n\n/**\n * `native_enum`'s entity-type factory output, checked separately from the assembled\n * `postgresAuthoringEntityTypes` map below: `deriveValueSet` is SQL-family surface\n * ({@link SqlValueSetDerivingEntityTypeOutput}), not part of the framework\n * `AuthoringEntityTypeFactoryOutput` shape, so folding it directly into the map's single\n * `satisfies AuthoringEntityTypeNamespace` check would trip an excess-property error. Checking it\n * here against the intersection of both shapes keeps it structurally valid against each without\n * widening the map's own check.\n */\nconst nativeEnumEntityTypeOutput = {\n factory: lowerNativeEnumFromBlock,\n deriveValueSet: (entity: PostgresNativeEnum) => ({\n kind: 'valueSet' as const,\n values: [...entity.members],\n }),\n} satisfies AuthoringEntityTypeFactoryOutput<PslExtensionBlock, PostgresNativeEnum | undefined> &\n SqlValueSetDerivingEntityTypeOutput;\n\nexport const postgresAuthoringEntityTypes = {\n role: {\n kind: 'entity',\n discriminator: 'role',\n validatorSchema: PostgresRoleSchema,\n output: {\n factory: (input: PostgresRoleInput): PostgresRole => new PostgresRole(input),\n },\n },\n policy: {\n kind: 'entity',\n discriminator: 'policy',\n validatorSchema: PostgresRlsPolicySchema,\n output: {\n factory: lowerRlsPolicyFromBlock,\n },\n },\n native_enum: {\n kind: 'entity',\n discriminator: 'native_enum',\n validatorSchema: PostgresNativeEnumSchema,\n output: nativeEnumEntityTypeOutput,\n },\n} as const satisfies AuthoringEntityTypeNamespace;\n\n/**\n * Field presets contributed by the Postgres target pack.\n *\n * These mirror the PSL scalar-to-codec mapping used by the Postgres adapter\n * (see `createPostgresPslScalarTypeDescriptors`), so that authoring a field\n * via the TS callback surface (e.g. `field.int()`) and via the PSL scalar\n * surface (e.g. `Int`) lowers to byte-identical contracts.\n *\n * The `uuidNative` / `id.uuidv4Native` / `id.uuidv7Native` presets use the\n * native Postgres `uuid` type (codecId `pg/uuid@1`). For cross-target\n * portability use `uuidString` / `id.uuidv4String` / `id.uuidv7String` from\n * the family pack instead.\n */\n/**\n * PSL block descriptor for `policy_select`.\n *\n * The parser learns the block shape from this descriptor; lowering from\n * `PslExtensionBlock` to `PostgresRlsPolicy` is wired in the PSL\n * interpreter (a later dispatch). The `discriminator` matches\n * `PostgresRlsPolicy.kind` so the parsed block node carries the same\n * discriminant as the IR class it will lower to.\n *\n * The `roles` list uses `scope:'cross-space'` because same-namespace\n * role ref resolution requires PSL namespace entries keyed by `refKind`\n * (i.e. `'role'`), which in turn requires the role block discriminator to\n * equal `'role'`. Aligning discriminator with refKind is tracked for\n * slice 4 (cross-space roles). Until then cross-space passes validation\n * unconditionally and the authored role names flow through unchanged.\n */\nexport const postgresAuthoringPslBlockDescriptors = {\n policy_select: {\n kind: 'pslBlock',\n keyword: 'policy_select',\n discriminator: 'policy',\n name: { required: true },\n parameters: {\n target: { kind: 'ref', refKind: 'model', scope: 'same-namespace', required: true },\n roles: {\n kind: 'list',\n of: { kind: 'ref', refKind: 'role', scope: 'cross-space' },\n },\n using: { kind: 'value', codecId: 'pg/text@1', required: true },\n },\n },\n /**\n * PSL block descriptor for `native_enum`.\n *\n * Reuses the existing variadic-block mechanism (the same shape the SQL\n * family's `enum` block ships): the body is an open `memberName = \"value\"`\n * list. `variadicParameters: true` opens the block to arbitrary keys\n * beyond the declared (empty) `parameters` set — the lowering factory\n * (`lowerNativeEnumFromBlock`) turns the variadic entries into ordered\n * members and rejects a bare (value-less) member.\n */\n native_enum: {\n kind: 'pslBlock',\n keyword: 'native_enum',\n discriminator: 'native_enum',\n name: { required: true },\n parameters: {},\n variadicParameters: true,\n },\n} as const satisfies AuthoringPslBlockDescriptorNamespace;\n\nexport const postgresAuthoringFieldPresets = {\n text: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/text@1',\n nativeType: 'text',\n },\n },\n int: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/int4@1',\n nativeType: 'int4',\n },\n },\n bigint: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/int8@1',\n nativeType: 'int8',\n },\n },\n float: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/float8@1',\n nativeType: 'float8',\n },\n },\n decimal: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/numeric@1',\n nativeType: 'numeric',\n },\n },\n boolean: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/bool@1',\n nativeType: 'bool',\n },\n },\n json: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/jsonb@1',\n nativeType: 'jsonb',\n },\n },\n bytes: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/bytea@1',\n nativeType: 'bytea',\n },\n },\n dateTime: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/timestamptz@1',\n nativeType: 'timestamptz',\n },\n },\n temporal: /* @__PURE__ */ temporalAuthoringPresets({\n codecId: 'pg/timestamptz@1',\n nativeType: 'timestamptz',\n }),\n uuidNative: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n },\n },\n id: {\n uuidv4Native: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n executionDefaults: {\n onCreate: {\n kind: 'generator',\n id: 'uuidv4',\n },\n },\n id: true,\n },\n },\n uuidv7Native: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n executionDefaults: {\n onCreate: {\n kind: 'generator',\n id: 'uuidv7',\n },\n },\n id: true,\n },\n },\n },\n} as const satisfies AuthoringFieldNamespace;\n"],"mappings":"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T,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,UAAU;EACR,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,UAA0B,yCAAyB;EACjD,SAAS;EACT,YAAY;CACd,CAAC;CACD,YAAY;EACV,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,IAAI;EACF,cAAc;GACZ,MAAM;GACN,QAAQ;IACN,SAAS;IACT,YAAY;IACZ,mBAAmB,EACjB,UAAU;KACR,MAAM;KACN,IAAI;IACN,EACF;IACA,IAAI;GACN;EACF;EACA,cAAc;GACZ,MAAM;GACN,QAAQ;IACN,SAAS;IACT,YAAY;IACZ,mBAAmB,EACjB,UAAU;KACR,MAAM;KACN,IAAI;IACN,EACF;IACA,IAAI;GACN;EACF;CACF;AACF"}