@tailor-platform/sdk 2.16.0 → 2.18.0
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/CHANGELOG.md +61 -0
- package/dist/{application-wYQ-ivDg.mjs → application-DEkgf2w1.mjs} +18 -18
- package/dist/application-DEkgf2w1.mjs.map +1 -0
- package/dist/application-Dl94fzpm.mjs +1 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-files.d.mts +5 -1
- package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +2 -2
- package/dist/cli/lib.d.mts +4 -3
- package/dist/cli/lib.mjs +1 -1
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.mjs +43 -43
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/shared/error-diagnostics.d.mts +10 -0
- package/dist/cli/shared/error-json.d.mts +19 -0
- package/dist/cli/shared/github-actions.d.mts +11 -0
- package/dist/cli/shared/logger.d.mts +18 -0
- package/dist/completion/zsh-worker.zsh +2 -2
- package/dist/configure/index.mjs +1 -1
- package/dist/configure/index.mjs.map +1 -1
- package/dist/crashreport-CgymxQDu.mjs +1 -0
- package/dist/crashreport-Cyuz1qiu.mjs +42 -0
- package/dist/crashreport-Cyuz1qiu.mjs.map +1 -0
- package/dist/{errors-BtTxkzgy.mjs → errors-BjJnpXkK.mjs} +2 -2
- package/dist/{errors-BtTxkzgy.mjs.map → errors-BjJnpXkK.mjs.map} +1 -1
- package/dist/field-parse-CzlKC4b7.mjs +2 -0
- package/dist/field-parse-CzlKC4b7.mjs.map +1 -0
- package/dist/kysely-type-B_oA8D1k.mjs +43 -0
- package/dist/kysely-type-B_oA8D1k.mjs.map +1 -0
- package/dist/{logger-CEAxByN5.mjs → logger-72hM4JWZ.mjs} +4 -4
- package/dist/logger-72hM4JWZ.mjs.map +1 -0
- package/dist/{manager-E3ffRcCt.mjs → manager-C26Gi1bX.mjs} +2 -2
- package/dist/{manager-E3ffRcCt.mjs.map → manager-C26Gi1bX.mjs.map} +1 -1
- package/dist/plugin/builtin/kysely-type/index.d.mts +2 -0
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
- package/dist/plugin/index.mjs +1 -1
- package/dist/{register-ts-hook-DrHS-J1k.mjs → register-ts-hook-BD3ArLqY.mjs} +111 -72
- package/dist/register-ts-hook-BD3ArLqY.mjs.map +1 -0
- package/dist/schema-DRyQEabV.mjs +2 -0
- package/dist/schema-DRyQEabV.mjs.map +1 -0
- package/dist/seed/index.d.mts +5 -0
- package/dist/seed/index.mjs +3 -2
- package/dist/seed/index.mjs.map +1 -1
- package/dist/service-B3OiWCYg.mjs +1 -0
- package/dist/{service-Cw7hb5HK.mjs → service-B4Gh_bbL.mjs} +2 -2
- package/dist/{service-Cw7hb5HK.mjs.map → service-B4Gh_bbL.mjs.map} +1 -1
- package/dist/{service-DaoW0kzo.mjs → service-eM7Fd8zS.mjs} +3 -3
- package/dist/{service-DaoW0kzo.mjs.map → service-eM7Fd8zS.mjs.map} +1 -1
- package/dist/tailordb-ddl-Fgm2cNvT.mjs +7 -0
- package/dist/tailordb-ddl-Fgm2cNvT.mjs.map +1 -0
- package/dist/utils/test/index.mjs +1 -1
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/mocks/tailordb-pglite.d.mts +5 -4
- package/docs/cli/tailordb.md +8 -8
- package/docs/cli-reference.md +18 -5
- package/docs/services/tailordb-migration.md +29 -24
- package/docs/testing.md +23 -21
- package/package.json +16 -15
- package/dist/application-Dw3t9p2f.mjs +0 -1
- package/dist/application-wYQ-ivDg.mjs.map +0 -1
- package/dist/crashreport-DF8YMIE5.mjs +0 -1
- package/dist/crashreport-Doz2Kuuq.mjs +0 -42
- package/dist/crashreport-Doz2Kuuq.mjs.map +0 -1
- package/dist/field-column-type-QMtF6lUp.mjs +0 -2
- package/dist/field-column-type-QMtF6lUp.mjs.map +0 -1
- package/dist/kysely-type-B-BOlXH7.mjs +0 -43
- package/dist/kysely-type-B-BOlXH7.mjs.map +0 -1
- package/dist/logger-CEAxByN5.mjs.map +0 -1
- package/dist/register-ts-hook-DrHS-J1k.mjs.map +0 -1
- package/dist/schema-BTioi2dP.mjs +0 -2
- package/dist/schema-BTioi2dP.mjs.map +0 -1
- package/dist/service-dn9jxC8c.mjs +0 -1
|
@@ -29,10 +29,11 @@ interface CreatedClient {
|
|
|
29
29
|
* PGlite instances are borrowed, never closed — close them yourself (e.g. in
|
|
30
30
|
* `afterAll`).
|
|
31
31
|
*
|
|
32
|
-
* Create the tables a test needs up front
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
32
|
+
* Create the tables a test needs up front: run the script `kyselyTypePlugin`
|
|
33
|
+
* writes when `pgliteSchemaPath` is set, or your own `CREATE TABLE`
|
|
34
|
+
* statements matching the generated Kysely types. PGlite runs full PostgreSQL
|
|
35
|
+
* while TailorDB supports a subset of it, so a statement passing here can
|
|
36
|
+
* still be rejected by the platform.
|
|
36
37
|
*
|
|
37
38
|
* Transactions on a shared instance are serialized: while one is open,
|
|
38
39
|
* queries from other `getDB` instances on the same PGlite instance wait for
|
package/docs/cli/tailordb.md
CHANGED
|
@@ -177,19 +177,19 @@ tailor tailordb migration script [options] <number>
|
|
|
177
177
|
|
|
178
178
|
**Options**
|
|
179
179
|
|
|
180
|
-
| Option | Alias | Description
|
|
181
|
-
| ------------------------- | ----- |
|
|
182
|
-
| `--config <CONFIG>` | `-c` | Path to Tailor config file
|
|
183
|
-
| `--namespace <NAMESPACE>` | `-n` | Target TailorDB namespace (required if multiple namespaces exist)
|
|
184
|
-
| `--no-script` | - | Record that this migration intentionally runs without a migration script (requires --reason)
|
|
185
|
-
| `--reason <REASON>` | - | Reason why no migration script is needed (used with --no-script)
|
|
186
|
-
| `--with-test` | - | Also add
|
|
180
|
+
| Option | Alias | Description | Required | Default | Env |
|
|
181
|
+
| ------------------------- | ----- | -------------------------------------------------------------------------------------------- | -------- | -------------------- | -------------------- |
|
|
182
|
+
| `--config <CONFIG>` | `-c` | Path to Tailor config file | No | `"tailor.config.ts"` | `TAILOR_CONFIG_PATH` |
|
|
183
|
+
| `--namespace <NAMESPACE>` | `-n` | Target TailorDB namespace (required if multiple namespaces exist) | No | - | - |
|
|
184
|
+
| `--no-script` | - | Record that this migration intentionally runs without a migration script (requires --reason) | No | - | - |
|
|
185
|
+
| `--reason <REASON>` | - | Reason why no migration script is needed (used with --no-script) | No | - | - |
|
|
186
|
+
| `--with-test` | - | Also add the migrate.test.ts and migrate.pglite.test.ts scaffolds | No | - | - |
|
|
187
187
|
|
|
188
188
|
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
189
189
|
|
|
190
190
|
**Notes**
|
|
191
191
|
|
|
192
|
-
When `migrate.ts` already exists, running the command clears a previously recorded `--no-script` acknowledgment.
|
|
192
|
+
When `migrate.ts` already exists, running the command clears a previously recorded `--no-script` acknowledgment, and `--with-test` adds only the tests that do not exist yet (writing `db.pglite.ts` if it is missing). `migrate.pglite.test.ts` is scaffolded only when `@electric-sql/pglite` is installed in the project.
|
|
193
193
|
|
|
194
194
|
#### tailordb migration set
|
|
195
195
|
|
package/docs/cli-reference.md
CHANGED
|
@@ -95,8 +95,17 @@ An annotation does not by itself fail a step: the step still fails on the CLI's
|
|
|
95
95
|
is unchanged. Workflows that already echo their own `::error::` around the CLI keep working;
|
|
96
96
|
those messages describe the workflow's own checks, which can fail even when the CLI succeeds.
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
When the failure has a known source, the annotation carries it: `seed validate` reports the
|
|
99
|
+
offending JSONL file and line, and a rejected config reports its file — or, when the config or a
|
|
100
|
+
file it imports cannot be parsed, that file and the line it failed on. Locations are written
|
|
101
|
+
relative to `GITHUB_WORKSPACE`; a file outside it is annotated without a location rather than with
|
|
102
|
+
a path the runner cannot resolve.
|
|
103
|
+
|
|
104
|
+
For a JSONL file containing a blank line, the annotation's line and the line printed in the report
|
|
105
|
+
text differ: the annotation counts every line in the file, while the printed line counts only the
|
|
106
|
+
records. The annotation points at the row as an editor numbers it.
|
|
107
|
+
|
|
108
|
+
`generate` and `deploy` do not group their per-service progress.
|
|
100
109
|
|
|
101
110
|
## Common Options
|
|
102
111
|
|
|
@@ -210,9 +219,13 @@ Resolution rules:
|
|
|
210
219
|
- **Lookup order:** the project's `node_modules/.bin` (nearest first, walking up from the current
|
|
211
220
|
directory), then your `PATH`. So a plugin installed as a project dev-dependency takes precedence over a
|
|
212
221
|
globally installed one.
|
|
213
|
-
- **
|
|
214
|
-
|
|
215
|
-
|
|
222
|
+
- **Global flags reach the plugin from either side.** `tailor --json tailordb erd export` and
|
|
223
|
+
`tailor tailordb erd export --json` both forward `--json`, and likewise `--verbose` and the
|
|
224
|
+
`--env-file` options. A flag typed before the plugin name is consumed by the host CLI first and
|
|
225
|
+
then forwarded, so when the same flag appears on both sides the later one wins. A flag the host
|
|
226
|
+
does not define — including one only some commands declare, such as `--profile` — still has to be
|
|
227
|
+
typed after the plugin's own subcommand. `--help` and `--version` are answered by the host CLI and
|
|
228
|
+
never dispatch a plugin.
|
|
216
229
|
|
|
217
230
|
Because resolution is based on `node_modules/.bin` and `PATH`, any package manager that populates
|
|
218
231
|
`node_modules/.bin` works for project-local plugins — npm, pnpm (its content-addressable store is
|
|
@@ -24,7 +24,8 @@ migrations/
|
|
|
24
24
|
├── 0001/ # First change
|
|
25
25
|
│ ├── diff.json # Field-level diff from 0000
|
|
26
26
|
│ ├── migrate.ts # Data migration script (auto-generated for breaking changes; can be added manually via `migration script`)
|
|
27
|
-
│
|
|
27
|
+
│ ├── db.ts # Kysely types for the script (pre-migration shape)
|
|
28
|
+
│ └── db.pglite.ts # CREATE TABLE script of that shape, for PGlite tests
|
|
28
29
|
├── 0002/
|
|
29
30
|
│ └── diff.json # No script — non-breaking changes only
|
|
30
31
|
└── ...
|
|
@@ -129,7 +130,7 @@ No `migrate.ts` is generated automatically because the schema change itself is n
|
|
|
129
130
|
tailor tailordb migration script 0002
|
|
130
131
|
```
|
|
131
132
|
|
|
132
|
-
This writes `migrations/0002/migrate.ts` and `migrations/0002/db.ts` next to the existing `diff.json` (add `--with-test` to also scaffold
|
|
133
|
+
This writes `migrations/0002/migrate.ts`, `migrations/0002/db.ts`, and `migrations/0002/db.pglite.ts` next to the existing `diff.json` (add `--with-test` to also scaffold the tests — see [Testing Migrations Locally](#testing-migrations-locally)). The removed field stays readable inside `migrate.ts` because the pre-migration phase keeps it on the table until the script finishes (see [Per-migration phases](#per-migration-phases)). The next `tailor deploy` runs the script automatically — `migrate.ts` is executed whenever the file exists on disk, regardless of whether the diff itself required it.
|
|
133
134
|
|
|
134
135
|
If the data loss is intentional and no script is needed, record that decision the same way as for breaking changes (see [Breaking changes without a script](#breaking-changes-without-a-script)):
|
|
135
136
|
|
|
@@ -267,13 +268,15 @@ export default defineConfig({
|
|
|
267
268
|
|
|
268
269
|
## Generated Files
|
|
269
270
|
|
|
270
|
-
| File
|
|
271
|
-
|
|
|
272
|
-
| `0000/schema.json`
|
|
273
|
-
| `XXXX/diff.json`
|
|
274
|
-
| `XXXX/migrate.ts`
|
|
275
|
-
| `XXXX/db.ts`
|
|
276
|
-
| `XXXX/
|
|
271
|
+
| File | When generated | Description |
|
|
272
|
+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
273
|
+
| `0000/schema.json` | First `migration generate` | Full snapshot of all tables in the namespace. |
|
|
274
|
+
| `XXXX/diff.json` | Every subsequent migration | Field-level diff against the previous snapshot. |
|
|
275
|
+
| `XXXX/migrate.ts` | Auto-generated for breaking changes and `--data-only` migrations; added manually via `tailordb migration script` for warning-tier changes | Data transformation script. The `main` export receives a Kysely `Transaction`. |
|
|
276
|
+
| `XXXX/db.ts` | Generated once when `migrate.ts` is created | Kysely types reflecting the schema **before** this migration. Exports `Database`, `Transaction`, and `MigrationContext`. |
|
|
277
|
+
| `XXXX/db.pglite.ts` | Generated with `db.ts` | `CREATE TABLE` script of the same schema, for running `migrate.ts` on PGlite. Never deployed. |
|
|
278
|
+
| `XXXX/migrate.test.ts` | Added via `tailordb migration script --with-test` | Unit-test scaffold for `migrate.ts` (see [Testing Migrations Locally](#testing-migrations-locally)). Never deployed. |
|
|
279
|
+
| `XXXX/migrate.pglite.test.ts` | Added via `tailordb migration script --with-test` when `@electric-sql/pglite` is installed | PGlite test scaffold for `migrate.ts`. Never deployed. |
|
|
277
280
|
|
|
278
281
|
`db.ts` reflects the pre-migration schema because the script runs after the pre-migration phase has temporarily relaxed breaking constraints (e.g., a new `required` field is added as `optional` first), so the data being read still matches the previous shape.
|
|
279
282
|
|
|
@@ -281,8 +284,12 @@ export default defineConfig({
|
|
|
281
284
|
|
|
282
285
|
Migration files are versioned independently of the SDK package. This SDK writes format version `6` and reads versions `1` through `6`. It normalizes supported older formats in memory; it never rewrites applied migration files on disk. Format version `6` records renames of members inside nested fields (`memberRenames`); older SDK versions refuse to read it rather than deploying such a migration without the copy step.
|
|
283
286
|
|
|
287
|
+
Supported histories also preserve the behavior of field hooks and validators saved by older SDKs, including access to the record and boolean validators with a separate error message. Legacy update hooks retain existing values for omitted fields; explicitly supplied values, including `null`, take precedence. This applies to both snapshots and diffs, including nested fields. Your existing migration files can remain as generated.
|
|
288
|
+
|
|
284
289
|
If a future SDK can no longer replay an old migration format, re-baseline while using an SDK version that still supports the complete history, commit the new baseline, deploy it to every environment, and then upgrade the SDK. A file from a newer unsupported format instead requires upgrading the SDK first. The CLI rejects both cases with guidance rather than attempting a best-effort replay.
|
|
285
290
|
|
|
291
|
+
The SDK used for this transition must read the old history and write a baseline format that the target SDK accepts. Keep that SDK version pinned until every environment has adopted the new baseline. File-format support does not guarantee compatibility for arbitrary imports in a custom `migrate.ts`; keep its dependencies pinned and test customized scripts when upgrading.
|
|
292
|
+
|
|
286
293
|
There is no migration-file conversion command. Keeping applied files unchanged preserves the record of what ran, while `migration rebaseline` provides the escape hatch when the supported replay window changes.
|
|
287
294
|
|
|
288
295
|
## Migration Script Anatomy
|
|
@@ -811,7 +818,7 @@ Scaffold a ready-to-fill test next to the script with:
|
|
|
811
818
|
tailor tailordb migration script 0005 --with-test
|
|
812
819
|
```
|
|
813
820
|
|
|
814
|
-
When `migrate.ts` already exists (the usual case for breaking changes, where `migration generate` creates it), the command adds only `
|
|
821
|
+
When `migrate.ts` already exists (the usual case for breaking changes, where `migration generate` creates it), the command adds only the tests that do not exist yet, plus a missing `db.pglite.ts`. Or write the test by hand:
|
|
815
822
|
|
|
816
823
|
```typescript
|
|
817
824
|
// migrations/0005/migrate.test.ts
|
|
@@ -845,30 +852,24 @@ A statement-level test verifies what the script issues, not what it does to data
|
|
|
845
852
|
npm install -D @electric-sql/pglite
|
|
846
853
|
```
|
|
847
854
|
|
|
848
|
-
|
|
855
|
+
The generated `db.pglite.ts` exports the `CREATE TABLE` script for the same schema `db.ts` types — the tables as the pre-migration phase leaves them while `migrate.ts` runs, including relaxed constraints, renamed fields under both names, and retained removed fields. Run it once on the PGlite instance, stage rows, then run the script in a transaction. `tailor tailordb migration script <N> --with-test` scaffolds this test too when `@electric-sql/pglite` is installed. Type the instance with `Unmigrated<Database>` rather than `Database`: `db.ts` types a column the migration makes required as `T | null` on read but `T` on write (and an enum it narrows as the old values on read but the new ones on write), so that `migrate.ts` cannot write what the migration is removing — which would also stop the test from staging the rows the script has to convert. `Unmigrated` lets every column be written with whatever it can still be read as; `main` still receives a `Transaction<Database>`.
|
|
849
856
|
|
|
850
857
|
```typescript
|
|
851
858
|
// migrations/0005/migrate.pglite.test.ts
|
|
852
859
|
import { PGlite } from "@electric-sql/pglite";
|
|
853
|
-
import { sql } from "@tailor-platform/sdk/kysely";
|
|
854
860
|
import { createKyselyPGlite, type Unmigrated } from "@tailor-platform/sdk/vitest";
|
|
855
861
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
856
862
|
import type { Database } from "./db";
|
|
863
|
+
import { pgliteSchema } from "./db.pglite";
|
|
857
864
|
import { main } from "./migrate";
|
|
858
865
|
|
|
859
|
-
const
|
|
866
|
+
const pglite = new PGlite();
|
|
867
|
+
const db = createKyselyPGlite<Unmigrated<Database>>(pglite);
|
|
860
868
|
|
|
869
|
+
// PGlite loads Postgres on first use, which can take longer than the default hook timeout.
|
|
861
870
|
beforeAll(async () => {
|
|
862
|
-
await
|
|
863
|
-
|
|
864
|
-
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
865
|
-
"name" text NOT NULL,
|
|
866
|
-
"email" text,
|
|
867
|
-
"createdAt" timestamptz NOT NULL,
|
|
868
|
-
"updatedAt" timestamptz NOT NULL
|
|
869
|
-
)
|
|
870
|
-
`.execute(db);
|
|
871
|
-
});
|
|
871
|
+
await pglite.exec(pgliteSchema.tailordb);
|
|
872
|
+
}, 60_000);
|
|
872
873
|
|
|
873
874
|
afterAll(async () => {
|
|
874
875
|
await db.destroy();
|
|
@@ -896,10 +897,14 @@ describe("0005 add required email", () => {
|
|
|
896
897
|
});
|
|
897
898
|
```
|
|
898
899
|
|
|
900
|
+
Pass nested field values as JavaScript objects or arrays of objects, without `JSON.stringify`.
|
|
901
|
+
Generated migration types use `Record<string, unknown>` for each nested object so scripts can
|
|
902
|
+
work with both old and new members during a migration; narrow member values before using them.
|
|
903
|
+
|
|
899
904
|
Two caveats keep this from replacing a scratch workspace:
|
|
900
905
|
|
|
901
906
|
- PGlite runs full PostgreSQL, while TailorDB supports [a subset of it](https://docs.tailor.tech/guides/function/accessing-tailordb#supported-sql-queries) — a statement that passes here can still be rejected on deploy.
|
|
902
|
-
-
|
|
907
|
+
- `db.pglite.ts` mirrors the column shape, not the platform: hooks, validations, and permissions do not run, and the limits listed under [Real SQL execution with PGlite](../testing.md#real-sql-execution-with-pglite-mocktailordbwithpglite) apply.
|
|
903
908
|
|
|
904
909
|
### Beyond unit tests
|
|
905
910
|
|
package/docs/testing.md
CHANGED
|
@@ -149,26 +149,30 @@ Pass `{ onUnhandled: "error" }` to make an unmatched query fail instead of retur
|
|
|
149
149
|
|
|
150
150
|
Instead of staging responses, back TailorDB with [`@electric-sql/pglite`](https://pglite.dev/) — an in-memory PostgreSQL (install it as a devDependency) — so the queries a resolver, executor, or workflow job issues through `getDB()` execute against real data. `getDB(namespace)` needs no test-side swap: acquire the mock, and each namespace you list resolves to its PGlite instance.
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
Let `kyselyTypePlugin` generate the `CREATE TABLE` script for you: set `pgliteSchemaPath` next to `distPath`, and `tailor generate` writes a module exporting one script per namespace, derived from the same table definitions as the Kysely types.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// tailor.config.ts
|
|
156
|
+
kyselyTypePlugin({
|
|
157
|
+
distPath: "./generated/db.ts",
|
|
158
|
+
pgliteSchemaPath: "./generated/db.pglite.ts",
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Run the namespace's script once per PGlite instance. Every statement is `IF NOT EXISTS`, so applying it again to an instance that already has the tables is harmless.
|
|
153
163
|
|
|
154
164
|
```typescript
|
|
155
165
|
import { PGlite } from "@electric-sql/pglite";
|
|
156
166
|
import { mockTailordbWithPGlite } from "@tailor-platform/sdk/vitest";
|
|
157
167
|
import { afterAll, beforeAll, expect, test } from "vitest";
|
|
158
168
|
import { getDB } from "../generated/db";
|
|
169
|
+
import { pgliteSchema } from "../generated/db.pglite";
|
|
159
170
|
import resolver from "./upsertUsers";
|
|
160
171
|
|
|
161
172
|
const pglite = new PGlite();
|
|
162
173
|
|
|
163
174
|
beforeAll(async () => {
|
|
164
|
-
await pglite.exec(
|
|
165
|
-
CREATE TABLE "User" (
|
|
166
|
-
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
167
|
-
"name" text NOT NULL,
|
|
168
|
-
"email" text NOT NULL,
|
|
169
|
-
"age" integer NOT NULL
|
|
170
|
-
);
|
|
171
|
-
`);
|
|
175
|
+
await pglite.exec(pgliteSchema["main-db"]);
|
|
172
176
|
});
|
|
173
177
|
|
|
174
178
|
afterAll(async () => {
|
|
@@ -201,21 +205,19 @@ test("upserts against real rows", async () => {
|
|
|
201
205
|
});
|
|
202
206
|
```
|
|
203
207
|
|
|
204
|
-
|
|
208
|
+
The generated columns follow the Kysely types, not TailorDB's storage: `text` for string and enum fields, `timestamptz` for datetime, `date` and `time` for date and time, `numeric` for decimal, rounded to the configured scale and read back with exactly that many fractional digits, `jsonb` for nested objects (and arrays of them), Postgres arrays for other array fields. `id` is a generated `uuid` primary key, `.unique()` fields and unique `.indexes()` are enforced, so `ON CONFLICT` upserts behave, and `.default()` values become column defaults (`"now"` becomes the current time). `.serial()` fields are assigned by the database from the configured `start`, `maxValue`, and format. Relations are not enforced.
|
|
205
209
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
);
|
|
213
|
-
```
|
|
210
|
+
What the script cannot reproduce:
|
|
211
|
+
|
|
212
|
+
- Hooks, validations, and permissions do not run. A required field whose value only its own field-level create hook supplies is created nullable, so inserts that omit it succeed; give it a `.default()` if the test reads it back. A field filled by a table-level hook stays `NOT NULL`, as its Kysely type still requires it on insert.
|
|
213
|
+
- Serial formats are reproduced for a single `%d`, `%x`, or `%X` specifier with an optional zero-padded width; an octal `%o` format fails generation with an error naming the field.
|
|
214
|
+
- A datetime inside a nested object reads back as a string from `jsonb`, not a `Date`.
|
|
215
|
+
- On a persistent PGlite (`dataDir`), tables created by an earlier run are kept as they were; drop them or start from an empty directory after changing a table definition.
|
|
214
216
|
|
|
215
|
-
|
|
217
|
+
To hand-write DDL instead — for a table not in the schema, or to add a constraint — run your own statements after the script, or without it.
|
|
216
218
|
|
|
217
219
|
- The PGlite instance is yours: the mock never closes it, so close it in `afterAll`. Reuse one instance across a suite — creating one per test is slow.
|
|
218
|
-
- Pass the same instance under several namespaces to drive them against one shared database.
|
|
220
|
+
- Pass the same instance under several namespaces to drive them against one shared database. Two namespaces with a same-named table cannot share one instance, because the second script leaves the first table as it is.
|
|
219
221
|
- Seed through `getDB` itself. When a column type rejects a value that only the test must stage, use `createKyselyPGlite<Unmigrated<...>>(pglite)` instead — see [Testing Migrations Locally](./services/tailordb-migration.md#testing-migrations-locally). This only affects test setup; it cannot supply a `.serial()` value for an insert issued by the code under test.
|
|
220
222
|
- Transactions on a shared instance are serialized: while one is open, queries from other `getDB` instances wait. Do not use `test.concurrent` with a shared instance, and do not query the same instance through a second `getDB` from inside a transaction — that waits on itself.
|
|
221
223
|
- PGlite runs full PostgreSQL while TailorDB supports a subset of it, and TailorDB hooks, validations, and permissions do not run here — a test passing on PGlite can still behave differently on the platform. Keep [`mockTailordb`](#tailordb-mock) or [`createKyselyMock`](#kysely-layer-mock-createkyselymock) tests for query shape and error paths, and E2E tests for platform behavior.
|
|
@@ -666,7 +668,7 @@ describe("upsertUsers resolver", () => {
|
|
|
666
668
|
|
|
667
669
|
Reach for [`mockTailordb`](#mocking-the-tailordb-client) instead when you want to drive the raw query sequence at the `tailordb.Client` level rather than at the Kysely layer, or [`mockTailordbWithPGlite`](#real-sql-execution-with-pglite-mocktailordbwithpglite) to execute the queries against a real in-memory Postgres.
|
|
668
670
|
|
|
669
|
-
TailorDB migration scripts (`migrate.ts`) are unit-tested the same way: the generated `db.ts` exports the `Database` interface to type the mock, and `tailor tailordb migration script <N> --with-test` scaffolds a ready-to-fill test. To execute a migration script against real rows in an in-memory Postgres, use `createKyselyPGlite` with `@electric-sql/pglite
|
|
671
|
+
TailorDB migration scripts (`migrate.ts`) are unit-tested the same way: the generated `db.ts` exports the `Database` interface to type the mock, and `tailor tailordb migration script <N> --with-test` scaffolds a ready-to-fill test. To execute a migration script against real rows in an in-memory Postgres, use `createKyselyPGlite` with `@electric-sql/pglite` and the generated `db.pglite.ts` schema. See [Testing Migrations Locally](./services/tailordb-migration.md#testing-migrations-locally).
|
|
670
672
|
|
|
671
673
|
#### Resolvers that resume a workflow
|
|
672
674
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailor-platform/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "Tailor Platform SDK - The SDK to work with Tailor Platform",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -151,12 +151,12 @@
|
|
|
151
151
|
"dependencies": {
|
|
152
152
|
"@0no-co/graphql.web": "1.3.4",
|
|
153
153
|
"@badgateway/oauth2-client": "3.3.1",
|
|
154
|
-
"@bufbuild/protobuf": "2.
|
|
154
|
+
"@bufbuild/protobuf": "2.15.0",
|
|
155
155
|
"@bufbuild/protovalidate": "1.2.0",
|
|
156
156
|
"@connectrpc/connect": "2.2.0",
|
|
157
157
|
"@connectrpc/connect-node": "2.2.0",
|
|
158
|
-
"@inquirer/core": "12.0.
|
|
159
|
-
"@inquirer/prompts": "8.7.
|
|
158
|
+
"@inquirer/core": "12.0.3",
|
|
159
|
+
"@inquirer/prompts": "8.7.2",
|
|
160
160
|
"@jridgewell/trace-mapping": "0.3.31",
|
|
161
161
|
"@napi-rs/keyring": "2.0.0",
|
|
162
162
|
"@opentelemetry/api": "1.9.1",
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
"@opentelemetry/resources": "2.11.0",
|
|
165
165
|
"@opentelemetry/sdk-trace-node": "2.11.0",
|
|
166
166
|
"@opentelemetry/semantic-conventions": "1.43.0",
|
|
167
|
-
"@oxc-project/types": "0.
|
|
167
|
+
"@oxc-project/types": "0.149.0",
|
|
168
168
|
"@politty/zod": "0.2.1",
|
|
169
169
|
"@secretlint/core": "13.0.5",
|
|
170
170
|
"@secretlint/secretlint-rule-preset-recommend": "13.0.5",
|
|
@@ -185,39 +185,40 @@
|
|
|
185
185
|
"inflection": "3.0.2",
|
|
186
186
|
"kysely": "0.29.5",
|
|
187
187
|
"mime-types": "3.0.2",
|
|
188
|
-
"open": "11.0.
|
|
189
|
-
"oxc-parser": "0.
|
|
188
|
+
"open": "11.0.3",
|
|
189
|
+
"oxc-parser": "0.149.0",
|
|
190
190
|
"p-limit": "7.3.2",
|
|
191
191
|
"pathe": "2.0.3",
|
|
192
192
|
"pgsql-ast-parser": "12.0.2",
|
|
193
|
-
"pkg-types": "2.3.
|
|
194
|
-
"rolldown": "1.2.
|
|
193
|
+
"pkg-types": "2.3.3",
|
|
194
|
+
"rolldown": "1.2.8",
|
|
195
195
|
"semver": "7.8.5",
|
|
196
196
|
"sql-highlight": "6.1.0",
|
|
197
197
|
"std-env": "4.2.0",
|
|
198
198
|
"ts-cron-validator": "1.1.5",
|
|
199
199
|
"type-fest": "5.9.0",
|
|
200
200
|
"xdg-basedir": "5.1.0",
|
|
201
|
-
"zod": "4.
|
|
201
|
+
"zod": "4.6.4"
|
|
202
202
|
},
|
|
203
203
|
"devDependencies": {
|
|
204
|
+
"@electric-sql/pglite": "0.5.8",
|
|
204
205
|
"@opentelemetry/sdk-trace-base": "2.11.0",
|
|
205
206
|
"@tailor-platform/shared": "^0.0.0",
|
|
206
207
|
"@tailor-platform/tailor-proto": "^0.0.1",
|
|
207
208
|
"@types/mime-types": "3.0.1",
|
|
208
|
-
"@types/node": "24.13.
|
|
209
|
+
"@types/node": "24.13.4",
|
|
209
210
|
"@types/semver": "7.8.0",
|
|
210
211
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
211
212
|
"@vitest/coverage-v8": "5.0.0",
|
|
212
|
-
"eslint-plugin-zod": "4.12.
|
|
213
|
-
"oxfmt": "0.
|
|
214
|
-
"oxlint": "1.
|
|
213
|
+
"eslint-plugin-zod": "4.12.1",
|
|
214
|
+
"oxfmt": "0.67.0",
|
|
215
|
+
"oxlint": "1.82.0",
|
|
215
216
|
"oxlint-tsgolint": "7.0.2001",
|
|
216
217
|
"sonda": "0.14.0",
|
|
217
218
|
"tsdown": "0.23.0",
|
|
218
219
|
"typescript": "6.0.3",
|
|
219
220
|
"vitest": "5.0.0",
|
|
220
|
-
"zinfer": "0.4.
|
|
221
|
+
"zinfer": "0.4.6"
|
|
221
222
|
},
|
|
222
223
|
"peerDependencies": {
|
|
223
224
|
"@electric-sql/pglite": ">=0.2.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e,t}from"./application-wYQ-ivDg.mjs";export{t as defineApplication,e as generatePluginFilesIfNeeded};
|