@prisma-next/sql-contract-ts 0.5.0-dev.9 → 0.5.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/README.md CHANGED
@@ -16,7 +16,7 @@ This package is part of the SQL family namespace (`packages/2-sql/2-authoring/co
16
16
 
17
17
  - the SQL contract DSL centered on `defineContract(...)`
18
18
  - the base structural helpers exported from `./contract-builder`: `field.column(...)`, `field.generated(...)`, `field.namedType(...)`, plus `model(...)` and `rel.*`
19
- - an optional callback overload that exposes pack-composed helper namespaces such as `field.id.uuidv7()`, `field.text()`, `field.createdAt()`, and `type.enum(...)`
19
+ - an optional callback overload that exposes pack-composed helper namespaces such as `field.id.uuidv7()`, `field.text()`, `field.temporal.createdAt()`, `field.temporal.updatedAt()`, and `type.enum(...)`
20
20
  - lowering from authored model definitions into the canonical SQL `Contract`
21
21
 
22
22
  ## Responsibilities
@@ -109,7 +109,7 @@ export const contract = defineContract({
109
109
 
110
110
  ### Callback Helper Vocabulary
111
111
 
112
- Pack-provided helper presets are available through the callback overload. This is the surface that exposes `field.id.*`, `field.text()`, `field.createdAt()`, `type.sql.String(...)`, and extension helpers such as `type.pgvector.Vector(...)`.
112
+ Pack-provided helper presets are available through the callback overload. This is the surface that exposes `field.id.*`, `field.text()`, `field.temporal.createdAt()`, `field.temporal.updatedAt()`, `type.sql.String(...)`, and extension helpers such as `type.pgvector.Vector(...)`.
113
113
 
114
114
  ```typescript
115
115
  import pgvector from '@prisma-next/extension-pgvector/pack';
@@ -136,6 +136,8 @@ export const contract = defineContract(
136
136
  shortName: field.namedType(types.ShortName),
137
137
  role: field.namedType(types.Role),
138
138
  embedding: field.namedType(types.Embedding1536).optional(),
139
+ createdAt: field.temporal.createdAt(),
140
+ updatedAt: field.temporal.updatedAt(),
139
141
  },
140
142
  });
141
143
 
