clivly 0.9.6 → 0.9.7
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 +15 -3
- package/core-auth-adapter.cjs +1 -1
- package/core-auth-adapter.mjs +1 -1
- package/core-drizzle.cjs +1 -1
- package/core-drizzle.d.cts +1 -1
- package/core-drizzle.d.mts +1 -1
- package/core-drizzle.mjs +1 -1
- package/core-entity-config.cjs +1 -1
- package/core-entity-config.mjs +1 -1
- package/core-mapping-form.cjs +1 -1
- package/core-mapping-form.mjs +1 -1
- package/core-mappings-config.cjs +1 -1
- package/core-mappings-config.mjs +1 -1
- package/core-sync-engine.cjs +1 -1
- package/core-sync-engine.mjs +1 -1
- package/core-view-compiler.cjs +1 -1
- package/core-view-compiler.mjs +1 -1
- package/core.cjs +4 -5
- package/core.mjs +4 -4
- package/{drizzle-CiK8MMEZ.d.mts → drizzle-BmDDgAIF.d.mts} +3 -1
- package/{drizzle-bfjVzYR6.cjs → drizzle-DcB7OfBp.cjs} +9 -1
- package/{drizzle-DEtRrqtc.d.cts → drizzle-ixVV4pPN.d.cts} +3 -1
- package/{drizzle-3kvhkwO7.mjs → drizzle-wbcuG-cy.mjs} +9 -1
- package/drizzle.cjs +56 -22
- package/drizzle.d.cts +9 -3
- package/drizzle.d.mts +9 -3
- package/drizzle.mjs +56 -22
- package/{entity-config-CusbTOJ1.mjs → entity-config-C8IIkrmX.mjs} +33 -4
- package/{entity-config-DE30_RpU.cjs → entity-config-CPM-Tp-d.cjs} +33 -4
- package/index.cjs +34 -3
- package/index.mjs +34 -3
- package/{internal-BQ47iN6f.cjs → internal-BLKMnIIZ.cjs} +1 -1
- package/{internal-ChufvXE6.mjs → internal-BpVh_J77.mjs} +1 -1
- package/internal-drizzle.cjs +1 -1
- package/internal-drizzle.d.cts +1 -1
- package/internal-drizzle.d.mts +1 -1
- package/internal-drizzle.mjs +1 -1
- package/internal-entity-config.cjs +1 -1
- package/internal-entity-config.mjs +1 -1
- package/internal-entity-heuristics.cjs +1 -1
- package/internal-entity-heuristics.mjs +1 -1
- package/internal-mappings-config.cjs +1 -1
- package/internal-mappings-config.mjs +1 -1
- package/internal.cjs +3 -3
- package/internal.mjs +3 -3
- package/{mappings-config-CjCmT-aU.cjs → mappings-config-CBwL3FVh.cjs} +1 -1
- package/{mappings-config-7qQ47p9K.mjs → mappings-config-DUKBe6OS.mjs} +1 -1
- package/{namespace-probe-Ckn9yJ6F.d.mts → namespace-probe-BQ4imnV7.d.mts} +41 -1
- package/{namespace-probe-DaTJINS-.d.cts → namespace-probe-DZIGdvlm.d.cts} +41 -1
- package/package.json +1 -1
- package/{sdk-w8Kv_XnW.cjs → sdk-BL9BCzyD.cjs} +324 -14
- package/{sdk-Dkq6ELkf.mjs → sdk-CubnsyD9.mjs} +324 -14
- package/sdk.cjs +2 -2
- package/sdk.d.cts +2 -2
- package/sdk.d.mts +2 -2
- package/sdk.mjs +2 -2
- package/vite.d.cts +1 -1
- package/vite.d.mts +1 -1
package/README.md
CHANGED
|
@@ -92,6 +92,12 @@ empty, for you or `clivly login` to fill; the trigger URL gets a visible
|
|
|
92
92
|
`https://<yourDomain.com>/api/clivly/tick` template, because there the shape is
|
|
93
93
|
the documentation.
|
|
94
94
|
|
|
95
|
+
From `0.9.7` the scaffolded config also sets `introspector:
|
|
96
|
+
drizzleIntrospector(db)`. Clivly never connects to your database, so that handle
|
|
97
|
+
is what lets your app run a **derived object** authored in Clivly's dashboard —
|
|
98
|
+
scaffolding it by default is what makes such an object sync with no further code
|
|
99
|
+
on your side. It costs nothing if you never author one.
|
|
100
|
+
|
|
95
101
|
| Flag | Purpose |
|
|
96
102
|
| --- | --- |
|
|
97
103
|
| `--dry-run` | Show what would be written; write nothing |
|
|
@@ -268,7 +274,7 @@ It answers two questions under two headings:
|
|
|
268
274
|
scope; `clivly doctor` is local by definition and omits it.
|
|
269
275
|
- **This project** — the local ladder, run here on your machine: credential →
|
|
270
276
|
Clivly reachable → `clivly.config` loads → `clivly.config` is edge-safe →
|
|
271
|
-
boot hook wired → setup checks → sync trigger URL.
|
|
277
|
+
boot hook wired → setup checks → dashboard-authored objects → sync trigger URL.
|
|
272
278
|
|
|
273
279
|
```text
|
|
274
280
|
Clivly status
|
|
@@ -281,11 +287,17 @@ Workspace
|
|
|
281
287
|
🔒 Let Clivly start a sync
|
|
282
288
|
|
|
283
289
|
This project
|
|
284
|
-
✅ Step 1 of
|
|
285
|
-
✅ Step 2 of
|
|
290
|
+
✅ Step 1 of 8 · API key present
|
|
291
|
+
✅ Step 2 of 8 · Clivly reachable — Acme
|
|
286
292
|
...
|
|
287
293
|
```
|
|
288
294
|
|
|
295
|
+
**Dashboard-authored objects** is new in `0.9.7`. It reports how many derived
|
|
296
|
+
objects authored in Clivly ran on the last sync and how many were quarantined —
|
|
297
|
+
and, when your config has no `introspector`, warns that such objects cannot run
|
|
298
|
+
at all here and names the one line to add. An app whose installed `clivly`
|
|
299
|
+
predates the feature reports nothing rather than a failure.
|
|
300
|
+
|
|
289
301
|
**Boot hook wired** is the rung to know about. It finds the boot site for your
|
|
290
302
|
framework and confirms something there actually starts Clivly — and on Next.js
|
|
291
303
|
below 15, that `experimental.instrumentationHook` is set in `next.config`,
|
package/core-auth-adapter.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
3
2
|
const require_auth_adapter = require("./auth-adapter-CiEXcweZ.cjs");
|
|
3
|
+
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
4
4
|
require("./internal-auth-adapter.cjs");
|
|
5
5
|
//#region src/core-auth-adapter.ts
|
|
6
6
|
require_deprecate_subpath.warnDeprecatedSubpath("clivly/core/auth-adapter", "clivly/internal/auth-adapter");
|
package/core-auth-adapter.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
2
1
|
import { t as authCustom } from "./auth-adapter-gfVDxf3d.mjs";
|
|
2
|
+
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
3
3
|
import "./internal-auth-adapter.mjs";
|
|
4
4
|
//#region src/core-auth-adapter.ts
|
|
5
5
|
warnDeprecatedSubpath("clivly/core/auth-adapter", "clivly/internal/auth-adapter");
|
package/core-drizzle.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
3
|
-
const require_drizzle = require("./drizzle-
|
|
3
|
+
const require_drizzle = require("./drizzle-DcB7OfBp.cjs");
|
|
4
4
|
require("./internal-drizzle.cjs");
|
|
5
5
|
//#region src/core-drizzle.ts
|
|
6
6
|
require_deprecate_subpath.warnDeprecatedSubpath("clivly/core/drizzle", "clivly/internal/drizzle");
|
package/core-drizzle.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-
|
|
1
|
+
import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-ixVV4pPN.cjs";
|
|
2
2
|
import "./internal-drizzle.cjs";
|
|
3
3
|
export { buildColumnsMeta, buildUniqueConstraints, discoverFromDrizzle };
|
package/core-drizzle.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-
|
|
1
|
+
import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-BmDDgAIF.mjs";
|
|
2
2
|
import "./internal-drizzle.mjs";
|
|
3
3
|
export { buildColumnsMeta, buildUniqueConstraints, discoverFromDrizzle };
|
package/core-drizzle.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
2
|
-
import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-
|
|
2
|
+
import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-wbcuG-cy.mjs";
|
|
3
3
|
import "./internal-drizzle.mjs";
|
|
4
4
|
//#region src/core-drizzle.ts
|
|
5
5
|
warnDeprecatedSubpath("clivly/core/drizzle", "clivly/internal/drizzle");
|
package/core-entity-config.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_entity_config = require("./entity-config-
|
|
2
|
+
const require_entity_config = require("./entity-config-CPM-Tp-d.cjs");
|
|
3
3
|
//#region src/core-entity-config.ts
|
|
4
4
|
require("./deprecate-subpath-B9ngvizt.cjs").warnDeprecatedSubpath("clivly/core/entity-config", "clivly/internal/entity-config");
|
|
5
5
|
//#endregion
|
package/core-entity-config.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as MATERIALIZING_CONCEPTS, c as entitiesConfigSchema, d as relationshipSchema, f as relationshipsSchema, i as ClivlyConfigError, l as filterSchema, n as CRM_CONCEPTS, o as customObjectDeclarations, p as validateEntitiesConfig, r as CUSTOM_CONCEPT, s as defineClivlyConfig, t as CANONICAL_FIELDS, u as projectionFields } from "./entity-config-
|
|
1
|
+
import { a as MATERIALIZING_CONCEPTS, c as entitiesConfigSchema, d as relationshipSchema, f as relationshipsSchema, i as ClivlyConfigError, l as filterSchema, n as CRM_CONCEPTS, o as customObjectDeclarations, p as validateEntitiesConfig, r as CUSTOM_CONCEPT, s as defineClivlyConfig, t as CANONICAL_FIELDS, u as projectionFields } from "./entity-config-C8IIkrmX.mjs";
|
|
2
2
|
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
3
3
|
//#region src/core-entity-config.ts
|
|
4
4
|
warnDeprecatedSubpath("clivly/core/entity-config", "clivly/internal/entity-config");
|
package/core-mapping-form.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
3
2
|
const require_mapping_form = require("./mapping-form-BpfON_ME.cjs");
|
|
3
|
+
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
4
4
|
require("./internal-mapping-form.cjs");
|
|
5
5
|
//#region src/core-mapping-form.ts
|
|
6
6
|
require_deprecate_subpath.warnDeprecatedSubpath("clivly/core/mapping-form", "clivly/internal/mapping-form");
|
package/core-mapping-form.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
2
1
|
import { n as buildRelationships, r as relationshipViaSignature, t as buildFilterFromDiscriminator } from "./mapping-form-DigkuvFc.mjs";
|
|
2
|
+
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
3
3
|
import "./internal-mapping-form.mjs";
|
|
4
4
|
//#region src/core-mapping-form.ts
|
|
5
5
|
warnDeprecatedSubpath("clivly/core/mapping-form", "clivly/internal/mapping-form");
|
package/core-mappings-config.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_mappings_config = require("./mappings-config-
|
|
2
|
+
const require_mappings_config = require("./mappings-config-CBwL3FVh.cjs");
|
|
3
3
|
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
4
4
|
require("./internal-mappings-config.cjs");
|
|
5
5
|
//#region src/core-mappings-config.ts
|
package/core-mappings-config.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as mappingsToEntitiesConfig, t as entitiesToMappings } from "./mappings-config-
|
|
1
|
+
import { n as mappingsToEntitiesConfig, t as entitiesToMappings } from "./mappings-config-DUKBe6OS.mjs";
|
|
2
2
|
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
3
3
|
import "./internal-mappings-config.mjs";
|
|
4
4
|
//#region src/core-mappings-config.ts
|
package/core-sync-engine.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
3
2
|
const require_sync_engine = require("./sync-engine-BLgwLpR6.cjs");
|
|
3
|
+
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
4
4
|
require("./internal-sync-engine.cjs");
|
|
5
5
|
//#region src/core-sync-engine.ts
|
|
6
6
|
require_deprecate_subpath.warnDeprecatedSubpath("clivly/core/sync-engine", "clivly/internal/sync-engine");
|
package/core-sync-engine.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
2
1
|
import { i as runSync, n as previewSync, r as reconcile, t as computeSampleWarnings } from "./sync-engine-B_IzoUSx.mjs";
|
|
2
|
+
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
3
3
|
import "./internal-sync-engine.mjs";
|
|
4
4
|
//#region src/core-sync-engine.ts
|
|
5
5
|
warnDeprecatedSubpath("clivly/core/sync-engine", "clivly/internal/sync-engine");
|
package/core-view-compiler.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
3
2
|
const require_view_compiler = require("./view-compiler-BHI5E4QI.cjs");
|
|
3
|
+
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
4
4
|
require("./internal-view-compiler.cjs");
|
|
5
5
|
//#region src/core-view-compiler.ts
|
|
6
6
|
require_deprecate_subpath.warnDeprecatedSubpath("clivly/core/view-compiler", "clivly/internal/view-compiler");
|
package/core-view-compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
2
1
|
import { a as explainViewExecutionError, i as explainEntitiesConfig, n as compileEntityView, r as compileEntityViews, t as DEFAULT_VIEW_PREFIX } from "./view-compiler-D_6gfXFr.mjs";
|
|
2
|
+
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
3
3
|
import "./internal-view-compiler.mjs";
|
|
4
4
|
//#region src/core-view-compiler.ts
|
|
5
5
|
warnDeprecatedSubpath("clivly/core/view-compiler", "clivly/internal/view-compiler");
|
package/core.cjs
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_projection = require("./projection-DEwL-D8R.cjs");
|
|
3
|
-
const require_entity_config = require("./entity-config-
|
|
4
|
-
const require_mappings_config = require("./mappings-config-
|
|
5
|
-
const require_deprecate_subpath = require("./deprecate-subpath-B9ngvizt.cjs");
|
|
3
|
+
const require_entity_config = require("./entity-config-CPM-Tp-d.cjs");
|
|
4
|
+
const require_mappings_config = require("./mappings-config-CBwL3FVh.cjs");
|
|
6
5
|
const require_auth_adapter = require("./auth-adapter-CiEXcweZ.cjs");
|
|
7
6
|
const require_mapping_form = require("./mapping-form-BpfON_ME.cjs");
|
|
8
|
-
const require_internal = require("./internal-
|
|
7
|
+
const require_internal = require("./internal-BLKMnIIZ.cjs");
|
|
9
8
|
const require_projection_sql = require("./projection-sql-iHy-Cx6V.cjs");
|
|
10
9
|
const require_view_compiler = require("./view-compiler-BHI5E4QI.cjs");
|
|
11
10
|
const require_sync_engine = require("./sync-engine-BLgwLpR6.cjs");
|
|
12
11
|
//#region src/core.ts
|
|
13
|
-
|
|
12
|
+
require("./deprecate-subpath-B9ngvizt.cjs").warnDeprecatedSubpath("clivly/core", "clivly/sdk", "Import \"defineClivlyConfig\" and its config types from \"clivly/sdk\"; import everything else from \"clivly/internal\" (no stability guarantee — see STABILITY.md).");
|
|
14
13
|
//#endregion
|
|
15
14
|
exports.BASE_REF = require_projection.BASE_REF;
|
|
16
15
|
exports.CANONICAL_FIELDS = require_entity_config.CANONICAL_FIELDS;
|
package/core.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { a as projectionSchema, i as identityRefs, t as BASE_REF } from "./projection-hnPSgH6G.mjs";
|
|
2
|
-
import { _ as columnMetaFor, a as MATERIALIZING_CONCEPTS, b as primaryKeyColumns, c as entitiesConfigSchema, d as relationshipSchema, f as relationshipsSchema, g as joinFansOut, h as fanOutJoins, i as ClivlyConfigError, l as filterSchema, m as validateProjection, n as CRM_CONCEPTS, p as validateEntitiesConfig, s as defineClivlyConfig, t as CANONICAL_FIELDS, v as coversUniqueKey, y as hasRichMeta } from "./entity-config-
|
|
3
|
-
import { n as mappingsToEntitiesConfig } from "./mappings-config-
|
|
4
|
-
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
2
|
+
import { _ as columnMetaFor, a as MATERIALIZING_CONCEPTS, b as primaryKeyColumns, c as entitiesConfigSchema, d as relationshipSchema, f as relationshipsSchema, g as joinFansOut, h as fanOutJoins, i as ClivlyConfigError, l as filterSchema, m as validateProjection, n as CRM_CONCEPTS, p as validateEntitiesConfig, s as defineClivlyConfig, t as CANONICAL_FIELDS, v as coversUniqueKey, y as hasRichMeta } from "./entity-config-C8IIkrmX.mjs";
|
|
3
|
+
import { n as mappingsToEntitiesConfig } from "./mappings-config-DUKBe6OS.mjs";
|
|
5
4
|
import { t as authCustom } from "./auth-adapter-gfVDxf3d.mjs";
|
|
6
5
|
import { n as buildRelationships, r as relationshipViaSignature, t as buildFilterFromDiscriminator } from "./mapping-form-DigkuvFc.mjs";
|
|
7
|
-
import { a as draftToProjection, c as suggestJoinConditions, i as draftRefOptions, n as describeCardinality, o as emptyProjectionDraft, r as draftErrors, s as removeDraftJoin, t as addDraftJoin } from "./internal-
|
|
6
|
+
import { a as draftToProjection, c as suggestJoinConditions, i as draftRefOptions, n as describeCardinality, o as emptyProjectionDraft, r as draftErrors, s as removeDraftJoin, t as addDraftJoin } from "./internal-BpVh_J77.mjs";
|
|
8
7
|
import { a as compileProjectionPreview, i as compileProjectionJoins, n as compileProjectionFrom, o as compileProjectionSelect, r as compileProjectionIdentity, s as quoteIdent, t as PREVIEW_MAX_ROWS } from "./projection-sql-9zzTVGvf.mjs";
|
|
9
8
|
import { i as explainEntitiesConfig, n as compileEntityView, r as compileEntityViews, t as DEFAULT_VIEW_PREFIX } from "./view-compiler-D_6gfXFr.mjs";
|
|
10
9
|
import { i as runSync, r as reconcile } from "./sync-engine-B_IzoUSx.mjs";
|
|
10
|
+
import { t as warnDeprecatedSubpath } from "./deprecate-subpath-CmvZtCpE.mjs";
|
|
11
11
|
//#region src/core.ts
|
|
12
12
|
warnDeprecatedSubpath("clivly/core", "clivly/sdk", "Import \"defineClivlyConfig\" and its config types from \"clivly/sdk\"; import everything else from \"clivly/internal\" (no stability guarantee — see STABILITY.md).");
|
|
13
13
|
//#endregion
|
|
@@ -36,6 +36,8 @@ declare function buildColumnsMeta(table: Table): DiscoveredColumnMeta[];
|
|
|
36
36
|
* when you import this entry (`@clivly/core/drizzle`); the rest of `@clivly/core`
|
|
37
37
|
* stays dependency-free.
|
|
38
38
|
*/
|
|
39
|
-
declare function discoverFromDrizzle(schema: Record<string, unknown
|
|
39
|
+
declare function discoverFromDrizzle(schema: Record<string, unknown>, options?: {
|
|
40
|
+
allowEmpty?: boolean;
|
|
41
|
+
}): DiscoveredSchemaTable[];
|
|
40
42
|
//#endregion
|
|
41
43
|
export { buildUniqueConstraints as n, discoverFromDrizzle as r, buildColumnsMeta as t };
|
|
@@ -91,7 +91,7 @@ function buildColumnsMeta(table) {
|
|
|
91
91
|
* when you import this entry (`@clivly/core/drizzle`); the rest of `@clivly/core`
|
|
92
92
|
* stays dependency-free.
|
|
93
93
|
*/
|
|
94
|
-
function discoverFromDrizzle(schema) {
|
|
94
|
+
function discoverFromDrizzle(schema, options = {}) {
|
|
95
95
|
const tables = [];
|
|
96
96
|
for (const value of Object.values(schema)) {
|
|
97
97
|
if (!(0, drizzle_orm.is)(value, drizzle_orm.Table)) continue;
|
|
@@ -104,8 +104,16 @@ function discoverFromDrizzle(schema) {
|
|
|
104
104
|
...uniqueConstraints === void 0 ? {} : { uniqueConstraints }
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
|
+
if (tables.length === 0 && !options.allowEmpty) throw new Error(`discoverFromDrizzle: found no Drizzle tables in the object it was given (${describeKeys(schema)}). Import the schema module's tables directly — \`import * as schema from "./db/schema"\` — rather than a barrel or a default export, which can collapse to \`{ default }\` under ESM/CJS interop. Pass { allowEmpty: true } if an empty schema is genuinely intended.`);
|
|
107
108
|
return tables;
|
|
108
109
|
}
|
|
110
|
+
/** The keys actually present, so the message names what was handed over. */
|
|
111
|
+
function describeKeys(schema) {
|
|
112
|
+
const keys = Object.keys(schema);
|
|
113
|
+
if (keys.length === 0) return "it was empty";
|
|
114
|
+
const shown = keys.slice(0, 5).join(", ");
|
|
115
|
+
return keys.length > 5 ? `keys: ${shown}, +${keys.length - 5} more` : `keys: ${shown}`;
|
|
116
|
+
}
|
|
109
117
|
//#endregion
|
|
110
118
|
Object.defineProperty(exports, "buildColumnsMeta", {
|
|
111
119
|
enumerable: true,
|
|
@@ -36,6 +36,8 @@ declare function buildColumnsMeta(table: Table): DiscoveredColumnMeta[];
|
|
|
36
36
|
* when you import this entry (`@clivly/core/drizzle`); the rest of `@clivly/core`
|
|
37
37
|
* stays dependency-free.
|
|
38
38
|
*/
|
|
39
|
-
declare function discoverFromDrizzle(schema: Record<string, unknown
|
|
39
|
+
declare function discoverFromDrizzle(schema: Record<string, unknown>, options?: {
|
|
40
|
+
allowEmpty?: boolean;
|
|
41
|
+
}): DiscoveredSchemaTable[];
|
|
40
42
|
//#endregion
|
|
41
43
|
export { buildUniqueConstraints as n, discoverFromDrizzle as r, buildColumnsMeta as t };
|
|
@@ -91,7 +91,7 @@ function buildColumnsMeta(table) {
|
|
|
91
91
|
* when you import this entry (`@clivly/core/drizzle`); the rest of `@clivly/core`
|
|
92
92
|
* stays dependency-free.
|
|
93
93
|
*/
|
|
94
|
-
function discoverFromDrizzle(schema) {
|
|
94
|
+
function discoverFromDrizzle(schema, options = {}) {
|
|
95
95
|
const tables = [];
|
|
96
96
|
for (const value of Object.values(schema)) {
|
|
97
97
|
if (!is(value, Table)) continue;
|
|
@@ -104,7 +104,15 @@ function discoverFromDrizzle(schema) {
|
|
|
104
104
|
...uniqueConstraints === void 0 ? {} : { uniqueConstraints }
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
|
+
if (tables.length === 0 && !options.allowEmpty) throw new Error(`discoverFromDrizzle: found no Drizzle tables in the object it was given (${describeKeys(schema)}). Import the schema module's tables directly — \`import * as schema from "./db/schema"\` — rather than a barrel or a default export, which can collapse to \`{ default }\` under ESM/CJS interop. Pass { allowEmpty: true } if an empty schema is genuinely intended.`);
|
|
107
108
|
return tables;
|
|
108
109
|
}
|
|
110
|
+
/** The keys actually present, so the message names what was handed over. */
|
|
111
|
+
function describeKeys(schema) {
|
|
112
|
+
const keys = Object.keys(schema);
|
|
113
|
+
if (keys.length === 0) return "it was empty";
|
|
114
|
+
const shown = keys.slice(0, 5).join(", ");
|
|
115
|
+
return keys.length > 5 ? `keys: ${shown}, +${keys.length - 5} more` : `keys: ${shown}`;
|
|
116
|
+
}
|
|
109
117
|
//#endregion
|
|
110
118
|
export { buildUniqueConstraints as n, discoverFromDrizzle as r, buildColumnsMeta as t };
|
package/drizzle.cjs
CHANGED
|
@@ -2,22 +2,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_projection = require("./projection-DEwL-D8R.cjs");
|
|
3
3
|
const require_drizzle_meta = require("./drizzle-meta-Bb1JWYqf.cjs");
|
|
4
4
|
const require_projection_sql = require("./projection-sql-iHy-Cx6V.cjs");
|
|
5
|
-
const require_drizzle = require("./drizzle-
|
|
5
|
+
const require_drizzle = require("./drizzle-DcB7OfBp.cjs");
|
|
6
6
|
let drizzle_orm = require("drizzle-orm");
|
|
7
|
-
//#region ../sdk/src/projection-preview.ts
|
|
8
|
-
/** `db.execute` returns either an array or `{ rows }`, depending on driver. */
|
|
9
|
-
function rowsOf(result) {
|
|
10
|
-
if (Array.isArray(result)) return result;
|
|
11
|
-
const rows = result.rows;
|
|
12
|
-
if (Array.isArray(rows)) return rows;
|
|
13
|
-
throw new Error("previewProjection: db.execute() returned neither an array of rows nor { rows }.");
|
|
14
|
-
}
|
|
15
|
-
async function previewProjection(db, projection, opts) {
|
|
16
|
-
const client = db;
|
|
17
|
-
const { sql } = await import("drizzle-orm");
|
|
18
|
-
return rowsOf(await client.execute(sql.raw(require_projection_sql.compileProjectionPreview(projection, opts.limit))));
|
|
19
|
-
}
|
|
20
|
-
//#endregion
|
|
21
7
|
//#region ../sdk/src/drizzle-projection.ts
|
|
22
8
|
/** `<ref>.<column>` — the token `fields` carries and cloud-ingest reads. */
|
|
23
9
|
function refToken(ref) {
|
|
@@ -54,10 +40,12 @@ function fromDrizzleProjection(db, projection, opts) {
|
|
|
54
40
|
const client = db;
|
|
55
41
|
const known = /* @__PURE__ */ new Set([require_projection.BASE_REF, ...projection.joins.map((j) => j.key)]);
|
|
56
42
|
if (projection.identity.kind === "base_pk" && projection.identity.column === void 0 && opts.basePkColumn === void 0) throw new Error(`fromDrizzleProjection: projection "${projection.entityKey}" has a base_pk identity with no column — pass { basePkColumn }.`);
|
|
57
|
-
const cursorRef = parseRef(opts.cursorField);
|
|
58
|
-
assertKnownRef(cursorRef, known, "cursorField");
|
|
59
43
|
for (const [field, binding] of Object.entries(projection.fieldBindings)) assertKnownRef(binding.from, known, `field "${field}"`);
|
|
60
44
|
const identityExpr = require_projection_sql.compileProjectionIdentity(projection, opts.basePkColumn ?? "");
|
|
45
|
+
const fromClause = [require_projection_sql.compileProjectionFrom(projection), ...require_projection_sql.compileProjectionJoins(projection)].join(" ");
|
|
46
|
+
if (opts.cursorField === void 0) return fromDrizzleProjectionByIdentity(client, projection, identityExpr, fromClause, opts);
|
|
47
|
+
const cursorRef = parseRef(opts.cursorField);
|
|
48
|
+
assertKnownRef(cursorRef, known, "cursorField");
|
|
61
49
|
const cursorToken = refToken(cursorRef);
|
|
62
50
|
const cursorExpr = `CAST(${refSql(cursorRef)} AS timestamptz)`;
|
|
63
51
|
const cursorRead = `to_char(${cursorExpr} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')`;
|
|
@@ -69,11 +57,7 @@ function fromDrizzleProjection(db, projection, opts) {
|
|
|
69
57
|
emitted.add(token);
|
|
70
58
|
selectItems.push(`${refSql(binding.from)} AS ${require_projection_sql.quoteIdent(token)}`);
|
|
71
59
|
}
|
|
72
|
-
const head = [
|
|
73
|
-
`select ${selectItems.join(", ")}`,
|
|
74
|
-
require_projection_sql.compileProjectionFrom(projection),
|
|
75
|
-
...require_projection_sql.compileProjectionJoins(projection)
|
|
76
|
-
].join(" ");
|
|
60
|
+
const head = [`select ${selectItems.join(", ")}`, fromClause].join(" ");
|
|
77
61
|
return {
|
|
78
62
|
entity: opts.entity,
|
|
79
63
|
cursorField: cursorToken,
|
|
@@ -86,6 +70,49 @@ function fromDrizzleProjection(db, projection, opts) {
|
|
|
86
70
|
}
|
|
87
71
|
};
|
|
88
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* The identity-only paging path `fromDrizzleProjection` takes when
|
|
75
|
+
* `cursorField` is omitted. Deliberately not a generalisation of the
|
|
76
|
+
* timestamp path above — it selects no timestamp cursor, pages on the
|
|
77
|
+
* identity expression alone, and always reports `cursorField`/`idField` as
|
|
78
|
+
* `"id"`, the alias every row carries either way.
|
|
79
|
+
*/
|
|
80
|
+
function fromDrizzleProjectionByIdentity(client, projection, identityExpr, fromClause, opts) {
|
|
81
|
+
const selectItems = [`${identityExpr} AS ${require_projection_sql.quoteIdent("id")}`];
|
|
82
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
83
|
+
for (const binding of Object.values(projection.fieldBindings)) {
|
|
84
|
+
const token = refToken(binding.from);
|
|
85
|
+
if (emitted.has(token)) continue;
|
|
86
|
+
emitted.add(token);
|
|
87
|
+
selectItems.push(`${refSql(binding.from)} AS ${require_projection_sql.quoteIdent(token)}`);
|
|
88
|
+
}
|
|
89
|
+
const head = [`select ${selectItems.join(", ")}`, fromClause].join(" ");
|
|
90
|
+
return {
|
|
91
|
+
entity: opts.entity,
|
|
92
|
+
cursorField: "id",
|
|
93
|
+
idField: "id",
|
|
94
|
+
...opts.objectType === void 0 ? {} : { objectType: opts.objectType },
|
|
95
|
+
fetchPage: async ({ since, limit }) => {
|
|
96
|
+
const where = since ? drizzle_orm.sql` where ${drizzle_orm.sql.raw(identityExpr)} > ${since.id}` : drizzle_orm.sql``;
|
|
97
|
+
const query = drizzle_orm.sql`${drizzle_orm.sql.raw(head)}${where} order by ${drizzle_orm.sql.raw(identityExpr)} asc limit ${limit}`;
|
|
98
|
+
return normalizeRows(await client.execute(query));
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region ../sdk/src/projection-preview.ts
|
|
104
|
+
/** `db.execute` returns either an array or `{ rows }`, depending on driver. */
|
|
105
|
+
function rowsOf(result) {
|
|
106
|
+
if (Array.isArray(result)) return result;
|
|
107
|
+
const rows = result.rows;
|
|
108
|
+
if (Array.isArray(rows)) return rows;
|
|
109
|
+
throw new Error("previewProjection: db.execute() returned neither an array of rows nor { rows }.");
|
|
110
|
+
}
|
|
111
|
+
async function previewProjection(db, projection, opts) {
|
|
112
|
+
const client = db;
|
|
113
|
+
const { sql } = await import("drizzle-orm");
|
|
114
|
+
return rowsOf(await client.execute(sql.raw(require_projection_sql.compileProjectionPreview(projection, opts.limit))));
|
|
115
|
+
}
|
|
89
116
|
//#endregion
|
|
90
117
|
//#region ../sdk/src/drizzle.ts
|
|
91
118
|
function inferIdField(table) {
|
|
@@ -152,6 +179,13 @@ function drizzleIntrospector(db) {
|
|
|
152
179
|
},
|
|
153
180
|
runProjection(projection, opts) {
|
|
154
181
|
return previewProjection(db, projection, opts);
|
|
182
|
+
},
|
|
183
|
+
projectionSource(projection, opts) {
|
|
184
|
+
return fromDrizzleProjection(db, projection, {
|
|
185
|
+
entity: opts.objectType,
|
|
186
|
+
objectType: opts.objectType,
|
|
187
|
+
...opts.basePkColumn ? { basePkColumn: opts.basePkColumn } : {}
|
|
188
|
+
});
|
|
155
189
|
}
|
|
156
190
|
};
|
|
157
191
|
}
|
package/drizzle.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { F as ProjectionRef, P as ProjectionMapping } from "./entity-config-B2RA53nw.cjs";
|
|
2
|
-
import { n as buildUniqueConstraints, r as discoverFromDrizzle } from "./drizzle-
|
|
3
|
-
import {
|
|
2
|
+
import { n as buildUniqueConstraints, r as discoverFromDrizzle } from "./drizzle-ixVV4pPN.cjs";
|
|
3
|
+
import { t as NamespaceIntrospector, v as SyncSource } from "./namespace-probe-DZIGdvlm.cjs";
|
|
4
4
|
import { Table } from "drizzle-orm";
|
|
5
5
|
//#region ../sdk/src/drizzle-projection.d.ts
|
|
6
6
|
/**
|
|
@@ -37,8 +37,14 @@ interface FromDrizzleProjectionOptions {
|
|
|
37
37
|
* The column to keyset-paginate on, as a ref token (`"base.updated_at"`) or
|
|
38
38
|
* a `ProjectionRef`. A projection spans several tables, so there is no
|
|
39
39
|
* single table to infer a cursor from.
|
|
40
|
+
*
|
|
41
|
+
* Omit it to page by identity alone — the mode a dashboard-authored
|
|
42
|
+
* projection uses, since it has no timestamp column and no UI to nominate
|
|
43
|
+
* one. `checkIdentitySafety` (`@clivly/core`) already proves the identity
|
|
44
|
+
* uniquely identifies a row, which makes it a sound keyset cursor with no
|
|
45
|
+
* timestamp involved.
|
|
40
46
|
*/
|
|
41
|
-
cursorField
|
|
47
|
+
cursorField?: string | ProjectionRef;
|
|
42
48
|
/** The source name rows are pushed under. */
|
|
43
49
|
entity: string;
|
|
44
50
|
/**
|
package/drizzle.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { F as ProjectionRef, P as ProjectionMapping } from "./entity-config-B2RA53nw.mjs";
|
|
2
|
-
import { n as buildUniqueConstraints, r as discoverFromDrizzle } from "./drizzle-
|
|
3
|
-
import {
|
|
2
|
+
import { n as buildUniqueConstraints, r as discoverFromDrizzle } from "./drizzle-BmDDgAIF.mjs";
|
|
3
|
+
import { t as NamespaceIntrospector, v as SyncSource } from "./namespace-probe-BQ4imnV7.mjs";
|
|
4
4
|
import { Table } from "drizzle-orm";
|
|
5
5
|
//#region ../sdk/src/drizzle-projection.d.ts
|
|
6
6
|
/**
|
|
@@ -37,8 +37,14 @@ interface FromDrizzleProjectionOptions {
|
|
|
37
37
|
* The column to keyset-paginate on, as a ref token (`"base.updated_at"`) or
|
|
38
38
|
* a `ProjectionRef`. A projection spans several tables, so there is no
|
|
39
39
|
* single table to infer a cursor from.
|
|
40
|
+
*
|
|
41
|
+
* Omit it to page by identity alone — the mode a dashboard-authored
|
|
42
|
+
* projection uses, since it has no timestamp column and no UI to nominate
|
|
43
|
+
* one. `checkIdentitySafety` (`@clivly/core`) already proves the identity
|
|
44
|
+
* uniquely identifies a row, which makes it a sound keyset cursor with no
|
|
45
|
+
* timestamp involved.
|
|
40
46
|
*/
|
|
41
|
-
cursorField
|
|
47
|
+
cursorField?: string | ProjectionRef;
|
|
42
48
|
/** The source name rows are pushed under. */
|
|
43
49
|
entity: string;
|
|
44
50
|
/**
|
package/drizzle.mjs
CHANGED
|
@@ -1,22 +1,8 @@
|
|
|
1
1
|
import { t as BASE_REF } from "./projection-hnPSgH6G.mjs";
|
|
2
2
|
import { t as DRIZZLE_META } from "./drizzle-meta-D-5k3n0i.mjs";
|
|
3
3
|
import { a as compileProjectionPreview, i as compileProjectionJoins, n as compileProjectionFrom, r as compileProjectionIdentity, s as quoteIdent } from "./projection-sql-9zzTVGvf.mjs";
|
|
4
|
-
import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-
|
|
4
|
+
import { n as buildUniqueConstraints, r as discoverFromDrizzle, t as buildColumnsMeta } from "./drizzle-wbcuG-cy.mjs";
|
|
5
5
|
import { asc, getTableColumns, getTableName, sql } from "drizzle-orm";
|
|
6
|
-
//#region ../sdk/src/projection-preview.ts
|
|
7
|
-
/** `db.execute` returns either an array or `{ rows }`, depending on driver. */
|
|
8
|
-
function rowsOf(result) {
|
|
9
|
-
if (Array.isArray(result)) return result;
|
|
10
|
-
const rows = result.rows;
|
|
11
|
-
if (Array.isArray(rows)) return rows;
|
|
12
|
-
throw new Error("previewProjection: db.execute() returned neither an array of rows nor { rows }.");
|
|
13
|
-
}
|
|
14
|
-
async function previewProjection(db, projection, opts) {
|
|
15
|
-
const client = db;
|
|
16
|
-
const { sql } = await import("drizzle-orm");
|
|
17
|
-
return rowsOf(await client.execute(sql.raw(compileProjectionPreview(projection, opts.limit))));
|
|
18
|
-
}
|
|
19
|
-
//#endregion
|
|
20
6
|
//#region ../sdk/src/drizzle-projection.ts
|
|
21
7
|
/** `<ref>.<column>` — the token `fields` carries and cloud-ingest reads. */
|
|
22
8
|
function refToken(ref) {
|
|
@@ -53,10 +39,12 @@ function fromDrizzleProjection(db, projection, opts) {
|
|
|
53
39
|
const client = db;
|
|
54
40
|
const known = /* @__PURE__ */ new Set([BASE_REF, ...projection.joins.map((j) => j.key)]);
|
|
55
41
|
if (projection.identity.kind === "base_pk" && projection.identity.column === void 0 && opts.basePkColumn === void 0) throw new Error(`fromDrizzleProjection: projection "${projection.entityKey}" has a base_pk identity with no column — pass { basePkColumn }.`);
|
|
56
|
-
const cursorRef = parseRef(opts.cursorField);
|
|
57
|
-
assertKnownRef(cursorRef, known, "cursorField");
|
|
58
42
|
for (const [field, binding] of Object.entries(projection.fieldBindings)) assertKnownRef(binding.from, known, `field "${field}"`);
|
|
59
43
|
const identityExpr = compileProjectionIdentity(projection, opts.basePkColumn ?? "");
|
|
44
|
+
const fromClause = [compileProjectionFrom(projection), ...compileProjectionJoins(projection)].join(" ");
|
|
45
|
+
if (opts.cursorField === void 0) return fromDrizzleProjectionByIdentity(client, projection, identityExpr, fromClause, opts);
|
|
46
|
+
const cursorRef = parseRef(opts.cursorField);
|
|
47
|
+
assertKnownRef(cursorRef, known, "cursorField");
|
|
60
48
|
const cursorToken = refToken(cursorRef);
|
|
61
49
|
const cursorExpr = `CAST(${refSql(cursorRef)} AS timestamptz)`;
|
|
62
50
|
const cursorRead = `to_char(${cursorExpr} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')`;
|
|
@@ -68,11 +56,7 @@ function fromDrizzleProjection(db, projection, opts) {
|
|
|
68
56
|
emitted.add(token);
|
|
69
57
|
selectItems.push(`${refSql(binding.from)} AS ${quoteIdent(token)}`);
|
|
70
58
|
}
|
|
71
|
-
const head = [
|
|
72
|
-
`select ${selectItems.join(", ")}`,
|
|
73
|
-
compileProjectionFrom(projection),
|
|
74
|
-
...compileProjectionJoins(projection)
|
|
75
|
-
].join(" ");
|
|
59
|
+
const head = [`select ${selectItems.join(", ")}`, fromClause].join(" ");
|
|
76
60
|
return {
|
|
77
61
|
entity: opts.entity,
|
|
78
62
|
cursorField: cursorToken,
|
|
@@ -85,6 +69,49 @@ function fromDrizzleProjection(db, projection, opts) {
|
|
|
85
69
|
}
|
|
86
70
|
};
|
|
87
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* The identity-only paging path `fromDrizzleProjection` takes when
|
|
74
|
+
* `cursorField` is omitted. Deliberately not a generalisation of the
|
|
75
|
+
* timestamp path above — it selects no timestamp cursor, pages on the
|
|
76
|
+
* identity expression alone, and always reports `cursorField`/`idField` as
|
|
77
|
+
* `"id"`, the alias every row carries either way.
|
|
78
|
+
*/
|
|
79
|
+
function fromDrizzleProjectionByIdentity(client, projection, identityExpr, fromClause, opts) {
|
|
80
|
+
const selectItems = [`${identityExpr} AS ${quoteIdent("id")}`];
|
|
81
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
82
|
+
for (const binding of Object.values(projection.fieldBindings)) {
|
|
83
|
+
const token = refToken(binding.from);
|
|
84
|
+
if (emitted.has(token)) continue;
|
|
85
|
+
emitted.add(token);
|
|
86
|
+
selectItems.push(`${refSql(binding.from)} AS ${quoteIdent(token)}`);
|
|
87
|
+
}
|
|
88
|
+
const head = [`select ${selectItems.join(", ")}`, fromClause].join(" ");
|
|
89
|
+
return {
|
|
90
|
+
entity: opts.entity,
|
|
91
|
+
cursorField: "id",
|
|
92
|
+
idField: "id",
|
|
93
|
+
...opts.objectType === void 0 ? {} : { objectType: opts.objectType },
|
|
94
|
+
fetchPage: async ({ since, limit }) => {
|
|
95
|
+
const where = since ? sql` where ${sql.raw(identityExpr)} > ${since.id}` : sql``;
|
|
96
|
+
const query = sql`${sql.raw(head)}${where} order by ${sql.raw(identityExpr)} asc limit ${limit}`;
|
|
97
|
+
return normalizeRows(await client.execute(query));
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region ../sdk/src/projection-preview.ts
|
|
103
|
+
/** `db.execute` returns either an array or `{ rows }`, depending on driver. */
|
|
104
|
+
function rowsOf(result) {
|
|
105
|
+
if (Array.isArray(result)) return result;
|
|
106
|
+
const rows = result.rows;
|
|
107
|
+
if (Array.isArray(rows)) return rows;
|
|
108
|
+
throw new Error("previewProjection: db.execute() returned neither an array of rows nor { rows }.");
|
|
109
|
+
}
|
|
110
|
+
async function previewProjection(db, projection, opts) {
|
|
111
|
+
const client = db;
|
|
112
|
+
const { sql } = await import("drizzle-orm");
|
|
113
|
+
return rowsOf(await client.execute(sql.raw(compileProjectionPreview(projection, opts.limit))));
|
|
114
|
+
}
|
|
88
115
|
//#endregion
|
|
89
116
|
//#region ../sdk/src/drizzle.ts
|
|
90
117
|
function inferIdField(table) {
|
|
@@ -151,6 +178,13 @@ function drizzleIntrospector(db) {
|
|
|
151
178
|
},
|
|
152
179
|
runProjection(projection, opts) {
|
|
153
180
|
return previewProjection(db, projection, opts);
|
|
181
|
+
},
|
|
182
|
+
projectionSource(projection, opts) {
|
|
183
|
+
return fromDrizzleProjection(db, projection, {
|
|
184
|
+
entity: opts.objectType,
|
|
185
|
+
objectType: opts.objectType,
|
|
186
|
+
...opts.basePkColumn ? { basePkColumn: opts.basePkColumn } : {}
|
|
187
|
+
});
|
|
154
188
|
}
|
|
155
189
|
};
|
|
156
190
|
}
|
|
@@ -137,7 +137,7 @@ function checkTablesExist(errors, projection, resolver, base) {
|
|
|
137
137
|
if (!hasRichMeta(table)) {
|
|
138
138
|
errors.push({
|
|
139
139
|
path,
|
|
140
|
-
message: `table "${name}"
|
|
140
|
+
message: `table "${name}" was discovered without column types or unique keys, which a projection needs to prove its id is unique. Redeploy or restart the app so it re-reports its schema (or run \`clivly push-schema\`); if the table is declared by hand as \`{ name, columns }\`, use \`discoverFromDrizzle\` so keys and types come with it.`
|
|
141
141
|
});
|
|
142
142
|
ok = false;
|
|
143
143
|
}
|
|
@@ -182,10 +182,27 @@ function checkRefs(errors, projection, resolver, base, basePk) {
|
|
|
182
182
|
for (const [field, binding] of Object.entries(projection.fieldBindings)) checkRef(errors, resolver, `${base}.projection.fieldBindings.${field}`, binding.from);
|
|
183
183
|
for (const ref of identityRefs(projection.identity, basePk)) checkRef(errors, resolver, `${base}.projection.identity`, ref);
|
|
184
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Prove that a single-column identity (`column`, or `base_pk` with an
|
|
187
|
+
* explicit column) is actually unique.
|
|
188
|
+
*
|
|
189
|
+
* `coversUniqueKey` fails closed on absent metadata, same as every other
|
|
190
|
+
* check in this file: a column not provably covered by a unique key is
|
|
191
|
+
* rejected, never assumed safe.
|
|
192
|
+
*/
|
|
193
|
+
function checkSingleColumnIdentity(errors, resolver, path, ref) {
|
|
194
|
+
const table = resolver.tableFor(ref.table);
|
|
195
|
+
if (!table) return;
|
|
196
|
+
if (!coversUniqueKey(table, [ref.column])) errors.push({
|
|
197
|
+
path,
|
|
198
|
+
message: `identity column "${ref.table}.${ref.column}" is not covered by a unique key of "${table.name}" — pick a column with a unique constraint, or use a composite identity that is`
|
|
199
|
+
});
|
|
200
|
+
}
|
|
185
201
|
function checkIdentitySafety(errors, projection, resolver, base, baseTable) {
|
|
186
202
|
const path = `${base}.projection.identity`;
|
|
187
203
|
const pk = primaryKeyColumns(baseTable);
|
|
188
|
-
|
|
204
|
+
const { identity } = projection;
|
|
205
|
+
if (identity.kind === "base_pk" && !identity.column) {
|
|
189
206
|
if (pk.length === 0) {
|
|
190
207
|
errors.push({
|
|
191
208
|
path,
|
|
@@ -200,9 +217,21 @@ function checkIdentitySafety(errors, projection, resolver, base, baseTable) {
|
|
|
200
217
|
});
|
|
201
218
|
return;
|
|
202
219
|
}
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (identity.kind === "base_pk" && identity.column) {
|
|
223
|
+
checkSingleColumnIdentity(errors, resolver, path, {
|
|
224
|
+
table: BASE_REF,
|
|
225
|
+
column: identity.column
|
|
226
|
+
});
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (identity.kind === "column") {
|
|
230
|
+
checkSingleColumnIdentity(errors, resolver, path, identity.from);
|
|
231
|
+
return;
|
|
203
232
|
}
|
|
204
|
-
if (
|
|
205
|
-
for (const part of
|
|
233
|
+
if (identity.kind !== "composite") return;
|
|
234
|
+
for (const part of identity.parts) {
|
|
206
235
|
const table = resolver.tableFor(part.table);
|
|
207
236
|
const meta = table && columnMetaFor(table, part.column);
|
|
208
237
|
if (!meta) continue;
|