@@ -192,7 +194,8 @@ const Membership = model('Membership', {
192
194
  ### Helper Notes
193
195
 
194
196
  - Structural helpers: `field.column(...)`, `field.generated(...)`, `field.namedType(...)`, plus `model(...)` and `rel.*`
195
- - Callback helper presets: `field.id.uuidv4()`, `field.id.uuidv7()`, `field.id.nanoid({ size })`, `field.uuid()`, `field.text()`, `field.timestamp()`, `field.createdAt()`, and `type.*`
197
+ - Callback helper presets: `field.id.uuidv4()`, `field.id.uuidv7()`, `field.id.nanoid({ size })`, `field.uuid()`, `field.text()`, `field.timestamp()`, `field.temporal.createdAt()`, `field.temporal.updatedAt()`, and `type.*`
198
+ - Timestamp helpers mirror PSL semantics: `field.temporal.createdAt()` lowers to a target storage `now()` default, while `field.temporal.updatedAt()` lowers to the target-owned `timestampNow` execution default for create and non-empty update mutations.
196
199
  - Keep field-local and FK-local storage overrides next to the authoring site with `field.sql(...)` and `rel.belongsTo(...).sql({ fk })`
197
200
  - Prefer typed local refs such as `field.namedType(types.Role)`, `User.refs.id`, and `User.ref('id')` when those tokens are available
198
201
  - See [API.md](./API.md) for generated-field spec semantics, validation rules, and typed-reference warning behavior
@@ -1 +1 @@
1
- {"version":3,"file":"config-types.d.mts","names":[],"sources":["../src/config-types.ts"],"sourcesContent":[],"mappings":";;;;iBAMgB,kBAAA,WAA6B,4BAA4B;iBASzD,0BAAA,yCAAmE"}
1
+ {"version":3,"file":"config-types.d.mts","names":[],"sources":["../src/config-types.ts"],"mappings":";;;;iBAmBgB,kBAAA,CAAmB,QAAA,EAAU,QAAA,EAAU,MAAA,YAAkB,gBAAA;AAAA,iBAWzD,0BAAA,CAA2B,YAAA,UAAsB,MAAA,YAAkB,gBAAA"}
@@ -1,8 +1,19 @@
1
1
  import { ifDefined } from "@prisma-next/utils/defined";
2
2
  import { pathToFileURL } from "node:url";
3
3
  import { ok } from "@prisma-next/utils/result";
4
-
4
+ import { extname } from "pathe";
5
5
  //#region src/config-types.ts
6
+ /**
7
+ * Derives the emit output path from the TS contract input so artefacts land
8
+ * colocated with the source (e.g. `prisma/contract.ts` →
9
+ * `prisma/contract.json`). Mirrors the same default-derivation logic in
10
+ * `@prisma-next/sql-contract-psl/provider`.
11
+ */
12
+ function defaultOutputFromContractPath(contractPath) {
13
+ const ext = extname(contractPath);
14
+ if (ext.length === 0) return `${contractPath}.json`;
15
+ return `${contractPath.slice(0, -ext.length)}.json`;
16
+ }
6
17
  function typescriptContract(contract, output) {
7
18
  return {
8
19
  source: { load: async () => ok(contract) },
@@ -22,10 +33,10 @@ function typescriptContractFromPath(contractPath, output) {
22
33
  return ok(contract);
23
34
  }
24
35
  },
25
- ...ifDefined("output", output)
36
+ output: output ?? defaultOutputFromContractPath(contractPath)
26
37
  };
27
38
  }
28
-
29
39
  //#endregion
30
40
  export { typescriptContract, typescriptContractFromPath };
41
+
31
42
  //# sourceMappingURL=config-types.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-types.mjs","names":["contract: Contract | undefined"],"sources":["../src/config-types.ts"],"sourcesContent":["import { pathToFileURL } from 'node:url';\nimport type { ContractConfig } from '@prisma-next/config/config-types';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { ok } from '@prisma-next/utils/result';\n\nexport function typescriptContract(contract: Contract, output?: string): ContractConfig {\n return {\n source: {\n load: async () => ok(contract),\n },\n ...ifDefined('output', output),\n };\n}\n\nexport function typescriptContractFromPath(contractPath: string, output?: string): ContractConfig {\n return {\n source: {\n inputs: [contractPath],\n load: async (context) => {\n const [absolutePath] = context.resolvedInputs;\n if (absolutePath === undefined) {\n throw new Error(\n 'typescriptContractFromPath: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.',\n );\n }\n const mod = await import(pathToFileURL(absolutePath).href);\n const contract: Contract | undefined = mod.default ?? mod.contract;\n if (contract === undefined) {\n throw new Error(\n `typescriptContractFromPath: module at \"${absolutePath}\" has no \"default\" or \"contract\" export.`,\n );\n }\n return ok(contract);\n },\n },\n ...ifDefined('output', output),\n };\n}\n"],"mappings":";;;;;AAMA,SAAgB,mBAAmB,UAAoB,QAAiC;AACtF,QAAO;EACL,QAAQ,EACN,MAAM,YAAY,GAAG,SAAS,EAC/B;EACD,GAAG,UAAU,UAAU,OAAO;EAC/B;;AAGH,SAAgB,2BAA2B,cAAsB,QAAiC;AAChG,QAAO;EACL,QAAQ;GACN,QAAQ,CAAC,aAAa;GACtB,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,gBAAgB,QAAQ;AAC/B,QAAI,iBAAiB,OACnB,OAAM,IAAI,MACR,+IACD;IAEH,MAAM,MAAM,MAAM,OAAO,cAAc,aAAa,CAAC;IACrD,MAAMA,WAAiC,IAAI,WAAW,IAAI;AAC1D,QAAI,aAAa,OACf,OAAM,IAAI,MACR,0CAA0C,aAAa,0CACxD;AAEH,WAAO,GAAG,SAAS;;GAEtB;EACD,GAAG,UAAU,UAAU,OAAO;EAC/B"}
1
+ {"version":3,"file":"config-types.mjs","names":[],"sources":["../src/config-types.ts"],"sourcesContent":["import { pathToFileURL } from 'node:url';\nimport type { ContractConfig } from '@prisma-next/config/config-types';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { ok } from '@prisma-next/utils/result';\nimport { extname } from 'pathe';\n\n/**\n * Derives the emit output path from the TS contract input so artefacts land\n * colocated with the source (e.g. `prisma/contract.ts` →\n * `prisma/contract.json`). Mirrors the same default-derivation logic in\n * `@prisma-next/sql-contract-psl/provider`.\n */\nfunction defaultOutputFromContractPath(contractPath: string): string {\n const ext = extname(contractPath);\n if (ext.length === 0) return `${contractPath}.json`;\n return `${contractPath.slice(0, -ext.length)}.json`;\n}\n\nexport function typescriptContract(contract: Contract, output?: string): ContractConfig {\n return {\n source: {\n load: async () => ok(contract),\n },\n // The in-memory variant has no input path to anchor on; fall through to\n // the global default in `normalizeContractConfig` when caller doesn't pin it.\n ...ifDefined('output', output),\n };\n}\n\nexport function typescriptContractFromPath(contractPath: string, output?: string): ContractConfig {\n return {\n source: {\n inputs: [contractPath],\n load: async (context) => {\n const [absolutePath] = context.resolvedInputs;\n if (absolutePath === undefined) {\n throw new Error(\n 'typescriptContractFromPath: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.',\n );\n }\n const mod = await import(pathToFileURL(absolutePath).href);\n const contract: Contract | undefined = mod.default ?? mod.contract;\n if (contract === undefined) {\n throw new Error(\n `typescriptContractFromPath: module at \"${absolutePath}\" has no \"default\" or \"contract\" export.`,\n );\n }\n return ok(contract);\n },\n },\n output: output ?? defaultOutputFromContractPath(contractPath),\n };\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAS,8BAA8B,cAA8B;CACnE,MAAM,MAAM,QAAQ,aAAa;CACjC,IAAI,IAAI,WAAW,GAAG,OAAO,GAAG,aAAa;CAC7C,OAAO,GAAG,aAAa,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC;;AAG/C,SAAgB,mBAAmB,UAAoB,QAAiC;CACtF,OAAO;EACL,QAAQ,EACN,MAAM,YAAY,GAAG,SAAS,EAC/B;EAGD,GAAG,UAAU,UAAU,OAAO;EAC/B;;AAGH,SAAgB,2BAA2B,cAAsB,QAAiC;CAChG,OAAO;EACL,QAAQ;GACN,QAAQ,CAAC,aAAa;GACtB,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,gBAAgB,QAAQ;IAC/B,IAAI,iBAAiB,KAAA,GACnB,MAAM,IAAI,MACR,+IACD;IAEH,MAAM,MAAM,MAAM,OAAO,cAAc,aAAa,CAAC;IACrD,MAAM,WAAiC,IAAI,WAAW,IAAI;IAC1D,IAAI,aAAa,KAAA,GACf,MAAM,IAAI,MACR,0CAA0C,aAAa,0CACxD;IAEH,OAAO,GAAG,SAAS;;GAEtB;EACD,QAAQ,UAAU,8BAA8B,aAAa;EAC9D"}