neoorm 0.7.3 → 0.8.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/README.md +4 -4
- package/dist/bin/neoorm.js +36 -27
- package/dist/bin/neoorm.js.map +1 -1
- package/dist/codegen/diff-manifest.d.ts.map +1 -1
- package/dist/codegen/diff-manifest.js +55 -30
- package/dist/codegen/diff-manifest.js.map +1 -1
- package/dist/codegen/emit-includes.d.ts.map +1 -1
- package/dist/codegen/emit-includes.js +6 -6
- package/dist/codegen/emit-includes.js.map +1 -1
- package/dist/codegen/emit-models.d.ts.map +1 -1
- package/dist/codegen/emit-models.js +14 -14
- package/dist/codegen/emit-models.js.map +1 -1
- package/dist/codegen/generate.d.ts +11 -1
- package/dist/codegen/generate.d.ts.map +1 -1
- package/dist/codegen/generate.js +30 -11
- package/dist/codegen/generate.js.map +1 -1
- package/dist/codegen/manifest-relations.d.ts +2 -1
- package/dist/codegen/manifest-relations.d.ts.map +1 -1
- package/dist/codegen/manifest-relations.js +4 -27
- package/dist/codegen/manifest-relations.js.map +1 -1
- package/dist/codegen/schema-to-manifest.d.ts +3 -2
- package/dist/codegen/schema-to-manifest.d.ts.map +1 -1
- package/dist/codegen/schema-to-manifest.js +9 -38
- package/dist/codegen/schema-to-manifest.js.map +1 -1
- package/dist/config.d.ts +6 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +21 -13
- package/dist/config.js.map +1 -1
- package/dist/datasource-provider.d.ts +7 -0
- package/dist/datasource-provider.d.ts.map +1 -0
- package/dist/datasource-provider.js +11 -0
- package/dist/datasource-provider.js.map +1 -0
- package/dist/dialect/fk.d.ts.map +1 -1
- package/dist/dialect/fk.js +4 -2
- package/dist/dialect/fk.js.map +1 -1
- package/dist/dialect/postgres.d.ts.map +1 -1
- package/dist/dialect/postgres.js +11 -15
- package/dist/dialect/postgres.js.map +1 -1
- package/dist/dialect/shared.d.ts +3 -1
- package/dist/dialect/shared.d.ts.map +1 -1
- package/dist/dialect/shared.js +4 -0
- package/dist/dialect/shared.js.map +1 -1
- package/dist/dialect/sqlite.d.ts.map +1 -1
- package/dist/dialect/sqlite.js +15 -18
- package/dist/dialect/sqlite.js.map +1 -1
- package/dist/dialect/sqlite.test.d.ts +2 -0
- package/dist/dialect/sqlite.test.d.ts.map +1 -0
- package/dist/dialect/sqlite.test.js +122 -0
- package/dist/dialect/sqlite.test.js.map +1 -0
- package/dist/dialect/types.d.ts +2 -1
- package/dist/dialect/types.d.ts.map +1 -1
- package/dist/docs/render.d.ts.map +1 -1
- package/dist/docs/render.js.map +1 -1
- package/dist/docs/search.d.ts.map +1 -1
- package/dist/docs/search.js +4 -4
- package/dist/docs/search.js.map +1 -1
- package/dist/docs/server.d.ts.map +1 -1
- package/dist/docs/server.js +3 -3
- package/dist/docs/server.js.map +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/init/scaffold.d.ts.map +1 -1
- package/dist/init/scaffold.js +3 -1
- package/dist/init/scaffold.js.map +1 -1
- package/dist/introspect/pull.d.ts.map +1 -1
- package/dist/introspect/pull.js +209 -154
- package/dist/introspect/pull.js.map +1 -1
- package/dist/introspect/queries.d.ts +6 -0
- package/dist/introspect/queries.d.ts.map +1 -1
- package/dist/introspect/queries.js +19 -0
- package/dist/introspect/queries.js.map +1 -1
- package/dist/introspect/sqlite/to-manifest.d.ts.map +1 -1
- package/dist/introspect/sqlite/to-manifest.js +6 -9
- package/dist/introspect/sqlite/to-manifest.js.map +1 -1
- package/dist/introspect/to-manifest.d.ts +8 -1
- package/dist/introspect/to-manifest.d.ts.map +1 -1
- package/dist/introspect/to-manifest.js +96 -21
- package/dist/introspect/to-manifest.js.map +1 -1
- package/dist/migrate/runner.d.ts +16 -0
- package/dist/migrate/runner.d.ts.map +1 -1
- package/dist/migrate/runner.js +147 -24
- package/dist/migrate/runner.js.map +1 -1
- package/dist/plugins/builtin.d.ts.map +1 -1
- package/dist/plugins/builtin.js +15 -16
- package/dist/plugins/builtin.js.map +1 -1
- package/dist/plugins/json/operators.d.ts.map +1 -1
- package/dist/plugins/json/operators.js +100 -27
- package/dist/plugins/json/operators.js.map +1 -1
- package/dist/plugins/postgis/columns.d.ts +18 -4
- package/dist/plugins/postgis/columns.d.ts.map +1 -1
- package/dist/plugins/postgis/columns.js +69 -10
- package/dist/plugins/postgis/columns.js.map +1 -1
- package/dist/plugins/postgis/columns.test.d.ts +2 -0
- package/dist/plugins/postgis/columns.test.d.ts.map +1 -0
- package/dist/plugins/postgis/columns.test.js +67 -0
- package/dist/plugins/postgis/columns.test.js.map +1 -0
- package/dist/plugins/postgis/index.d.ts +4 -2
- package/dist/plugins/postgis/index.d.ts.map +1 -1
- package/dist/plugins/postgis/index.js +2 -1
- package/dist/plugins/postgis/index.js.map +1 -1
- package/dist/plugins/postgis/where-types.d.ts +18 -0
- package/dist/plugins/postgis/where-types.d.ts.map +1 -0
- package/dist/plugins/postgis/where-types.js +2 -0
- package/dist/plugins/postgis/where-types.js.map +1 -0
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +20 -5
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/types.d.ts +1 -1
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/runtime/client.d.ts +60 -11
- package/dist/runtime/client.d.ts.map +1 -1
- package/dist/runtime/client.js +85 -39
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/client.test.d.ts +2 -0
- package/dist/runtime/client.test.d.ts.map +1 -0
- package/dist/runtime/client.test.js +170 -0
- package/dist/runtime/client.test.js.map +1 -0
- package/dist/runtime/compile-error.d.ts +14 -0
- package/dist/runtime/compile-error.d.ts.map +1 -0
- package/dist/runtime/compile-error.js +14 -0
- package/dist/runtime/compile-error.js.map +1 -0
- package/dist/runtime/driver-sqlite.test.d.ts +2 -0
- package/dist/runtime/driver-sqlite.test.d.ts.map +1 -0
- package/dist/runtime/driver-sqlite.test.js +195 -0
- package/dist/runtime/driver-sqlite.test.js.map +1 -0
- package/dist/runtime/driver.d.ts +16 -1
- package/dist/runtime/driver.d.ts.map +1 -1
- package/dist/runtime/driver.js +118 -96
- package/dist/runtime/driver.js.map +1 -1
- package/dist/runtime/error-builders.d.ts +7 -6
- package/dist/runtime/error-builders.d.ts.map +1 -1
- package/dist/runtime/error-builders.js +2 -2
- package/dist/runtime/error-builders.js.map +1 -1
- package/dist/runtime/error-codes.d.ts +50 -0
- package/dist/runtime/error-codes.d.ts.map +1 -0
- package/dist/runtime/error-codes.js +54 -0
- package/dist/runtime/error-codes.js.map +1 -0
- package/dist/runtime/error-hints.d.ts +1 -0
- package/dist/runtime/error-hints.d.ts.map +1 -1
- package/dist/runtime/error-hints.js +13 -1
- package/dist/runtime/error-hints.js.map +1 -1
- package/dist/runtime/errors.d.ts +55 -8
- package/dist/runtime/errors.d.ts.map +1 -1
- package/dist/runtime/errors.js +143 -12
- package/dist/runtime/errors.js.map +1 -1
- package/dist/runtime/errors.test.d.ts +2 -0
- package/dist/runtime/errors.test.d.ts.map +1 -0
- package/dist/runtime/errors.test.js +115 -0
- package/dist/runtime/errors.test.js.map +1 -0
- package/dist/runtime/executor.d.ts +22 -3
- package/dist/runtime/executor.d.ts.map +1 -1
- package/dist/runtime/executor.js +93 -39
- package/dist/runtime/executor.js.map +1 -1
- package/dist/runtime/parse-db-json.d.ts +8 -0
- package/dist/runtime/parse-db-json.d.ts.map +1 -0
- package/dist/runtime/parse-db-json.js +33 -0
- package/dist/runtime/parse-db-json.js.map +1 -0
- package/dist/runtime/pg-error.d.ts.map +1 -1
- package/dist/runtime/pg-error.js +16 -16
- package/dist/runtime/pg-error.js.map +1 -1
- package/dist/runtime/pg-rollback.test.d.ts +2 -0
- package/dist/runtime/pg-rollback.test.d.ts.map +1 -0
- package/dist/runtime/pg-rollback.test.js +39 -0
- package/dist/runtime/pg-rollback.test.js.map +1 -0
- package/dist/runtime/query/aggregate.d.ts.map +1 -1
- package/dist/runtime/query/aggregate.js +15 -4
- package/dist/runtime/query/aggregate.js.map +1 -1
- package/dist/runtime/query/compile-aggregate.d.ts +39 -0
- package/dist/runtime/query/compile-aggregate.d.ts.map +1 -0
- package/dist/runtime/query/compile-aggregate.js +456 -0
- package/dist/runtime/query/compile-aggregate.js.map +1 -0
- package/dist/runtime/query/compile-where.d.ts +32 -0
- package/dist/runtime/query/compile-where.d.ts.map +1 -0
- package/dist/runtime/query/compile-where.js +708 -0
- package/dist/runtime/query/compile-where.js.map +1 -0
- package/dist/runtime/query/compile-write.d.ts +53 -0
- package/dist/runtime/query/compile-write.d.ts.map +1 -0
- package/dist/runtime/query/compile-write.js +467 -0
- package/dist/runtime/query/compile-write.js.map +1 -0
- package/dist/runtime/query/compile.d.ts +3 -114
- package/dist/runtime/query/compile.d.ts.map +1 -1
- package/dist/runtime/query/compile.js +3 -1536
- package/dist/runtime/query/compile.js.map +1 -1
- package/dist/runtime/query/count.d.ts +1 -0
- package/dist/runtime/query/count.d.ts.map +1 -1
- package/dist/runtime/query/count.js +12 -14
- package/dist/runtime/query/count.js.map +1 -1
- package/dist/runtime/query/create.d.ts.map +1 -1
- package/dist/runtime/query/create.js +20 -49
- package/dist/runtime/query/create.js.map +1 -1
- package/dist/runtime/query/cursor-codec.d.ts.map +1 -1
- package/dist/runtime/query/cursor-codec.js +8 -2
- package/dist/runtime/query/cursor-codec.js.map +1 -1
- package/dist/runtime/query/cursor.d.ts.map +1 -1
- package/dist/runtime/query/cursor.js +31 -7
- package/dist/runtime/query/cursor.js.map +1 -1
- package/dist/runtime/query/delete.d.ts.map +1 -1
- package/dist/runtime/query/delete.js +17 -17
- package/dist/runtime/query/delete.js.map +1 -1
- package/dist/runtime/query/execute.d.ts.map +1 -1
- package/dist/runtime/query/execute.js +11 -12
- package/dist/runtime/query/execute.js.map +1 -1
- package/dist/runtime/query/find-or-create.d.ts +4 -2
- package/dist/runtime/query/find-or-create.d.ts.map +1 -1
- package/dist/runtime/query/find-or-create.js +53 -43
- package/dist/runtime/query/find-or-create.js.map +1 -1
- package/dist/runtime/query/find-or-create.test.d.ts +2 -0
- package/dist/runtime/query/find-or-create.test.d.ts.map +1 -0
- package/dist/runtime/query/find-or-create.test.js +189 -0
- package/dist/runtime/query/find-or-create.test.js.map +1 -0
- package/dist/runtime/query/find.d.ts.map +1 -1
- package/dist/runtime/query/find.js +86 -58
- package/dist/runtime/query/find.js.map +1 -1
- package/dist/runtime/query/group-by.d.ts.map +1 -1
- package/dist/runtime/query/group-by.js +3 -2
- package/dist/runtime/query/group-by.js.map +1 -1
- package/dist/runtime/query/manifest-lookup.d.ts.map +1 -1
- package/dist/runtime/query/manifest-lookup.js +1 -1
- package/dist/runtime/query/manifest-lookup.js.map +1 -1
- package/dist/runtime/query/map-row.d.ts.map +1 -1
- package/dist/runtime/query/map-row.js +1 -1
- package/dist/runtime/query/map-row.js.map +1 -1
- package/dist/runtime/query/paginate.d.ts +3 -0
- package/dist/runtime/query/paginate.d.ts.map +1 -1
- package/dist/runtime/query/paginate.js +49 -11
- package/dist/runtime/query/paginate.js.map +1 -1
- package/dist/runtime/query/primary-key.d.ts +1 -1
- package/dist/runtime/query/primary-key.d.ts.map +1 -1
- package/dist/runtime/query/primary-key.js +45 -8
- package/dist/runtime/query/primary-key.js.map +1 -1
- package/dist/runtime/query/projection.d.ts +1 -0
- package/dist/runtime/query/projection.d.ts.map +1 -1
- package/dist/runtime/query/projection.js +23 -7
- package/dist/runtime/query/projection.js.map +1 -1
- package/dist/runtime/query/relation-planner.d.ts.map +1 -1
- package/dist/runtime/query/relation-planner.js +82 -53
- package/dist/runtime/query/relation-planner.js.map +1 -1
- package/dist/runtime/query/relation-writes.d.ts +3 -1
- package/dist/runtime/query/relation-writes.d.ts.map +1 -1
- package/dist/runtime/query/relation-writes.js +145 -54
- package/dist/runtime/query/relation-writes.js.map +1 -1
- package/dist/runtime/query/serialize-dialect.test.d.ts +2 -0
- package/dist/runtime/query/serialize-dialect.test.d.ts.map +1 -0
- package/dist/runtime/query/serialize-dialect.test.js +79 -0
- package/dist/runtime/query/serialize-dialect.test.js.map +1 -0
- package/dist/runtime/query/sqlite-constraint-errors.test.d.ts +2 -0
- package/dist/runtime/query/sqlite-constraint-errors.test.d.ts.map +1 -0
- package/dist/runtime/query/sqlite-constraint-errors.test.js +60 -0
- package/dist/runtime/query/sqlite-constraint-errors.test.js.map +1 -0
- package/dist/runtime/query/strip.d.ts.map +1 -1
- package/dist/runtime/query/strip.js.map +1 -1
- package/dist/runtime/query/table-index.d.ts.map +1 -1
- package/dist/runtime/query/table-index.js +4 -3
- package/dist/runtime/query/table-index.js.map +1 -1
- package/dist/runtime/query/unique.d.ts +8 -1
- package/dist/runtime/query/unique.d.ts.map +1 -1
- package/dist/runtime/query/unique.js +89 -4
- package/dist/runtime/query/unique.js.map +1 -1
- package/dist/runtime/query/unique.test.d.ts +2 -0
- package/dist/runtime/query/unique.test.d.ts.map +1 -0
- package/dist/runtime/query/unique.test.js +231 -0
- package/dist/runtime/query/unique.test.js.map +1 -0
- package/dist/runtime/query/update.d.ts.map +1 -1
- package/dist/runtime/query/update.js +30 -35
- package/dist/runtime/query/update.js.map +1 -1
- package/dist/runtime/query/update.test.d.ts +2 -0
- package/dist/runtime/query/update.test.d.ts.map +1 -0
- package/dist/runtime/query/update.test.js +186 -0
- package/dist/runtime/query/update.test.js.map +1 -0
- package/dist/runtime/query/updated-at.d.ts.map +1 -1
- package/dist/runtime/query/updated-at.js.map +1 -1
- package/dist/runtime/query/upsert.d.ts.map +1 -1
- package/dist/runtime/query/upsert.js +5 -7
- package/dist/runtime/query/upsert.js.map +1 -1
- package/dist/runtime/schema-error.d.ts.map +1 -1
- package/dist/runtime/schema-error.js +6 -2
- package/dist/runtime/schema-error.js.map +1 -1
- package/dist/runtime/sqlite-error.d.ts.map +1 -1
- package/dist/runtime/sqlite-error.js +11 -12
- package/dist/runtime/sqlite-error.js.map +1 -1
- package/dist/runtime/sqlite-open.d.ts +2 -0
- package/dist/runtime/sqlite-open.d.ts.map +1 -1
- package/dist/runtime/sqlite-open.js +18 -1
- package/dist/runtime/sqlite-open.js.map +1 -1
- package/dist/runtime/transaction.d.ts +4 -0
- package/dist/runtime/transaction.d.ts.map +1 -1
- package/dist/runtime/transaction.js +31 -1
- package/dist/runtime/transaction.js.map +1 -1
- package/dist/runtime/transaction.test.d.ts +2 -0
- package/dist/runtime/transaction.test.d.ts.map +1 -0
- package/dist/runtime/transaction.test.js +43 -0
- package/dist/runtime/transaction.test.js.map +1 -0
- package/dist/runtime/types.d.ts +50 -17
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/schema/column-where.d.ts +11 -1
- package/dist/schema/column-where.d.ts.map +1 -1
- package/dist/schema/column.d.ts +1 -1
- package/dist/schema/column.d.ts.map +1 -1
- package/dist/schema/column.js +1 -1
- package/dist/schema/column.js.map +1 -1
- package/dist/schema/define-schema.d.ts +1 -1
- package/dist/schema/define-schema.d.ts.map +1 -1
- package/dist/schema/define-schema.js +5 -23
- package/dist/schema/define-schema.js.map +1 -1
- package/dist/schema/index.d.ts +2 -2
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +1 -1
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/relation-types.d.ts +29 -22
- package/dist/schema/relation-types.d.ts.map +1 -1
- package/dist/schema/relation.d.ts.map +1 -1
- package/dist/schema/relation.js +6 -4
- package/dist/schema/relation.js.map +1 -1
- package/dist/schema/table-registry.d.ts.map +1 -1
- package/dist/schema/table-registry.js +8 -2
- package/dist/schema/table-registry.js.map +1 -1
- package/dist/schema/table.d.ts +6 -3
- package/dist/schema/table.d.ts.map +1 -1
- package/dist/schema/table.js +30 -31
- package/dist/schema/table.js.map +1 -1
- package/dist/schema/types.d.ts +33 -25
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/sql/builder.d.ts +5 -1
- package/dist/sql/builder.d.ts.map +1 -1
- package/dist/sql/builder.js +23 -3
- package/dist/sql/builder.js.map +1 -1
- package/dist/sql/index.d.ts +5 -2
- package/dist/sql/index.d.ts.map +1 -1
- package/dist/sql/index.js +5 -2
- package/dist/sql/index.js.map +1 -1
- package/dist/utils/case.d.ts +4 -0
- package/dist/utils/case.d.ts.map +1 -1
- package/dist/utils/case.js +11 -0
- package/dist/utils/case.js.map +1 -1
- package/dist/utils/dotenv.d.ts +8 -0
- package/dist/utils/dotenv.d.ts.map +1 -0
- package/dist/utils/dotenv.js +70 -0
- package/dist/utils/dotenv.js.map +1 -0
- package/dist/utils/dotenv.test.d.ts +2 -0
- package/dist/utils/dotenv.test.d.ts.map +1 -0
- package/dist/utils/dotenv.test.js +32 -0
- package/dist/utils/dotenv.test.js.map +1 -0
- package/dist/utils/inflect.d.ts +6 -0
- package/dist/utils/inflect.d.ts.map +1 -0
- package/dist/utils/inflect.js +80 -0
- package/dist/utils/inflect.js.map +1 -0
- package/docs/cli.md +6 -2
- package/docs/configuration.md +3 -1
- package/docs/errors.md +61 -6
- package/docs/examples.md +63 -13
- package/docs/getting-started.md +24 -1
- package/docs/migrations.md +15 -2
- package/docs/plugins.md +13 -1
- package/docs/queries.md +109 -10
- package/docs/relations.md +5 -1
- package/docs/schema.md +12 -5
- package/docs/sqlite.md +24 -10
- package/docs/transactions.md +13 -2
- package/package.json +4 -2
|
@@ -1,1537 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { rebaseParamRefs } from "../../sql/template.js";
|
|
5
|
-
import { findM2M } from "./manifest-lookup.js";
|
|
6
|
-
import { primaryKeySqlName, requireScalarPrimaryKey, targetRelationPkSql, } from "./primary-key.js";
|
|
7
|
-
import { columnBySqlName, columnByTsName, columnsByTsNames, getOrSetSqlCache, getTableIndex, requireTsColumn, reorderKeyValues, sortedKeysCacheKey, } from "./table-index.js";
|
|
8
|
-
function colByTs(table, tsName, manifestIndex) {
|
|
9
|
-
return columnByTsName(getTableIndex(manifestIndex, table.accessor), table, tsName);
|
|
10
|
-
}
|
|
11
|
-
const PARAMLESS_OPERATORS = new Set(["isNull", "isNotNull"]);
|
|
12
|
-
function isOperatorObject(value) {
|
|
13
|
-
return (typeof value === "object" &&
|
|
14
|
-
value !== null &&
|
|
15
|
-
!Array.isArray(value) &&
|
|
16
|
-
!(value instanceof Date));
|
|
17
|
-
}
|
|
18
|
-
const operatorParamTransform = {
|
|
19
|
-
contains: (v) => `%${String(v)}%`,
|
|
20
|
-
startsWith: (v) => `${String(v)}%`,
|
|
21
|
-
endsWith: (v) => `%${String(v)}`,
|
|
22
|
-
};
|
|
23
|
-
function parseQueryMode(value) {
|
|
24
|
-
if (value === undefined || value === "default")
|
|
25
|
-
return "default";
|
|
26
|
-
if (value === "insensitive")
|
|
27
|
-
return "insensitive";
|
|
28
|
-
throw new Error(`unsupported query mode: ${String(value)}`);
|
|
29
|
-
}
|
|
30
|
-
function isStringPatternOp(op) {
|
|
31
|
-
return (op === "contains" ||
|
|
32
|
-
op === "startsWith" ||
|
|
33
|
-
op === "endsWith" ||
|
|
34
|
-
op === "search");
|
|
35
|
-
}
|
|
36
|
-
function stringFilterSql(op, sqlCol, paramIndex, mode, dialect) {
|
|
37
|
-
switch (op) {
|
|
38
|
-
case "contains":
|
|
39
|
-
case "startsWith":
|
|
40
|
-
case "endsWith":
|
|
41
|
-
return mode === "insensitive"
|
|
42
|
-
? dialect.ilike(sqlCol, paramIndex)
|
|
43
|
-
: dialect.whereOperators[op](sqlCol, paramIndex);
|
|
44
|
-
case "search":
|
|
45
|
-
return dialect.regex(sqlCol, paramIndex, mode === "insensitive");
|
|
46
|
-
default: {
|
|
47
|
-
const _never = op;
|
|
48
|
-
throw new Error(`unsupported string filter: ${_never}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function pluginWhereOperators(col) {
|
|
53
|
-
if (col.kind === "fk")
|
|
54
|
-
return {};
|
|
55
|
-
return getColumnType(col.kind)?.whereOperators ?? {};
|
|
56
|
-
}
|
|
57
|
-
export function serializeColumnValue(col, value, dialect = postgresDialect) {
|
|
58
|
-
if (col.kind === "fk")
|
|
59
|
-
return value;
|
|
60
|
-
const plugin = getColumnType(col.kind);
|
|
61
|
-
if (plugin?.serializeValue) {
|
|
62
|
-
return plugin.serializeValue(col, value, dialect);
|
|
63
|
-
}
|
|
64
|
-
return value;
|
|
65
|
-
}
|
|
66
|
-
function defaultColumnRef(col) {
|
|
67
|
-
return quoteIdentifier(col.sqlName);
|
|
68
|
-
}
|
|
69
|
-
function qualifiedColumnRefForTable(table) {
|
|
70
|
-
return (col) => `${tableRef(table)}.${quoteIdentifier(col.sqlName)}`;
|
|
71
|
-
}
|
|
72
|
-
function parentPkRef(table) {
|
|
73
|
-
const pkSql = primaryKeySqlName(table);
|
|
74
|
-
return `${tableRef(table)}.${quoteIdentifier(pkSql)}`;
|
|
75
|
-
}
|
|
76
|
-
function compileColumnCondition(col, rawValue, dialect, paramIndex, columnRef) {
|
|
77
|
-
const sqlCol = columnRef(col);
|
|
78
|
-
const spatialOps = pluginWhereOperators(col);
|
|
79
|
-
const conditions = [];
|
|
80
|
-
const params = [];
|
|
81
|
-
let nextParamIndex = paramIndex;
|
|
82
|
-
if (rawValue === null) {
|
|
83
|
-
conditions.push(dialect.whereOperators.isNull(sqlCol, nextParamIndex));
|
|
84
|
-
return { sql: conditions.join(" AND "), params, nextParamIndex };
|
|
85
|
-
}
|
|
86
|
-
if (!isOperatorObject(rawValue) || Array.isArray(rawValue)) {
|
|
87
|
-
conditions.push(dialect.whereOperators.equals(sqlCol, nextParamIndex));
|
|
88
|
-
params.push(serializeColumnValue(col, rawValue));
|
|
89
|
-
nextParamIndex++;
|
|
90
|
-
return { sql: conditions.join(" AND "), params, nextParamIndex };
|
|
91
|
-
}
|
|
92
|
-
const queryMode = parseQueryMode(rawValue.mode);
|
|
93
|
-
const hasOperator = Object.keys(rawValue).some((k) => k in dialect.whereOperators || k in spatialOps);
|
|
94
|
-
if (!hasOperator) {
|
|
95
|
-
conditions.push(dialect.whereOperators.equals(sqlCol, nextParamIndex));
|
|
96
|
-
params.push(rawValue);
|
|
97
|
-
nextParamIndex++;
|
|
98
|
-
return { sql: conditions.join(" AND "), params, nextParamIndex };
|
|
99
|
-
}
|
|
100
|
-
for (const [op, value] of Object.entries(rawValue)) {
|
|
101
|
-
if (op === "mode")
|
|
102
|
-
continue;
|
|
103
|
-
if (op in spatialOps) {
|
|
104
|
-
const operator = spatialOps[op];
|
|
105
|
-
if (!operator)
|
|
106
|
-
continue;
|
|
107
|
-
const compiled = operator.compile(sqlCol, value, col, nextParamIndex);
|
|
108
|
-
conditions.push(compiled.sql);
|
|
109
|
-
params.push(...compiled.params);
|
|
110
|
-
nextParamIndex += compiled.params.length;
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
if (!(op in dialect.whereOperators))
|
|
114
|
-
continue;
|
|
115
|
-
const operator = op;
|
|
116
|
-
if (PARAMLESS_OPERATORS.has(operator)) {
|
|
117
|
-
conditions.push(dialect.whereOperators[operator](sqlCol, nextParamIndex));
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
if (Array.isArray(value) && value.length === 0) {
|
|
121
|
-
if (operator === "in") {
|
|
122
|
-
conditions.push("1=0");
|
|
123
|
-
}
|
|
124
|
-
else if (operator === "notIn") {
|
|
125
|
-
conditions.push("1=1");
|
|
126
|
-
}
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
const transform = operatorParamTransform[operator];
|
|
130
|
-
const paramValue = operator === "in" || operator === "notIn"
|
|
131
|
-
? Array.isArray(value)
|
|
132
|
-
? value.map((item) => serializeColumnValue(col, item))
|
|
133
|
-
: value
|
|
134
|
-
: transform
|
|
135
|
-
? transform(value)
|
|
136
|
-
: serializeColumnValue(col, value);
|
|
137
|
-
conditions.push(isStringPatternOp(operator)
|
|
138
|
-
? stringFilterSql(operator, sqlCol, nextParamIndex, queryMode, dialect)
|
|
139
|
-
: dialect.whereOperators[operator](sqlCol, nextParamIndex));
|
|
140
|
-
params.push(paramValue);
|
|
141
|
-
nextParamIndex++;
|
|
142
|
-
}
|
|
143
|
-
return { sql: conditions.join(" AND "), params, nextParamIndex };
|
|
144
|
-
}
|
|
145
|
-
function compileExistsSubquery(existsSql, negate) {
|
|
146
|
-
return negate ? `NOT EXISTS (${existsSql})` : `EXISTS (${existsSql})`;
|
|
147
|
-
}
|
|
148
|
-
function compileRelationCondition(manifest, parentTable, relation, rawValue, dialect, paramIndex, manifestIndex) {
|
|
149
|
-
const m2m = findM2M(manifest, parentTable.accessor, relation.name);
|
|
150
|
-
const targetTable = manifest.tables[relation.targetAccessor];
|
|
151
|
-
if (!targetTable) {
|
|
152
|
-
return { sql: "", params: [], nextParamIndex: paramIndex };
|
|
153
|
-
}
|
|
154
|
-
const parentTableIndex = getTableIndex(manifestIndex, parentTable.accessor);
|
|
155
|
-
const targetTableIndex = getTableIndex(manifestIndex, targetTable.accessor);
|
|
156
|
-
if (relation.cardinality === "one") {
|
|
157
|
-
if (!isOperatorObject(rawValue) || Array.isArray(rawValue)) {
|
|
158
|
-
return { sql: "", params: [], nextParamIndex: paramIndex };
|
|
159
|
-
}
|
|
160
|
-
const relAlias = "_rel";
|
|
161
|
-
const columnRef = (col) => `${quoteIdentifier(relAlias)}.${quoteIdentifier(col.sqlName)}`;
|
|
162
|
-
const nested = compileWhereNode(manifest, targetTable, rawValue, dialect, paramIndex, columnRef, manifestIndex);
|
|
163
|
-
const parentFkCol = columnByTsName(parentTableIndex, parentTable, relation.fkColumn);
|
|
164
|
-
const parentFkRef = parentFkCol
|
|
165
|
-
? `${tableRef(parentTable)}.${quoteIdentifier(parentFkCol.sqlName)}`
|
|
166
|
-
: `${tableRef(parentTable)}.${quoteIdentifier(relation.fkSqlColumn)}`;
|
|
167
|
-
const targetPkSql = targetRelationPkSql(targetTable, relation);
|
|
168
|
-
const joinCond = `${quoteIdentifier(relAlias)}.${quoteIdentifier(targetPkSql)} = ${parentFkRef}`;
|
|
169
|
-
const whereParts = [joinCond];
|
|
170
|
-
if (nested.sql)
|
|
171
|
-
whereParts.push(nested.sql);
|
|
172
|
-
const existsSql = `SELECT 1 FROM ${tableRef(targetTable)} AS ${quoteIdentifier(relAlias)} WHERE ${whereParts.join(" AND ")}`;
|
|
173
|
-
return {
|
|
174
|
-
sql: compileExistsSubquery(existsSql, false),
|
|
175
|
-
params: nested.params,
|
|
176
|
-
nextParamIndex: nested.nextParamIndex,
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
if (!isOperatorObject(rawValue) || Array.isArray(rawValue)) {
|
|
180
|
-
return { sql: "", params: [], nextParamIndex: paramIndex };
|
|
181
|
-
}
|
|
182
|
-
const mode = ["some", "every", "none"].find((k) => k in rawValue);
|
|
183
|
-
if (!mode) {
|
|
184
|
-
return { sql: "", params: [], nextParamIndex: paramIndex };
|
|
185
|
-
}
|
|
186
|
-
const nestedWhere = rawValue[mode];
|
|
187
|
-
if (!isOperatorObject(nestedWhere) && nestedWhere !== undefined) {
|
|
188
|
-
return { sql: "", params: [], nextParamIndex: paramIndex };
|
|
189
|
-
}
|
|
190
|
-
const relAlias = "_rel";
|
|
191
|
-
const columnRef = (col) => `${quoteIdentifier(relAlias)}.${quoteIdentifier(col.sqlName)}`;
|
|
192
|
-
const nested = compileWhereNode(manifest, targetTable, (nestedWhere ?? {}), dialect, paramIndex, columnRef, manifestIndex);
|
|
193
|
-
let fromClause;
|
|
194
|
-
let whereParts;
|
|
195
|
-
if (m2m) {
|
|
196
|
-
const isLeft = m2m.leftAccessor === parentTable.accessor;
|
|
197
|
-
const throughTable = manifest.tables[m2m.throughAccessor];
|
|
198
|
-
if (!throughTable) {
|
|
199
|
-
return { sql: "", params: [], nextParamIndex: paramIndex };
|
|
200
|
-
}
|
|
201
|
-
const junctionAlias = "_jt";
|
|
202
|
-
const parentFkCol = isLeft ? m2m.leftFkColumn : m2m.rightFkColumn;
|
|
203
|
-
const targetFkCol = isLeft ? m2m.rightFkColumn : m2m.leftFkColumn;
|
|
204
|
-
const targetPkSql = targetRelationPkSql(targetTable);
|
|
205
|
-
fromClause = `${tableRef(throughTable)} AS ${quoteIdentifier(junctionAlias)} INNER JOIN ${tableRef(targetTable)} AS ${quoteIdentifier(relAlias)} ON ${quoteIdentifier(relAlias)}.${quoteIdentifier(targetPkSql)} = ${quoteIdentifier(junctionAlias)}.${quoteIdentifier(targetFkCol)}`;
|
|
206
|
-
whereParts = [
|
|
207
|
-
`${quoteIdentifier(junctionAlias)}.${quoteIdentifier(parentFkCol)} = ${parentPkRef(parentTable)}`,
|
|
208
|
-
];
|
|
209
|
-
if (nested.sql)
|
|
210
|
-
whereParts.push(nested.sql);
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
fromClause = `${tableRef(targetTable)} AS ${quoteIdentifier(relAlias)}`;
|
|
214
|
-
whereParts = [
|
|
215
|
-
`${quoteIdentifier(relAlias)}.${quoteIdentifier(relation.fkSqlColumn)} = ${parentPkRef(parentTable)}`,
|
|
216
|
-
];
|
|
217
|
-
if (nested.sql)
|
|
218
|
-
whereParts.push(nested.sql);
|
|
219
|
-
}
|
|
220
|
-
const existsSql = `SELECT 1 FROM ${fromClause} WHERE ${whereParts.join(" AND ")}`;
|
|
221
|
-
if (mode === "some") {
|
|
222
|
-
return {
|
|
223
|
-
sql: compileExistsSubquery(existsSql, false),
|
|
224
|
-
params: nested.params,
|
|
225
|
-
nextParamIndex: nested.nextParamIndex,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
if (mode === "none") {
|
|
229
|
-
return {
|
|
230
|
-
sql: compileExistsSubquery(existsSql, true),
|
|
231
|
-
params: nested.params,
|
|
232
|
-
nextParamIndex: nested.nextParamIndex,
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
const everyWhereParts = [...whereParts];
|
|
236
|
-
if (nested.sql) {
|
|
237
|
-
everyWhereParts.push(`NOT (${nested.sql})`);
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
everyWhereParts.push("FALSE");
|
|
241
|
-
}
|
|
242
|
-
const everySql = `SELECT 1 FROM ${fromClause} WHERE ${everyWhereParts.join(" AND ")}`;
|
|
243
|
-
return {
|
|
244
|
-
sql: compileExistsSubquery(everySql, true),
|
|
245
|
-
params: nested.params,
|
|
246
|
-
nextParamIndex: nested.nextParamIndex,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
function compileWhereNode(manifest, table, where, dialect, startParamIndex, columnRef = defaultColumnRef, manifestIndex) {
|
|
250
|
-
const conditions = [];
|
|
251
|
-
const params = [];
|
|
252
|
-
let paramIndex = startParamIndex;
|
|
253
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
254
|
-
const relations = tableIndex?.effectiveRelationsByName ??
|
|
255
|
-
new Map(effectiveRelations(manifest, table).map((rel) => [rel.name, rel]));
|
|
256
|
-
for (const [key, value] of Object.entries(where)) {
|
|
257
|
-
if (key === "AND" && Array.isArray(value)) {
|
|
258
|
-
const parts = [];
|
|
259
|
-
for (const item of value) {
|
|
260
|
-
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
261
|
-
continue;
|
|
262
|
-
const compiled = compileWhereNode(manifest, table, item, dialect, paramIndex, columnRef, manifestIndex);
|
|
263
|
-
if (compiled.sql)
|
|
264
|
-
parts.push(`(${compiled.sql})`);
|
|
265
|
-
params.push(...compiled.params);
|
|
266
|
-
paramIndex = compiled.nextParamIndex;
|
|
267
|
-
}
|
|
268
|
-
if (parts.length > 0)
|
|
269
|
-
conditions.push(`(${parts.join(" AND ")})`);
|
|
270
|
-
continue;
|
|
271
|
-
}
|
|
272
|
-
if (key === "OR" && Array.isArray(value)) {
|
|
273
|
-
const parts = [];
|
|
274
|
-
for (const item of value) {
|
|
275
|
-
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
276
|
-
continue;
|
|
277
|
-
const compiled = compileWhereNode(manifest, table, item, dialect, paramIndex, columnRef, manifestIndex);
|
|
278
|
-
if (compiled.sql)
|
|
279
|
-
parts.push(`(${compiled.sql})`);
|
|
280
|
-
params.push(...compiled.params);
|
|
281
|
-
paramIndex = compiled.nextParamIndex;
|
|
282
|
-
}
|
|
283
|
-
if (parts.length > 0)
|
|
284
|
-
conditions.push(`(${parts.join(" OR ")})`);
|
|
285
|
-
continue;
|
|
286
|
-
}
|
|
287
|
-
if (key === "NOT" && isOperatorObject(value)) {
|
|
288
|
-
const compiled = compileWhereNode(manifest, table, value, dialect, paramIndex, columnRef, manifestIndex);
|
|
289
|
-
if (compiled.sql)
|
|
290
|
-
conditions.push(`NOT (${compiled.sql})`);
|
|
291
|
-
params.push(...compiled.params);
|
|
292
|
-
paramIndex = compiled.nextParamIndex;
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
295
|
-
const relation = relations.get(key);
|
|
296
|
-
if (relation) {
|
|
297
|
-
const compiled = compileRelationCondition(manifest, table, relation, value, dialect, paramIndex, manifestIndex);
|
|
298
|
-
if (compiled.sql)
|
|
299
|
-
conditions.push(compiled.sql);
|
|
300
|
-
params.push(...compiled.params);
|
|
301
|
-
paramIndex = compiled.nextParamIndex;
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
const col = columnByTsName(tableIndex, table, key);
|
|
305
|
-
if (!col)
|
|
306
|
-
continue;
|
|
307
|
-
const compiled = compileColumnCondition(col, value, dialect, paramIndex, columnRef);
|
|
308
|
-
if (compiled.sql)
|
|
309
|
-
conditions.push(compiled.sql);
|
|
310
|
-
params.push(...compiled.params);
|
|
311
|
-
paramIndex = compiled.nextParamIndex;
|
|
312
|
-
}
|
|
313
|
-
return {
|
|
314
|
-
sql: conditions.join(" AND "),
|
|
315
|
-
params,
|
|
316
|
-
nextParamIndex: paramIndex,
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
export function compileWhere(manifest, table, where, dialect, startParamIndex = 1, manifestIndex, qualifyColumns = false, tableAlias) {
|
|
320
|
-
if (!where || Object.keys(where).length === 0) {
|
|
321
|
-
return { sql: "", params: [] };
|
|
322
|
-
}
|
|
323
|
-
const columnRef = tableAlias
|
|
324
|
-
? (col) => `${quoteIdentifier(tableAlias)}.${quoteIdentifier(col.sqlName)}`
|
|
325
|
-
: qualifyColumns
|
|
326
|
-
? qualifiedColumnRefForTable(table)
|
|
327
|
-
: defaultColumnRef;
|
|
328
|
-
const result = compileWhereNode(manifest, table, where, dialect, startParamIndex, columnRef, manifestIndex);
|
|
329
|
-
const impossible = isImpossibleWhereSql(result.sql);
|
|
330
|
-
return {
|
|
331
|
-
sql: result.sql ? `WHERE ${result.sql}` : "",
|
|
332
|
-
params: result.params,
|
|
333
|
-
...(impossible ? { impossible: true } : {}),
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
export function whereShapeKey(where) {
|
|
337
|
-
const parts = [];
|
|
338
|
-
for (const [key, value] of Object.entries(where)) {
|
|
339
|
-
if (key === "AND" && Array.isArray(value)) {
|
|
340
|
-
parts.push(`AND:${value
|
|
341
|
-
.filter((item) => !!item &&
|
|
342
|
-
typeof item === "object" &&
|
|
343
|
-
!Array.isArray(item))
|
|
344
|
-
.map((item) => whereShapeKey(item))
|
|
345
|
-
.join(",")}`);
|
|
346
|
-
continue;
|
|
347
|
-
}
|
|
348
|
-
if (key === "OR" && Array.isArray(value)) {
|
|
349
|
-
parts.push(`OR:${value
|
|
350
|
-
.filter((item) => !!item &&
|
|
351
|
-
typeof item === "object" &&
|
|
352
|
-
!Array.isArray(item))
|
|
353
|
-
.map((item) => whereShapeKey(item))
|
|
354
|
-
.join(",")}`);
|
|
355
|
-
continue;
|
|
356
|
-
}
|
|
357
|
-
if (key === "NOT" && isOperatorObject(value)) {
|
|
358
|
-
parts.push(`NOT:${whereShapeKey(value)}`);
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
if (isOperatorObject(value) && !(value instanceof Date)) {
|
|
362
|
-
const ops = Object.keys(value).sort();
|
|
363
|
-
if (ops.some((op) => op === "some" || op === "every" || op === "none")) {
|
|
364
|
-
const mode = ops.find((op) => op === "some" || op === "every" || op === "none");
|
|
365
|
-
const nested = value[mode ?? ""];
|
|
366
|
-
parts.push(`${key}:rel:${mode}:${isOperatorObject(nested) ? whereShapeKey(nested) : "{}"}`);
|
|
367
|
-
}
|
|
368
|
-
else if (ops.includes("in") || ops.includes("notIn")) {
|
|
369
|
-
const arr = value.in ?? value.notIn;
|
|
370
|
-
const len = Array.isArray(arr) ? arr.length : 0;
|
|
371
|
-
const op = ops.includes("in") ? "in" : "notIn";
|
|
372
|
-
parts.push(`${key}:${op}:${len}`);
|
|
373
|
-
}
|
|
374
|
-
else {
|
|
375
|
-
const modePart = typeof value.mode === "string" ? `:mode:${value.mode}` : "";
|
|
376
|
-
const opsForKey = ops.filter((op) => op !== "mode");
|
|
377
|
-
parts.push(`${key}:${opsForKey.join(",")}${modePart}`);
|
|
378
|
-
}
|
|
379
|
-
continue;
|
|
380
|
-
}
|
|
381
|
-
parts.push(`${key}:eq`);
|
|
382
|
-
}
|
|
383
|
-
return parts.join("&");
|
|
384
|
-
}
|
|
385
|
-
function collectWhereParams(manifest, table, where, dialect, manifestIndex) {
|
|
386
|
-
const params = [];
|
|
387
|
-
function walk(node, columnRef) {
|
|
388
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
389
|
-
const relations = tableIndex?.effectiveRelationsByName ??
|
|
390
|
-
new Map(effectiveRelations(manifest, table).map((rel) => [
|
|
391
|
-
rel.name,
|
|
392
|
-
rel,
|
|
393
|
-
]));
|
|
394
|
-
for (const [key, value] of Object.entries(node)) {
|
|
395
|
-
if (key === "AND" || key === "OR") {
|
|
396
|
-
if (Array.isArray(value)) {
|
|
397
|
-
for (const item of value) {
|
|
398
|
-
if (item &&
|
|
399
|
-
typeof item === "object" &&
|
|
400
|
-
!Array.isArray(item)) {
|
|
401
|
-
walk(item, columnRef);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
continue;
|
|
406
|
-
}
|
|
407
|
-
if (key === "NOT" && isOperatorObject(value)) {
|
|
408
|
-
walk(value, columnRef);
|
|
409
|
-
continue;
|
|
410
|
-
}
|
|
411
|
-
if (relations.get(key)) {
|
|
412
|
-
const compiled = compileRelationCondition(manifest, table, relations.get(key), value, dialect, 1, manifestIndex);
|
|
413
|
-
params.push(...compiled.params);
|
|
414
|
-
continue;
|
|
415
|
-
}
|
|
416
|
-
const col = columnByTsName(tableIndex, table, key);
|
|
417
|
-
if (!col)
|
|
418
|
-
continue;
|
|
419
|
-
const compiled = compileColumnCondition(col, value, dialect, 1, columnRef);
|
|
420
|
-
params.push(...compiled.params);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
walk(where, defaultColumnRef);
|
|
424
|
-
return params;
|
|
425
|
-
}
|
|
426
|
-
function whereValuesFingerprint(manifest, table, where, dialect, manifestIndex) {
|
|
427
|
-
return JSON.stringify(collectWhereParams(manifest, table, where, dialect, manifestIndex));
|
|
428
|
-
}
|
|
429
|
-
export function getCachedWhereClause(manifest, table, where, dialect, startParamIndex = 1, manifestIndex, qualifyColumns = false) {
|
|
430
|
-
if (!where || Object.keys(where).length === 0) {
|
|
431
|
-
return { sql: "", params: [] };
|
|
432
|
-
}
|
|
433
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
434
|
-
const shape = qualifyColumns
|
|
435
|
-
? `${whereShapeKey(where)}|qualified`
|
|
436
|
-
: whereShapeKey(where);
|
|
437
|
-
const shellCached = tableIndex?.whereClauseByShape.get(shape);
|
|
438
|
-
if (shellCached) {
|
|
439
|
-
return {
|
|
440
|
-
sql: shellCached.sql,
|
|
441
|
-
params: collectWhereParams(manifest, table, where, dialect, manifestIndex),
|
|
442
|
-
...(shellCached.impossible ? { impossible: true } : {}),
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
const fingerprint = whereValuesFingerprint(manifest, table, where, dialect, manifestIndex);
|
|
446
|
-
const cacheKey = `${shape}\0${fingerprint}`;
|
|
447
|
-
const cached = tableIndex?.whereClauseByFingerprint.get(cacheKey);
|
|
448
|
-
if (cached)
|
|
449
|
-
return cached;
|
|
450
|
-
const compiled = compileWhere(manifest, table, where, dialect, startParamIndex, manifestIndex, qualifyColumns);
|
|
451
|
-
tableIndex?.whereClauseByShape.set(shape, {
|
|
452
|
-
sql: compiled.sql,
|
|
453
|
-
...(compiled.impossible ? { impossible: true } : {}),
|
|
454
|
-
});
|
|
455
|
-
tableIndex?.whereClauseByFingerprint.set(cacheKey, compiled);
|
|
456
|
-
return compiled;
|
|
457
|
-
}
|
|
458
|
-
export function orderByShapeKey(orderBy, tableAlias) {
|
|
459
|
-
if (!orderBy || Object.keys(orderBy).length === 0)
|
|
460
|
-
return "";
|
|
461
|
-
const entries = Object.entries(orderBy)
|
|
462
|
-
.filter(([key]) => key !== "_count")
|
|
463
|
-
.map(([key, direction]) => typeof direction === "string"
|
|
464
|
-
? `${key}:${direction.toUpperCase()}`
|
|
465
|
-
: "")
|
|
466
|
-
.filter(Boolean)
|
|
467
|
-
.sort((a, b) => a.localeCompare(b));
|
|
468
|
-
if (entries.length === 0)
|
|
469
|
-
return "";
|
|
470
|
-
const base = entries.join("|");
|
|
471
|
-
return tableAlias ? `${base}|@${tableAlias}` : base;
|
|
472
|
-
}
|
|
473
|
-
export function getCachedOrderByClause(table, orderBy, tableAlias, manifestIndex) {
|
|
474
|
-
if (!orderBy || Object.keys(orderBy).length === 0)
|
|
475
|
-
return "";
|
|
476
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
477
|
-
const shape = orderByShapeKey(orderBy, tableAlias);
|
|
478
|
-
if (!shape)
|
|
479
|
-
return "";
|
|
480
|
-
if (!tableIndex) {
|
|
481
|
-
return compileOrderBy(table, orderBy, tableAlias, manifestIndex);
|
|
482
|
-
}
|
|
483
|
-
return getOrSetSqlCache(tableIndex.orderBySqlByShape, shape, () => compileOrderBy(table, orderBy, tableAlias, manifestIndex));
|
|
484
|
-
}
|
|
485
|
-
export function getCachedDeleteManyQuery(tableIndex, table, whereSql) {
|
|
486
|
-
const cacheKey = whereSql || "";
|
|
487
|
-
if (!tableIndex)
|
|
488
|
-
return buildDeleteManyQuery(table, whereSql);
|
|
489
|
-
return getOrSetSqlCache(tableIndex.deleteManySqlByWhereShape, cacheKey, () => buildDeleteManyQuery(table, whereSql));
|
|
490
|
-
}
|
|
491
|
-
export function isImpossibleWhereSql(sql) {
|
|
492
|
-
if (!sql)
|
|
493
|
-
return false;
|
|
494
|
-
return /\b1\s*=\s*0\b/.test(sql);
|
|
495
|
-
}
|
|
496
|
-
export function isImpossibleWhere(whereSql) {
|
|
497
|
-
if (!whereSql)
|
|
498
|
-
return false;
|
|
499
|
-
return isImpossibleWhereSql(whereSql.replace(/^WHERE\s+/i, ""));
|
|
500
|
-
}
|
|
501
|
-
function buildValuePlaceholder(col, paramIndex) {
|
|
502
|
-
if (!col || col.kind === "fk")
|
|
503
|
-
return `$${paramIndex}`;
|
|
504
|
-
const plugin = getColumnType(col.kind);
|
|
505
|
-
if (plugin?.writeExpression) {
|
|
506
|
-
return plugin.writeExpression(col, paramIndex);
|
|
507
|
-
}
|
|
508
|
-
return `$${paramIndex}`;
|
|
509
|
-
}
|
|
510
|
-
function isBinaryValue(value) {
|
|
511
|
-
if (typeof Buffer !== "undefined" && Buffer.isBuffer(value))
|
|
512
|
-
return true;
|
|
513
|
-
return value instanceof Uint8Array;
|
|
514
|
-
}
|
|
515
|
-
const ATOMIC_UPDATE_OPS = new Set([
|
|
516
|
-
"increment",
|
|
517
|
-
"decrement",
|
|
518
|
-
"multiply",
|
|
519
|
-
"set",
|
|
520
|
-
]);
|
|
521
|
-
const NUMERIC_UPDATE_KINDS = new Set(["int", "serial", "decimal", "bigint"]);
|
|
522
|
-
function isNumericUpdateKind(kind) {
|
|
523
|
-
return NUMERIC_UPDATE_KINDS.has(kind);
|
|
524
|
-
}
|
|
525
|
-
function needsNumericCast(col, dialect) {
|
|
526
|
-
return (col.kind === "decimal" ||
|
|
527
|
-
(dialect.name === "sqlite" && col.kind === "bigint"));
|
|
528
|
-
}
|
|
529
|
-
function isAtomicOp(op) {
|
|
530
|
-
return ATOMIC_UPDATE_OPS.has(op);
|
|
531
|
-
}
|
|
532
|
-
function arithmeticSql(op, left, right) {
|
|
533
|
-
switch (op) {
|
|
534
|
-
case "increment":
|
|
535
|
-
return `${left} + ${right}`;
|
|
536
|
-
case "decrement":
|
|
537
|
-
return `${left} - ${right}`;
|
|
538
|
-
case "multiply":
|
|
539
|
-
return `${left} * ${right}`;
|
|
540
|
-
default: {
|
|
541
|
-
const _never = op;
|
|
542
|
-
throw new Error(`unsupported atomic update: ${_never}`);
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
export function parseAtomicUpdate(col, value) {
|
|
547
|
-
if (!isOperatorObject(value) || isBinaryValue(value)) {
|
|
548
|
-
return { op: "set", value };
|
|
549
|
-
}
|
|
550
|
-
const keys = Object.keys(value);
|
|
551
|
-
const opKeys = keys.filter(isAtomicOp);
|
|
552
|
-
if (opKeys.length === 0) {
|
|
553
|
-
if (isNumericUpdateKind(col.kind)) {
|
|
554
|
-
throw new Error(`update on ${col.tsName} requires increment, decrement, multiply, or set`);
|
|
555
|
-
}
|
|
556
|
-
return { op: "set", value };
|
|
557
|
-
}
|
|
558
|
-
if (opKeys.length !== keys.length) {
|
|
559
|
-
throw new Error(`update on ${col.tsName} cannot mix operators with other keys`);
|
|
560
|
-
}
|
|
561
|
-
if (opKeys.length !== 1) {
|
|
562
|
-
throw new Error(`update on ${col.tsName} allows only one of increment, decrement, multiply, set`);
|
|
563
|
-
}
|
|
564
|
-
const op = opKeys[0];
|
|
565
|
-
if (op === undefined) {
|
|
566
|
-
throw new Error(`update on ${col.tsName} requires an operator`);
|
|
567
|
-
}
|
|
568
|
-
if (value[op] === undefined) {
|
|
569
|
-
throw new Error(`update ${op} on ${col.tsName} requires a value`);
|
|
570
|
-
}
|
|
571
|
-
if (op !== "set" && !isNumericUpdateKind(col.kind)) {
|
|
572
|
-
throw new Error(`${op} is not supported on ${col.kind} column ${col.tsName}`);
|
|
573
|
-
}
|
|
574
|
-
return { op, value: value[op] };
|
|
575
|
-
}
|
|
576
|
-
function orderUpdateAssignments(dataKeys, ops) {
|
|
577
|
-
const pairs = dataKeys.map((key, i) => ({
|
|
578
|
-
key,
|
|
579
|
-
op: ops?.[i] ?? "set",
|
|
580
|
-
}));
|
|
581
|
-
pairs.sort((a, b) => a.key.localeCompare(b.key));
|
|
582
|
-
return {
|
|
583
|
-
keys: pairs.map((pair) => pair.key),
|
|
584
|
-
ops: pairs.map((pair) => pair.op),
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
function buildSetExpression(col, paramIndex, op = "set", dialect = postgresDialect) {
|
|
588
|
-
const sqlCol = quoteIdentifier(col?.sqlName ?? "");
|
|
589
|
-
const placeholder = buildValuePlaceholder(col, paramIndex);
|
|
590
|
-
switch (op) {
|
|
591
|
-
case "set":
|
|
592
|
-
return `${sqlCol} = ${placeholder}`;
|
|
593
|
-
case "increment":
|
|
594
|
-
case "decrement":
|
|
595
|
-
case "multiply": {
|
|
596
|
-
if (!col) {
|
|
597
|
-
throw new Error("atomic update requires a column");
|
|
598
|
-
}
|
|
599
|
-
const left = needsNumericCast(col, dialect)
|
|
600
|
-
? dialect.castToNumeric(sqlCol)
|
|
601
|
-
: sqlCol;
|
|
602
|
-
const right = needsNumericCast(col, dialect)
|
|
603
|
-
? dialect.castToNumeric(placeholder)
|
|
604
|
-
: placeholder;
|
|
605
|
-
return `${sqlCol} = ${arithmeticSql(op, left, right)}`;
|
|
606
|
-
}
|
|
607
|
-
default: {
|
|
608
|
-
const _never = op;
|
|
609
|
-
throw new Error(`unsupported atomic update: ${_never}`);
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
export function compileOrderBy(table, orderBy, tableAlias, manifestIndex) {
|
|
614
|
-
if (!orderBy || Object.keys(orderBy).length === 0)
|
|
615
|
-
return "";
|
|
616
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
617
|
-
const prefix = tableAlias ? `${quoteIdentifier(tableAlias)}.` : "";
|
|
618
|
-
const parts = [];
|
|
619
|
-
for (const [tsKey, direction] of Object.entries(orderBy)) {
|
|
620
|
-
if (tsKey === "_count" || typeof direction !== "string")
|
|
621
|
-
continue;
|
|
622
|
-
const col = columnByTsName(tableIndex, table, tsKey);
|
|
623
|
-
if (!col)
|
|
624
|
-
continue;
|
|
625
|
-
const dir = direction.toUpperCase() === "DESC" ? "DESC" : "ASC";
|
|
626
|
-
parts.push(`${prefix}${quoteIdentifier(col.sqlName)} ${dir}`);
|
|
627
|
-
}
|
|
628
|
-
return parts.length > 0 ? `ORDER BY ${parts.join(", ")}` : "";
|
|
629
|
-
}
|
|
630
|
-
export function normalizeSelectColumns(select) {
|
|
631
|
-
if (!select)
|
|
632
|
-
return undefined;
|
|
633
|
-
if (Array.isArray(select))
|
|
634
|
-
return select;
|
|
635
|
-
return Object.entries(select)
|
|
636
|
-
.filter(([, enabled]) => enabled === true)
|
|
637
|
-
.map(([key]) => key);
|
|
638
|
-
}
|
|
639
|
-
/** Columns returned by default SELECT (omits `.hidden()` unless `includeHidden` or explicitly selected). */
|
|
640
|
-
export function columnsForOutput(tableIndex, table, select, includeHidden) {
|
|
641
|
-
if (select && select.length > 0) {
|
|
642
|
-
return columnsByTsNames(tableIndex, table, select);
|
|
643
|
-
}
|
|
644
|
-
if (includeHidden) {
|
|
645
|
-
return table.columns;
|
|
646
|
-
}
|
|
647
|
-
return table.columns.filter((col) => col.hidden !== true);
|
|
648
|
-
}
|
|
649
|
-
function aliasToTsName(expression, col) {
|
|
650
|
-
if (col.sqlName === col.tsName)
|
|
651
|
-
return expression;
|
|
652
|
-
return `${expression} AS ${quoteIdentifier(col.tsName)}`;
|
|
653
|
-
}
|
|
654
|
-
function selectExpression(col) {
|
|
655
|
-
if (col.kind === "fk") {
|
|
656
|
-
return aliasToTsName(quoteIdentifier(col.sqlName), col);
|
|
657
|
-
}
|
|
658
|
-
const plugin = getColumnType(col.kind);
|
|
659
|
-
if (plugin?.selectExpression) {
|
|
660
|
-
return aliasToTsName(plugin.selectExpression(col), col);
|
|
661
|
-
}
|
|
662
|
-
return aliasToTsName(quoteIdentifier(col.sqlName), col);
|
|
663
|
-
}
|
|
664
|
-
export function buildSelectColumns(table, select, manifestIndex, includeHidden) {
|
|
665
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
666
|
-
const cols = columnsForOutput(tableIndex, table, select, includeHidden);
|
|
667
|
-
return cols.map((c) => selectExpression(c)).join(", ");
|
|
668
|
-
}
|
|
669
|
-
export function buildQualifiedSelectColumns(table, select, manifestIndex, includeHidden) {
|
|
670
|
-
const ref = tableRef(table);
|
|
671
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
672
|
-
const cols = columnsForOutput(tableIndex, table, select, includeHidden);
|
|
673
|
-
return cols.map((c) => `${ref}.${selectExpression(c)}`).join(", ");
|
|
674
|
-
}
|
|
675
|
-
export function buildFindByIdQuery(table, select, manifestIndex, includeHidden) {
|
|
676
|
-
const { sqlName } = requireScalarPrimaryKey(table);
|
|
677
|
-
const sqlCol = quoteIdentifier(sqlName);
|
|
678
|
-
const selectCols = buildSelectColumns(table, select, manifestIndex, includeHidden);
|
|
679
|
-
return `SELECT ${selectCols} FROM ${tableRef(table)} WHERE ${sqlCol} = $1`;
|
|
680
|
-
}
|
|
681
|
-
export function buildFindAllQuery(table) {
|
|
682
|
-
return `SELECT ${buildSelectColumns(table)} FROM ${tableRef(table)}`;
|
|
683
|
-
}
|
|
684
|
-
export function normalizeLimitOffset(value, label) {
|
|
685
|
-
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
686
|
-
throw new Error(`${label} must be a non-negative integer, got ${JSON.stringify(value)}`);
|
|
687
|
-
}
|
|
688
|
-
return value;
|
|
689
|
-
}
|
|
690
|
-
export function buildFindManyQuery(table, whereSql, orderSql, take, skip, distinctOn, extraSelectCols, joinClauses, manifestIndex, groupBySql, select, includeHidden) {
|
|
691
|
-
const hasJoins = Boolean(joinClauses && joinClauses.length > 0);
|
|
692
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
693
|
-
const selectCols = hasJoins
|
|
694
|
-
? buildQualifiedSelectColumns(table, select, manifestIndex, includeHidden)
|
|
695
|
-
: buildSelectColumns(table, select, manifestIndex, includeHidden);
|
|
696
|
-
let sql = "SELECT ";
|
|
697
|
-
if (distinctOn && distinctOn.length > 0) {
|
|
698
|
-
const distinctCols = columnsByTsNames(tableIndex, table, distinctOn)
|
|
699
|
-
.map((col) => hasJoins
|
|
700
|
-
? `${tableRef(table)}.${quoteIdentifier(col.sqlName)}`
|
|
701
|
-
: quoteIdentifier(col.sqlName))
|
|
702
|
-
.join(", ");
|
|
703
|
-
sql += `DISTINCT ON (${distinctCols}) `;
|
|
704
|
-
}
|
|
705
|
-
sql += selectCols;
|
|
706
|
-
if (extraSelectCols && extraSelectCols.length > 0) {
|
|
707
|
-
sql += `, ${extraSelectCols.join(", ")}`;
|
|
708
|
-
}
|
|
709
|
-
sql += ` FROM ${tableRef(table)}`;
|
|
710
|
-
if (joinClauses && joinClauses.length > 0) {
|
|
711
|
-
sql += ` ${joinClauses.join(" ")}`;
|
|
712
|
-
}
|
|
713
|
-
if (whereSql)
|
|
714
|
-
sql += ` ${whereSql}`;
|
|
715
|
-
if (groupBySql)
|
|
716
|
-
sql += ` ${groupBySql}`;
|
|
717
|
-
if (orderSql)
|
|
718
|
-
sql += ` ${orderSql}`;
|
|
719
|
-
if (take !== undefined) {
|
|
720
|
-
sql += ` LIMIT ${normalizeLimitOffset(take, "take")}`;
|
|
721
|
-
}
|
|
722
|
-
if (skip !== undefined) {
|
|
723
|
-
sql += ` OFFSET ${normalizeLimitOffset(skip, "skip")}`;
|
|
724
|
-
}
|
|
725
|
-
return sql;
|
|
726
|
-
}
|
|
727
|
-
export function buildPaginateQuery(table, whereSql, orderSql, take, extraSelectCols, joinClauses, manifestIndex) {
|
|
728
|
-
return buildFindManyQuery(table, whereSql, orderSql, take + 1, undefined, undefined, extraSelectCols, joinClauses, manifestIndex);
|
|
729
|
-
}
|
|
730
|
-
export function buildCountQuery(table, whereSql, dialect = postgresDialect, distinct, select, manifestIndex) {
|
|
731
|
-
if (select !== undefined) {
|
|
732
|
-
if (distinct) {
|
|
733
|
-
throw new Error("count cannot combine distinct and select");
|
|
734
|
-
}
|
|
735
|
-
const parts = countSelectParts(table, select, dialect, manifestIndex);
|
|
736
|
-
if (parts.length === 0) {
|
|
737
|
-
throw new Error("count select requires at least one field");
|
|
738
|
-
}
|
|
739
|
-
let sql = `SELECT ${parts.join(", ")} FROM ${tableRef(table)}`;
|
|
740
|
-
if (whereSql)
|
|
741
|
-
sql += ` ${whereSql}`;
|
|
742
|
-
return sql;
|
|
743
|
-
}
|
|
744
|
-
let expr = "COUNT(*)";
|
|
745
|
-
if (distinct) {
|
|
746
|
-
const sqlCol = requireCountSqlCol(table, distinct, manifestIndex);
|
|
747
|
-
expr = `COUNT(DISTINCT ${sqlCol})`;
|
|
748
|
-
}
|
|
749
|
-
let sql = `SELECT ${dialect.castToInt(expr)} AS count FROM ${tableRef(table)}`;
|
|
750
|
-
if (whereSql)
|
|
751
|
-
sql += ` ${whereSql}`;
|
|
752
|
-
return sql;
|
|
753
|
-
}
|
|
754
|
-
export function buildExistsQuery(table, whereSql) {
|
|
755
|
-
let sql = `SELECT 1 FROM ${tableRef(table)}`;
|
|
756
|
-
if (whereSql)
|
|
757
|
-
sql += ` ${whereSql}`;
|
|
758
|
-
sql += " LIMIT 1";
|
|
759
|
-
return sql;
|
|
760
|
-
}
|
|
761
|
-
function countSqlCol(table, tsName, manifestIndex) {
|
|
762
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
763
|
-
const col = columnByTsName(tableIndex, table, tsName);
|
|
764
|
-
if (!col)
|
|
765
|
-
return undefined;
|
|
766
|
-
return quoteIdentifier(col.sqlName);
|
|
767
|
-
}
|
|
768
|
-
export function requireCountSqlCol(table, tsName, manifestIndex) {
|
|
769
|
-
const sqlCol = countSqlCol(table, tsName, manifestIndex);
|
|
770
|
-
if (!sqlCol) {
|
|
771
|
-
requireTsColumn(getTableIndex(manifestIndex, table.accessor), table, tsName, "count", "select");
|
|
772
|
-
}
|
|
773
|
-
return sqlCol;
|
|
774
|
-
}
|
|
775
|
-
export function normalizeCountMap(select) {
|
|
776
|
-
const map = {};
|
|
777
|
-
for (const [key, value] of Object.entries(select)) {
|
|
778
|
-
if (value === true)
|
|
779
|
-
map[key] = true;
|
|
780
|
-
}
|
|
781
|
-
return map;
|
|
782
|
-
}
|
|
783
|
-
export function toCountSelector(value) {
|
|
784
|
-
if (value === true)
|
|
785
|
-
return true;
|
|
786
|
-
const map = normalizeCountMap(value);
|
|
787
|
-
if (Object.keys(map).length === 0) {
|
|
788
|
-
throw new Error("_count requires at least one field");
|
|
789
|
-
}
|
|
790
|
-
return map;
|
|
791
|
-
}
|
|
792
|
-
export function hasStarCount(selectors) {
|
|
793
|
-
return (selectors._count === true ||
|
|
794
|
-
(typeof selectors._count === "object" && selectors._count._all === true));
|
|
795
|
-
}
|
|
796
|
-
export function hasCountField(selectors, field) {
|
|
797
|
-
return (typeof selectors._count === "object" && selectors._count[field] === true);
|
|
798
|
-
}
|
|
799
|
-
export function countSelectParts(table, select, dialect = postgresDialect, manifestIndex) {
|
|
800
|
-
const parts = [];
|
|
801
|
-
if (select._all) {
|
|
802
|
-
parts.push(`${dialect.castToInt("COUNT(*)")} AS "_all"`);
|
|
803
|
-
}
|
|
804
|
-
for (const key of Object.keys(select).sort()) {
|
|
805
|
-
if (key === "_all")
|
|
806
|
-
continue;
|
|
807
|
-
const sqlCol = requireCountSqlCol(table, key, manifestIndex);
|
|
808
|
-
parts.push(`${dialect.castToInt(`COUNT(${sqlCol})`)} AS ${quoteIdentifier(key)}`);
|
|
809
|
-
}
|
|
810
|
-
return parts;
|
|
811
|
-
}
|
|
812
|
-
function aggregateSqlCol(table, tsName, dialect, manifestIndex) {
|
|
813
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
814
|
-
const col = columnByTsName(tableIndex, table, tsName);
|
|
815
|
-
if (!col)
|
|
816
|
-
return undefined;
|
|
817
|
-
const sqlCol = quoteIdentifier(col.sqlName);
|
|
818
|
-
if (col.kind === "decimal")
|
|
819
|
-
return dialect.castToNumeric(sqlCol);
|
|
820
|
-
return sqlCol;
|
|
821
|
-
}
|
|
822
|
-
const FIELD_AGG_KEYS = ["_avg", "_sum", "_min", "_max"];
|
|
823
|
-
function sqlFnForFieldAgg(key) {
|
|
824
|
-
switch (key) {
|
|
825
|
-
case "_avg":
|
|
826
|
-
return "AVG";
|
|
827
|
-
case "_sum":
|
|
828
|
-
return "SUM";
|
|
829
|
-
case "_min":
|
|
830
|
-
return "MIN";
|
|
831
|
-
case "_max":
|
|
832
|
-
return "MAX";
|
|
833
|
-
default: {
|
|
834
|
-
const _never = key;
|
|
835
|
-
throw new Error(`unsupported aggregate: ${_never}`);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
function fieldAggExpression(key, table, colName, dialect, manifestIndex) {
|
|
840
|
-
const sqlCol = aggregateSqlCol(table, colName, dialect, manifestIndex);
|
|
841
|
-
if (!sqlCol)
|
|
842
|
-
return undefined;
|
|
843
|
-
return `${sqlFnForFieldAgg(key)}(${sqlCol})`;
|
|
844
|
-
}
|
|
845
|
-
export function aggregateSelectParts(table, selectors, dialect = postgresDialect, manifestIndex) {
|
|
846
|
-
const parts = [];
|
|
847
|
-
if (selectors._count === true) {
|
|
848
|
-
parts.push(`${dialect.castToInt("COUNT(*)")} AS "__count"`);
|
|
849
|
-
}
|
|
850
|
-
else if (selectors._count) {
|
|
851
|
-
for (const key of Object.keys(selectors._count).sort()) {
|
|
852
|
-
if (key === "_all") {
|
|
853
|
-
parts.push(`${dialect.castToInt("COUNT(*)")} AS "__count_all"`);
|
|
854
|
-
continue;
|
|
855
|
-
}
|
|
856
|
-
const sqlCol = requireCountSqlCol(table, key, manifestIndex);
|
|
857
|
-
parts.push(`${dialect.castToInt(`COUNT(${sqlCol})`)} AS "__count_${key}"`);
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
for (const key of FIELD_AGG_KEYS) {
|
|
861
|
-
const fieldMap = selectors[key];
|
|
862
|
-
if (!fieldMap)
|
|
863
|
-
continue;
|
|
864
|
-
for (const colName of Object.keys(fieldMap)) {
|
|
865
|
-
const expr = fieldAggExpression(key, table, colName, dialect, manifestIndex);
|
|
866
|
-
if (expr)
|
|
867
|
-
parts.push(`${expr} AS "${key}_${colName}"`);
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
return parts;
|
|
871
|
-
}
|
|
872
|
-
export function buildAggregateQuery(table, selectors, whereSql, manifestIndex, dialect = postgresDialect) {
|
|
873
|
-
const parts = aggregateSelectParts(table, selectors, dialect, manifestIndex);
|
|
874
|
-
if (parts.length === 0) {
|
|
875
|
-
throw new Error("aggregate requires at least one selector");
|
|
876
|
-
}
|
|
877
|
-
let sql = `SELECT ${parts.join(", ")} FROM ${tableRef(table)}`;
|
|
878
|
-
if (whereSql)
|
|
879
|
-
sql += ` ${whereSql}`;
|
|
880
|
-
return sql;
|
|
881
|
-
}
|
|
882
|
-
export function aggregateSelectorCacheKey(selectors) {
|
|
883
|
-
const parts = [];
|
|
884
|
-
if (selectors._count === true) {
|
|
885
|
-
parts.push("_count");
|
|
886
|
-
}
|
|
887
|
-
else if (selectors._count) {
|
|
888
|
-
parts.push(`_count:${Object.keys(selectors._count).sort().join(",")}`);
|
|
889
|
-
}
|
|
890
|
-
for (const key of ["_avg", "_sum", "_min", "_max"]) {
|
|
891
|
-
const fieldMap = selectors[key];
|
|
892
|
-
if (!fieldMap)
|
|
893
|
-
continue;
|
|
894
|
-
parts.push(`${key}:${Object.keys(fieldMap).sort().join(",")}`);
|
|
895
|
-
}
|
|
896
|
-
return parts.join("|");
|
|
897
|
-
}
|
|
898
|
-
export function getCachedAggregateQuery(tableIndex, table, selectors, whereSql, manifestIndex, dialect = postgresDialect) {
|
|
899
|
-
const cacheKey = `${dialect.name}|${aggregateSelectorCacheKey(selectors)}|${whereSql}`;
|
|
900
|
-
if (!tableIndex) {
|
|
901
|
-
return buildAggregateQuery(table, selectors, whereSql, manifestIndex, dialect);
|
|
902
|
-
}
|
|
903
|
-
return getOrSetSqlCache(tableIndex.aggregateSqlBySelector, cacheKey, () => buildAggregateQuery(table, selectors, whereSql, manifestIndex, dialect));
|
|
904
|
-
}
|
|
905
|
-
function isHavingOperator(op) {
|
|
906
|
-
return (op === "equals" ||
|
|
907
|
-
op === "gt" ||
|
|
908
|
-
op === "gte" ||
|
|
909
|
-
op === "lt" ||
|
|
910
|
-
op === "lte" ||
|
|
911
|
-
op === "in" ||
|
|
912
|
-
op === "notIn");
|
|
913
|
-
}
|
|
914
|
-
function requireStarCount(selectors, context) {
|
|
915
|
-
if (!hasStarCount(selectors)) {
|
|
916
|
-
throw new Error(`${context} requires _count: true or _count: { _all: true }`);
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
function requireCountMapField(selectors, field, context) {
|
|
920
|
-
if (field === "_all") {
|
|
921
|
-
requireStarCount(selectors, context);
|
|
922
|
-
return;
|
|
923
|
-
}
|
|
924
|
-
if (!hasCountField(selectors, field)) {
|
|
925
|
-
throw new Error(`${context} requires _count: { ${field}: true }`);
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
function isStarHavingSpec(spec) {
|
|
929
|
-
if (typeof spec === "number")
|
|
930
|
-
return true;
|
|
931
|
-
const keys = Object.keys(spec);
|
|
932
|
-
return keys.every((key) => isHavingOperator(key));
|
|
933
|
-
}
|
|
934
|
-
function isMixedCountHaving(spec) {
|
|
935
|
-
const keys = Object.keys(spec);
|
|
936
|
-
const hasOps = keys.some((key) => isHavingOperator(key));
|
|
937
|
-
const hasFields = keys.some((key) => !isHavingOperator(key));
|
|
938
|
-
return hasOps && hasFields;
|
|
939
|
-
}
|
|
940
|
-
function countStarExpr() {
|
|
941
|
-
return "COUNT(*)";
|
|
942
|
-
}
|
|
943
|
-
function countFieldExpr(table, field, manifestIndex) {
|
|
944
|
-
if (field === "_all")
|
|
945
|
-
return countStarExpr();
|
|
946
|
-
return `COUNT(${requireCountSqlCol(table, field, manifestIndex)})`;
|
|
947
|
-
}
|
|
948
|
-
function requireSelectedFieldAgg(selectors, key, colName) {
|
|
949
|
-
if (!selectors[key]?.[colName]) {
|
|
950
|
-
throw new Error(`having.${key}.${colName} requires ${key}: { ${colName}: true }`);
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
function compileHavingCompare(expr, spec, dialect, paramIndex) {
|
|
954
|
-
const conditions = [];
|
|
955
|
-
const params = [];
|
|
956
|
-
let nextParamIndex = paramIndex;
|
|
957
|
-
let impossible = false;
|
|
958
|
-
const ops = typeof spec === "number" ? { equals: spec } : spec;
|
|
959
|
-
for (const [op, value] of Object.entries(ops)) {
|
|
960
|
-
if (!isHavingOperator(op)) {
|
|
961
|
-
throw new Error(`unsupported having operator: ${op}`);
|
|
962
|
-
}
|
|
963
|
-
switch (op) {
|
|
964
|
-
case "in":
|
|
965
|
-
case "notIn": {
|
|
966
|
-
if (Array.isArray(value) && value.length === 0) {
|
|
967
|
-
if (op === "in") {
|
|
968
|
-
conditions.push("1=0");
|
|
969
|
-
impossible = true;
|
|
970
|
-
}
|
|
971
|
-
else {
|
|
972
|
-
conditions.push("1=1");
|
|
973
|
-
}
|
|
974
|
-
break;
|
|
975
|
-
}
|
|
976
|
-
conditions.push(dialect.whereOperators[op](expr, nextParamIndex));
|
|
977
|
-
params.push(value);
|
|
978
|
-
nextParamIndex++;
|
|
979
|
-
break;
|
|
980
|
-
}
|
|
981
|
-
case "equals":
|
|
982
|
-
case "gt":
|
|
983
|
-
case "gte":
|
|
984
|
-
case "lt":
|
|
985
|
-
case "lte": {
|
|
986
|
-
conditions.push(dialect.whereOperators[op](expr, nextParamIndex));
|
|
987
|
-
params.push(value);
|
|
988
|
-
nextParamIndex++;
|
|
989
|
-
break;
|
|
990
|
-
}
|
|
991
|
-
default: {
|
|
992
|
-
const _never = op;
|
|
993
|
-
throw new Error(`unsupported having operator: ${_never}`);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
return {
|
|
998
|
-
sql: conditions.join(" AND "),
|
|
999
|
-
params,
|
|
1000
|
-
nextParamIndex,
|
|
1001
|
-
...(impossible ? { impossible: true } : {}),
|
|
1002
|
-
};
|
|
1003
|
-
}
|
|
1004
|
-
function requireFieldAggExpression(key, table, colName, dialect, manifestIndex) {
|
|
1005
|
-
const expr = fieldAggExpression(key, table, colName, dialect, manifestIndex);
|
|
1006
|
-
if (!expr) {
|
|
1007
|
-
requireTsColumn(getTableIndex(manifestIndex, table.accessor), table, colName, `aggregate ${key}`, "select");
|
|
1008
|
-
}
|
|
1009
|
-
return expr;
|
|
1010
|
-
}
|
|
1011
|
-
export function compileHaving(table, selectors, having, dialect, startParamIndex = 1, manifestIndex) {
|
|
1012
|
-
if (!having || Object.keys(having).length === 0) {
|
|
1013
|
-
return { sql: "", params: [] };
|
|
1014
|
-
}
|
|
1015
|
-
for (const key of Object.keys(having)) {
|
|
1016
|
-
if (key !== "_count" &&
|
|
1017
|
-
key !== "_avg" &&
|
|
1018
|
-
key !== "_sum" &&
|
|
1019
|
-
key !== "_min" &&
|
|
1020
|
-
key !== "_max") {
|
|
1021
|
-
throw new Error(`unsupported having key: ${key}`);
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
const conditions = [];
|
|
1025
|
-
const params = [];
|
|
1026
|
-
let paramIndex = startParamIndex;
|
|
1027
|
-
let impossible = false;
|
|
1028
|
-
const pushCompare = (expr, spec) => {
|
|
1029
|
-
const compiled = compileHavingCompare(expr, spec, dialect, paramIndex);
|
|
1030
|
-
if (compiled.sql)
|
|
1031
|
-
conditions.push(compiled.sql);
|
|
1032
|
-
params.push(...compiled.params);
|
|
1033
|
-
paramIndex = compiled.nextParamIndex;
|
|
1034
|
-
if (compiled.impossible)
|
|
1035
|
-
impossible = true;
|
|
1036
|
-
};
|
|
1037
|
-
if (having._count !== undefined) {
|
|
1038
|
-
const spec = having._count;
|
|
1039
|
-
if (typeof spec === "number") {
|
|
1040
|
-
requireStarCount(selectors, "having._count");
|
|
1041
|
-
pushCompare(countStarExpr(), spec);
|
|
1042
|
-
}
|
|
1043
|
-
else if (typeof spec === "object" && spec !== null) {
|
|
1044
|
-
if (isMixedCountHaving(spec)) {
|
|
1045
|
-
throw new Error("having._count cannot mix comparison operators with field keys");
|
|
1046
|
-
}
|
|
1047
|
-
if (isStarHavingSpec(spec)) {
|
|
1048
|
-
requireStarCount(selectors, "having._count");
|
|
1049
|
-
pushCompare(countStarExpr(), spec);
|
|
1050
|
-
}
|
|
1051
|
-
else {
|
|
1052
|
-
for (const [field, fieldSpec] of Object.entries(spec)) {
|
|
1053
|
-
if (typeof fieldSpec === "number") {
|
|
1054
|
-
requireCountMapField(selectors, field, `having._count.${field}`);
|
|
1055
|
-
pushCompare(countFieldExpr(table, field, manifestIndex), fieldSpec);
|
|
1056
|
-
continue;
|
|
1057
|
-
}
|
|
1058
|
-
if (typeof fieldSpec !== "object" || fieldSpec === null) {
|
|
1059
|
-
throw new Error(`invalid having._count.${field} predicate`);
|
|
1060
|
-
}
|
|
1061
|
-
requireCountMapField(selectors, field, `having._count.${field}`);
|
|
1062
|
-
pushCompare(countFieldExpr(table, field, manifestIndex), fieldSpec);
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
for (const key of FIELD_AGG_KEYS) {
|
|
1068
|
-
const fieldMap = having[key];
|
|
1069
|
-
if (!fieldMap)
|
|
1070
|
-
continue;
|
|
1071
|
-
for (const [colName, spec] of Object.entries(fieldMap)) {
|
|
1072
|
-
requireSelectedFieldAgg(selectors, key, colName);
|
|
1073
|
-
if (typeof spec !== "number" &&
|
|
1074
|
-
(typeof spec !== "object" || spec === null)) {
|
|
1075
|
-
throw new Error(`invalid having.${key}.${colName} predicate`);
|
|
1076
|
-
}
|
|
1077
|
-
const expr = requireFieldAggExpression(key, table, colName, dialect, manifestIndex);
|
|
1078
|
-
pushCompare(expr, spec);
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
if (conditions.length === 0)
|
|
1082
|
-
return { sql: "", params: [] };
|
|
1083
|
-
return {
|
|
1084
|
-
sql: `HAVING ${conditions.join(" AND ")}`,
|
|
1085
|
-
params,
|
|
1086
|
-
...(impossible ? { impossible: true } : {}),
|
|
1087
|
-
};
|
|
1088
|
-
}
|
|
1089
|
-
export function compileGroupByOrderBy(table, byKeys, selectors, orderBy, dialect = postgresDialect, manifestIndex) {
|
|
1090
|
-
if (!orderBy || Object.keys(orderBy).length === 0)
|
|
1091
|
-
return "";
|
|
1092
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
1093
|
-
const bySet = new Set(byKeys);
|
|
1094
|
-
const parts = [];
|
|
1095
|
-
for (const [tsKey, direction] of Object.entries(orderBy)) {
|
|
1096
|
-
if (tsKey === "_count") {
|
|
1097
|
-
if (typeof direction === "string") {
|
|
1098
|
-
requireStarCount(selectors, "orderBy._count");
|
|
1099
|
-
const dir = direction.toUpperCase() === "DESC" ? "DESC" : "ASC";
|
|
1100
|
-
parts.push(`${countStarExpr()} ${dir}`);
|
|
1101
|
-
continue;
|
|
1102
|
-
}
|
|
1103
|
-
if (typeof direction !== "object" || direction === null) {
|
|
1104
|
-
throw new Error('orderBy._count must be "asc" or "desc" or a field map');
|
|
1105
|
-
}
|
|
1106
|
-
for (const [field, colDir] of Object.entries(direction)) {
|
|
1107
|
-
if (typeof colDir !== "string")
|
|
1108
|
-
continue;
|
|
1109
|
-
requireCountMapField(selectors, field, `orderBy._count.${field}`);
|
|
1110
|
-
const dir = colDir.toUpperCase() === "DESC" ? "DESC" : "ASC";
|
|
1111
|
-
parts.push(`${countFieldExpr(table, field, manifestIndex)} ${dir}`);
|
|
1112
|
-
}
|
|
1113
|
-
continue;
|
|
1114
|
-
}
|
|
1115
|
-
if (tsKey === "_avg" ||
|
|
1116
|
-
tsKey === "_sum" ||
|
|
1117
|
-
tsKey === "_min" ||
|
|
1118
|
-
tsKey === "_max") {
|
|
1119
|
-
const key = tsKey;
|
|
1120
|
-
if (typeof direction !== "object" || direction === null) {
|
|
1121
|
-
throw new Error(`orderBy.${key} must be a column map`);
|
|
1122
|
-
}
|
|
1123
|
-
for (const [colName, colDir] of Object.entries(direction)) {
|
|
1124
|
-
if (typeof colDir !== "string")
|
|
1125
|
-
continue;
|
|
1126
|
-
if (!selectors[key]?.[colName]) {
|
|
1127
|
-
throw new Error(`orderBy.${key}.${colName} requires ${key}: { ${colName}: true }`);
|
|
1128
|
-
}
|
|
1129
|
-
const expr = requireFieldAggExpression(key, table, colName, dialect, manifestIndex);
|
|
1130
|
-
const dir = colDir.toUpperCase() === "DESC" ? "DESC" : "ASC";
|
|
1131
|
-
parts.push(`${expr} ${dir}`);
|
|
1132
|
-
}
|
|
1133
|
-
continue;
|
|
1134
|
-
}
|
|
1135
|
-
if (typeof direction !== "string")
|
|
1136
|
-
continue;
|
|
1137
|
-
if (!bySet.has(tsKey)) {
|
|
1138
|
-
throw new Error(`orderBy column "${tsKey}" is not in groupBy by`);
|
|
1139
|
-
}
|
|
1140
|
-
const col = requireTsColumn(tableIndex, table, tsKey, "groupBy orderBy", "select");
|
|
1141
|
-
const dir = direction.toUpperCase() === "DESC" ? "DESC" : "ASC";
|
|
1142
|
-
parts.push(`${quoteIdentifier(col.sqlName)} ${dir}`);
|
|
1143
|
-
}
|
|
1144
|
-
return parts.length > 0 ? `ORDER BY ${parts.join(", ")}` : "";
|
|
1145
|
-
}
|
|
1146
|
-
export function resolveGroupByColumns(table, byKeys, manifestIndex) {
|
|
1147
|
-
if (byKeys.length === 0) {
|
|
1148
|
-
throw new Error("groupBy requires at least one column");
|
|
1149
|
-
}
|
|
1150
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
1151
|
-
const cols = [];
|
|
1152
|
-
for (const key of byKeys) {
|
|
1153
|
-
cols.push(requireTsColumn(tableIndex, table, key, "groupBy", "select"));
|
|
1154
|
-
}
|
|
1155
|
-
return cols;
|
|
1156
|
-
}
|
|
1157
|
-
export function buildGroupByQuery(table, byKeys, selectors, whereSql, havingSql, orderSql, take, skip, manifestIndex, dialect = postgresDialect) {
|
|
1158
|
-
const byCols = resolveGroupByColumns(table, byKeys, manifestIndex);
|
|
1159
|
-
const selectBy = buildSelectColumns(table, byKeys, manifestIndex);
|
|
1160
|
-
const aggParts = aggregateSelectParts(table, selectors, dialect, manifestIndex);
|
|
1161
|
-
const selectList = aggParts.length > 0 ? `${selectBy}, ${aggParts.join(", ")}` : selectBy;
|
|
1162
|
-
const groupList = byCols
|
|
1163
|
-
.map((col) => quoteIdentifier(col.sqlName))
|
|
1164
|
-
.join(", ");
|
|
1165
|
-
let sql = `SELECT ${selectList} FROM ${tableRef(table)}`;
|
|
1166
|
-
if (whereSql)
|
|
1167
|
-
sql += ` ${whereSql}`;
|
|
1168
|
-
sql += ` GROUP BY ${groupList}`;
|
|
1169
|
-
if (havingSql)
|
|
1170
|
-
sql += ` ${havingSql}`;
|
|
1171
|
-
if (orderSql)
|
|
1172
|
-
sql += ` ${orderSql}`;
|
|
1173
|
-
if (take !== undefined) {
|
|
1174
|
-
sql += ` LIMIT ${normalizeLimitOffset(take, "take")}`;
|
|
1175
|
-
}
|
|
1176
|
-
if (skip !== undefined) {
|
|
1177
|
-
sql += ` OFFSET ${normalizeLimitOffset(skip, "skip")}`;
|
|
1178
|
-
}
|
|
1179
|
-
return sql;
|
|
1180
|
-
}
|
|
1181
|
-
export function getCachedGroupByQuery(tableIndex, table, byKeys, selectors, whereSql, havingSql, orderSql, take, skip, manifestIndex, dialect = postgresDialect) {
|
|
1182
|
-
const cacheKey = `${dialect.name}|${byKeys.join(",")}|${aggregateSelectorCacheKey(selectors)}|${whereSql}|${havingSql}|${orderSql}|${take ?? ""}|${skip ?? ""}`;
|
|
1183
|
-
if (!tableIndex) {
|
|
1184
|
-
return buildGroupByQuery(table, byKeys, selectors, whereSql, havingSql, orderSql, take, skip, manifestIndex, dialect);
|
|
1185
|
-
}
|
|
1186
|
-
return getOrSetSqlCache(tableIndex.groupBySqlBySignature, cacheKey, () => buildGroupByQuery(table, byKeys, selectors, whereSql, havingSql, orderSql, take, skip, manifestIndex, dialect));
|
|
1187
|
-
}
|
|
1188
|
-
export function buildUpsertQuery(table, insertKeys, updateKeys, conflictSqlColumns, exprSets = [], manifestIndex, dialect = postgresDialect, updateOps) {
|
|
1189
|
-
const insertCols = insertKeys.map((k) => {
|
|
1190
|
-
const col = colByTs(table, k, manifestIndex);
|
|
1191
|
-
return quoteIdentifier(col?.sqlName ?? k);
|
|
1192
|
-
});
|
|
1193
|
-
const insertPlaceholders = insertKeys
|
|
1194
|
-
.map((k, i) => {
|
|
1195
|
-
const col = colByTs(table, k, manifestIndex);
|
|
1196
|
-
return buildValuePlaceholder(col, i + 1);
|
|
1197
|
-
})
|
|
1198
|
-
.join(", ");
|
|
1199
|
-
const selectCols = buildSelectColumns(table, undefined, manifestIndex);
|
|
1200
|
-
const conflictCols = conflictSqlColumns
|
|
1201
|
-
.map((c) => quoteIdentifier(c))
|
|
1202
|
-
.join(", ");
|
|
1203
|
-
let nextParam = insertKeys.length + 1;
|
|
1204
|
-
const updateSets = updateKeys.length > 0
|
|
1205
|
-
? updateKeys.map((k, i) => {
|
|
1206
|
-
const col = colByTs(table, k, manifestIndex);
|
|
1207
|
-
const sqlCol = quoteIdentifier(col?.sqlName ?? k);
|
|
1208
|
-
const op = updateOps?.[i] ?? "set";
|
|
1209
|
-
if (op === "set") {
|
|
1210
|
-
return `${sqlCol} = excluded.${sqlCol}`;
|
|
1211
|
-
}
|
|
1212
|
-
const expr = buildSetExpression(col, nextParam, op, dialect);
|
|
1213
|
-
nextParam++;
|
|
1214
|
-
return expr;
|
|
1215
|
-
})
|
|
1216
|
-
: exprSets.length === 0
|
|
1217
|
-
? conflictSqlColumns.map((c) => {
|
|
1218
|
-
const sqlCol = quoteIdentifier(c);
|
|
1219
|
-
return `${sqlCol} = excluded.${sqlCol}`;
|
|
1220
|
-
})
|
|
1221
|
-
: [];
|
|
1222
|
-
const allUpdateSets = [...updateSets, ...exprSets];
|
|
1223
|
-
return `INSERT INTO ${tableRef(table)} (${insertCols.join(", ")}) VALUES (${insertPlaceholders}) ON CONFLICT (${conflictCols}) DO UPDATE SET ${allUpdateSets.join(", ")} RETURNING ${selectCols}`;
|
|
1224
|
-
}
|
|
1225
|
-
export const FIND_OR_CREATE_FLAG = "__neoorm_created";
|
|
1226
|
-
export function buildFindOrCreateQuery(table, insertKeys, conflictSqlColumns, fallbackWhereBody, manifestIndex) {
|
|
1227
|
-
const insertCols = insertKeys.map((k) => {
|
|
1228
|
-
const col = colByTs(table, k, manifestIndex);
|
|
1229
|
-
return quoteIdentifier(col?.sqlName ?? k);
|
|
1230
|
-
});
|
|
1231
|
-
const insertPlaceholders = insertKeys
|
|
1232
|
-
.map((k, i) => {
|
|
1233
|
-
const col = colByTs(table, k, manifestIndex);
|
|
1234
|
-
return buildValuePlaceholder(col, i + 1);
|
|
1235
|
-
})
|
|
1236
|
-
.join(", ");
|
|
1237
|
-
const selectCols = buildSelectColumns(table, undefined, manifestIndex);
|
|
1238
|
-
const conflictCols = conflictSqlColumns
|
|
1239
|
-
.map((c) => quoteIdentifier(c))
|
|
1240
|
-
.join(", ");
|
|
1241
|
-
const tableSql = tableRef(table);
|
|
1242
|
-
const fallbackClause = fallbackWhereBody
|
|
1243
|
-
? ` AND (${fallbackWhereBody})`
|
|
1244
|
-
: "";
|
|
1245
|
-
return `WITH ins AS (
|
|
1246
|
-
INSERT INTO ${tableSql} (${insertCols.join(", ")}) VALUES (${insertPlaceholders})
|
|
1247
|
-
ON CONFLICT (${conflictCols}) DO NOTHING
|
|
1248
|
-
RETURNING ${selectCols}
|
|
1249
|
-
)
|
|
1250
|
-
SELECT ${selectCols}, true AS "${FIND_OR_CREATE_FLAG}" FROM ins
|
|
1251
|
-
UNION ALL
|
|
1252
|
-
SELECT ${selectCols}, false AS "${FIND_OR_CREATE_FLAG}" FROM ${tableSql} t
|
|
1253
|
-
WHERE NOT EXISTS (SELECT 1 FROM ins)${fallbackClause}
|
|
1254
|
-
LIMIT 1`;
|
|
1255
|
-
}
|
|
1256
|
-
/**
|
|
1257
|
-
* "pk" returning is impossible for tables without a primary key: the column
|
|
1258
|
-
* list would be empty, producing a dangling `RETURNING` clause that databases
|
|
1259
|
-
* reject. Fall back to returning the full row instead.
|
|
1260
|
-
*/
|
|
1261
|
-
export function resolveReturning(table, returning) {
|
|
1262
|
-
if (returning === "pk" && table.primaryKey.length === 0) {
|
|
1263
|
-
return "full";
|
|
1264
|
-
}
|
|
1265
|
-
return returning;
|
|
1266
|
-
}
|
|
1267
|
-
export function buildInsertQuery(table, dataKeys, manifestIndex, returning = "pk") {
|
|
1268
|
-
if (dataKeys.length === 0) {
|
|
1269
|
-
throw new Error("Cannot build INSERT query with no columns");
|
|
1270
|
-
}
|
|
1271
|
-
const orderedKeys = [...dataKeys].sort();
|
|
1272
|
-
const cols = orderedKeys.map((k) => {
|
|
1273
|
-
const col = colByTs(table, k, manifestIndex);
|
|
1274
|
-
return quoteIdentifier(col?.sqlName ?? k);
|
|
1275
|
-
});
|
|
1276
|
-
const placeholders = orderedKeys
|
|
1277
|
-
.map((k, i) => {
|
|
1278
|
-
const col = colByTs(table, k, manifestIndex);
|
|
1279
|
-
return buildValuePlaceholder(col, i + 1);
|
|
1280
|
-
})
|
|
1281
|
-
.join(", ");
|
|
1282
|
-
const sql = `INSERT INTO ${tableRef(table)} (${cols.join(", ")}) VALUES (${placeholders})`;
|
|
1283
|
-
if (returning === "none")
|
|
1284
|
-
return sql;
|
|
1285
|
-
const effectiveReturning = resolveReturning(table, returning);
|
|
1286
|
-
const returningCols = effectiveReturning === "full"
|
|
1287
|
-
? buildSelectColumns(table, undefined, manifestIndex)
|
|
1288
|
-
: buildReturningPkColumns(table, manifestIndex);
|
|
1289
|
-
return `${sql} RETURNING ${returningCols}`;
|
|
1290
|
-
}
|
|
1291
|
-
export function getCachedInsertQuery(tableIndex, table, dataKeys, returning, manifestIndex) {
|
|
1292
|
-
const orderedKeys = [...dataKeys].sort();
|
|
1293
|
-
const cacheKey = `${sortedKeysCacheKey(orderedKeys)}:${returning}`;
|
|
1294
|
-
if (!tableIndex) {
|
|
1295
|
-
return buildInsertQuery(table, orderedKeys, manifestIndex, returning);
|
|
1296
|
-
}
|
|
1297
|
-
return getOrSetSqlCache(tableIndex.insertSqlByKeys, cacheKey, () => buildInsertQuery(table, orderedKeys, manifestIndex, returning));
|
|
1298
|
-
}
|
|
1299
|
-
export function buildInsertManyValueRows(table, dataKeys, rows, manifestIndex) {
|
|
1300
|
-
if (dataKeys.length === 0) {
|
|
1301
|
-
throw new Error("Cannot build INSERT many value rows with no columns");
|
|
1302
|
-
}
|
|
1303
|
-
const valueRows = [];
|
|
1304
|
-
const values = [];
|
|
1305
|
-
let paramIndex = 1;
|
|
1306
|
-
for (const row of rows) {
|
|
1307
|
-
const placeholders = [];
|
|
1308
|
-
for (let i = 0; i < dataKeys.length; i++) {
|
|
1309
|
-
const key = dataKeys[i];
|
|
1310
|
-
if (key === undefined) {
|
|
1311
|
-
throw new Error("dataKeys index out of bounds");
|
|
1312
|
-
}
|
|
1313
|
-
const col = colByTs(table, key, manifestIndex);
|
|
1314
|
-
const val = row[i];
|
|
1315
|
-
if (val === undefined) {
|
|
1316
|
-
placeholders.push("DEFAULT");
|
|
1317
|
-
}
|
|
1318
|
-
else {
|
|
1319
|
-
placeholders.push(buildValuePlaceholder(col, paramIndex));
|
|
1320
|
-
values.push(val);
|
|
1321
|
-
paramIndex++;
|
|
1322
|
-
}
|
|
1323
|
-
}
|
|
1324
|
-
valueRows.push(`(${placeholders.join(", ")})`);
|
|
1325
|
-
}
|
|
1326
|
-
return { valueRows, values };
|
|
1327
|
-
}
|
|
1328
|
-
export function buildInsertManyQuery(table, dataKeys, valueRows, manifestIndex, skipDuplicates = false, dialect = postgresDialect) {
|
|
1329
|
-
if (dataKeys.length === 0) {
|
|
1330
|
-
throw new Error("Cannot build INSERT many query with no columns");
|
|
1331
|
-
}
|
|
1332
|
-
const cols = dataKeys.map((k) => {
|
|
1333
|
-
const col = colByTs(table, k, manifestIndex);
|
|
1334
|
-
return quoteIdentifier(col?.sqlName ?? k);
|
|
1335
|
-
});
|
|
1336
|
-
const selectCols = buildSelectColumns(table, undefined, manifestIndex);
|
|
1337
|
-
const conflict = skipDuplicates ? ` ${dialect.onConflictDoNothing()}` : "";
|
|
1338
|
-
return `INSERT INTO ${tableRef(table)} (${cols.join(", ")}) VALUES ${valueRows.join(", ")}${conflict} RETURNING ${selectCols}`;
|
|
1339
|
-
}
|
|
1340
|
-
export function buildUpdateQuery(table, dataKeys, whereSql, exprSets = [], manifestIndex, returning = "full", dialect = postgresDialect, ops) {
|
|
1341
|
-
const ordered = orderUpdateAssignments(dataKeys, ops);
|
|
1342
|
-
const paramSets = ordered.keys.map((k, i) => {
|
|
1343
|
-
const col = colByTs(table, k, manifestIndex);
|
|
1344
|
-
const op = ordered.ops[i] ?? "set";
|
|
1345
|
-
return buildSetExpression(col, i + 1, op, dialect);
|
|
1346
|
-
});
|
|
1347
|
-
const sets = [...paramSets, ...exprSets];
|
|
1348
|
-
const whereOffset = ordered.keys.length;
|
|
1349
|
-
let sql = `UPDATE ${tableRef(table)} SET ${sets.join(", ")}`;
|
|
1350
|
-
if (whereSql) {
|
|
1351
|
-
const adjustedWhere = rebaseParamRefs(whereSql, whereOffset);
|
|
1352
|
-
sql += ` ${adjustedWhere}`;
|
|
1353
|
-
}
|
|
1354
|
-
if (returning === "none")
|
|
1355
|
-
return sql;
|
|
1356
|
-
const effectiveReturning = resolveReturning(table, returning);
|
|
1357
|
-
const returningCols = effectiveReturning === "full"
|
|
1358
|
-
? buildSelectColumns(table, undefined, manifestIndex)
|
|
1359
|
-
: buildReturningPkColumns(table, manifestIndex);
|
|
1360
|
-
return `${sql} RETURNING ${returningCols}`;
|
|
1361
|
-
}
|
|
1362
|
-
export function buildReturningPkColumns(table, manifestIndex) {
|
|
1363
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
1364
|
-
return table.primaryKey
|
|
1365
|
-
.map((sqlName) => {
|
|
1366
|
-
const col = columnBySqlName(tableIndex, table, sqlName);
|
|
1367
|
-
return quoteIdentifier(col?.sqlName ?? sqlName);
|
|
1368
|
-
})
|
|
1369
|
-
.join(", ");
|
|
1370
|
-
}
|
|
1371
|
-
export function buildDeleteQuery(table, whereSql, returning, manifestIndex) {
|
|
1372
|
-
const effectiveReturning = resolveReturning(table, returning);
|
|
1373
|
-
const selectCols = effectiveReturning === "full"
|
|
1374
|
-
? buildSelectColumns(table, undefined, manifestIndex)
|
|
1375
|
-
: buildReturningPkColumns(table, manifestIndex);
|
|
1376
|
-
let sql = `DELETE FROM ${tableRef(table)}`;
|
|
1377
|
-
if (whereSql)
|
|
1378
|
-
sql += ` ${whereSql}`;
|
|
1379
|
-
sql += ` RETURNING ${selectCols}`;
|
|
1380
|
-
return sql;
|
|
1381
|
-
}
|
|
1382
|
-
export function buildDeleteManyQuery(table, whereSql) {
|
|
1383
|
-
let sql = `DELETE FROM ${tableRef(table)}`;
|
|
1384
|
-
if (whereSql)
|
|
1385
|
-
sql += ` ${whereSql}`;
|
|
1386
|
-
return sql;
|
|
1387
|
-
}
|
|
1388
|
-
export function buildUpdateManyQuery(table, dataKeys, whereSql, exprSets = [], manifestIndex, dialect = postgresDialect, ops) {
|
|
1389
|
-
const ordered = orderUpdateAssignments(dataKeys, ops);
|
|
1390
|
-
const paramSets = ordered.keys.map((k, i) => {
|
|
1391
|
-
const col = colByTs(table, k, manifestIndex);
|
|
1392
|
-
const op = ordered.ops[i] ?? "set";
|
|
1393
|
-
return buildSetExpression(col, i + 1, op, dialect);
|
|
1394
|
-
});
|
|
1395
|
-
const sets = [...paramSets, ...exprSets];
|
|
1396
|
-
const whereOffset = ordered.keys.length;
|
|
1397
|
-
let sql = `UPDATE ${tableRef(table)} SET ${sets.join(", ")}`;
|
|
1398
|
-
if (whereSql) {
|
|
1399
|
-
const adjustedWhere = rebaseParamRefs(whereSql, whereOffset);
|
|
1400
|
-
sql += ` ${adjustedWhere}`;
|
|
1401
|
-
}
|
|
1402
|
-
return sql;
|
|
1403
|
-
}
|
|
1404
|
-
export function getCachedUpdateManyQuery(tableIndex, table, dataKeys, whereSql, exprSets, manifestIndex, dialect = postgresDialect, ops) {
|
|
1405
|
-
const ordered = orderUpdateAssignments(dataKeys, ops);
|
|
1406
|
-
const opKey = ordered.keys
|
|
1407
|
-
.map((key, i) => `${key}:${ordered.ops[i] ?? "set"}`)
|
|
1408
|
-
.join(",");
|
|
1409
|
-
const cacheKey = `${dialect.name}|${opKey}|${exprSets.length}|${whereSql}`;
|
|
1410
|
-
if (!tableIndex) {
|
|
1411
|
-
return buildUpdateManyQuery(table, ordered.keys, whereSql, exprSets, manifestIndex, dialect, ordered.ops);
|
|
1412
|
-
}
|
|
1413
|
-
return getOrSetSqlCache(tableIndex.updateManySqlByKeys, cacheKey, () => buildUpdateManyQuery(table, ordered.keys, whereSql, exprSets, manifestIndex, dialect, ordered.ops));
|
|
1414
|
-
}
|
|
1415
|
-
export function getCachedFindManyQuery(tableIndex, signature, build) {
|
|
1416
|
-
if (!tableIndex)
|
|
1417
|
-
return build();
|
|
1418
|
-
return getOrSetSqlCache(tableIndex.findManySqlBySignature, signature, build);
|
|
1419
|
-
}
|
|
1420
|
-
export function dataToSqlValues(table, data, options, manifestIndex, dialect = postgresDialect) {
|
|
1421
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
1422
|
-
const keys = [];
|
|
1423
|
-
const values = [];
|
|
1424
|
-
for (const [key, value] of Object.entries(data)) {
|
|
1425
|
-
const col = columnByTsName(tableIndex, table, key);
|
|
1426
|
-
if (!col)
|
|
1427
|
-
continue;
|
|
1428
|
-
if (options?.excludePrimary && col.primary)
|
|
1429
|
-
continue;
|
|
1430
|
-
if (value === undefined)
|
|
1431
|
-
continue;
|
|
1432
|
-
keys.push(key);
|
|
1433
|
-
values.push(serializeColumnValue(col, value, dialect));
|
|
1434
|
-
}
|
|
1435
|
-
return reorderKeyValues(keys, values);
|
|
1436
|
-
}
|
|
1437
|
-
export function dataToUpdateAssignments(table, data, options, manifestIndex, dialect = postgresDialect) {
|
|
1438
|
-
const tableIndex = getTableIndex(manifestIndex, table.accessor);
|
|
1439
|
-
const keys = [];
|
|
1440
|
-
const ops = [];
|
|
1441
|
-
const values = [];
|
|
1442
|
-
for (const [key, raw] of Object.entries(data)) {
|
|
1443
|
-
const col = columnByTsName(tableIndex, table, key);
|
|
1444
|
-
if (!col)
|
|
1445
|
-
continue;
|
|
1446
|
-
if (options?.excludePrimary && col.primary)
|
|
1447
|
-
continue;
|
|
1448
|
-
if (raw === undefined)
|
|
1449
|
-
continue;
|
|
1450
|
-
const parsed = parseAtomicUpdate(col, raw);
|
|
1451
|
-
keys.push(key);
|
|
1452
|
-
ops.push(parsed.op);
|
|
1453
|
-
values.push(serializeColumnValue(col, parsed.value, dialect));
|
|
1454
|
-
}
|
|
1455
|
-
if (keys.length <= 1)
|
|
1456
|
-
return { keys, ops, values };
|
|
1457
|
-
const pairs = keys.map((key, index) => ({
|
|
1458
|
-
key,
|
|
1459
|
-
op: ops[index] ?? "set",
|
|
1460
|
-
value: values[index],
|
|
1461
|
-
}));
|
|
1462
|
-
pairs.sort((a, b) => a.key.localeCompare(b.key));
|
|
1463
|
-
return {
|
|
1464
|
-
keys: pairs.map((pair) => pair.key),
|
|
1465
|
-
ops: pairs.map((pair) => pair.op),
|
|
1466
|
-
values: pairs.map((pair) => pair.value),
|
|
1467
|
-
};
|
|
1468
|
-
}
|
|
1469
|
-
export function upsertAtomicValues(ops, values) {
|
|
1470
|
-
const extra = [];
|
|
1471
|
-
for (let i = 0; i < ops.length; i++) {
|
|
1472
|
-
if (ops[i] !== "set")
|
|
1473
|
-
extra.push(values[i]);
|
|
1474
|
-
}
|
|
1475
|
-
return extra;
|
|
1476
|
-
}
|
|
1477
|
-
export function rowToTs(table, row) {
|
|
1478
|
-
const result = {};
|
|
1479
|
-
for (const col of table.columns) {
|
|
1480
|
-
if (col.sqlName in row) {
|
|
1481
|
-
const raw = row[col.sqlName];
|
|
1482
|
-
if (col.kind === "fk") {
|
|
1483
|
-
result[col.tsName] = raw;
|
|
1484
|
-
continue;
|
|
1485
|
-
}
|
|
1486
|
-
const plugin = getColumnType(col.kind);
|
|
1487
|
-
result[col.tsName] = plugin?.deserializeValue
|
|
1488
|
-
? plugin.deserializeValue(col, raw)
|
|
1489
|
-
: raw;
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
return result;
|
|
1493
|
-
}
|
|
1494
|
-
function mapKnownTableColumns(table, row) {
|
|
1495
|
-
const result = {};
|
|
1496
|
-
for (const col of table.columns) {
|
|
1497
|
-
let raw;
|
|
1498
|
-
if (col.tsName in row) {
|
|
1499
|
-
raw = row[col.tsName];
|
|
1500
|
-
}
|
|
1501
|
-
else if (col.sqlName in row) {
|
|
1502
|
-
raw = row[col.sqlName];
|
|
1503
|
-
}
|
|
1504
|
-
else {
|
|
1505
|
-
continue;
|
|
1506
|
-
}
|
|
1507
|
-
if (col.kind === "fk") {
|
|
1508
|
-
result[col.tsName] = raw;
|
|
1509
|
-
continue;
|
|
1510
|
-
}
|
|
1511
|
-
const plugin = getColumnType(col.kind);
|
|
1512
|
-
result[col.tsName] = plugin?.deserializeValue
|
|
1513
|
-
? plugin.deserializeValue(col, raw)
|
|
1514
|
-
: raw;
|
|
1515
|
-
}
|
|
1516
|
-
return result;
|
|
1517
|
-
}
|
|
1518
|
-
export function rowToTsIndexed(_index, table, row) {
|
|
1519
|
-
return mapKnownTableColumns(table, row);
|
|
1520
|
-
}
|
|
1521
|
-
export function rowsToTsIndexed(index, table, rows) {
|
|
1522
|
-
return rows.map((row) => rowToTsIndexed(index, table, row));
|
|
1523
|
-
}
|
|
1524
|
-
export function rowsToTs(table, rows) {
|
|
1525
|
-
return rows.map((row) => rowToTs(table, row));
|
|
1526
|
-
}
|
|
1527
|
-
export function mapRowToTs(tableIndex, table, row) {
|
|
1528
|
-
return tableIndex
|
|
1529
|
-
? rowToTsIndexed(tableIndex, table, row)
|
|
1530
|
-
: rowToTs(table, row);
|
|
1531
|
-
}
|
|
1532
|
-
export function mapRowsToTs(tableIndex, table, rows) {
|
|
1533
|
-
return tableIndex
|
|
1534
|
-
? rowsToTsIndexed(tableIndex, table, rows)
|
|
1535
|
-
: rowsToTs(table, rows);
|
|
1536
|
-
}
|
|
1
|
+
export { aggregateSelectorCacheKey, aggregateSelectParts, buildAggregateQuery, buildCountQuery, buildGroupByQuery, compileGroupByOrderBy, compileHaving, countSelectParts, getCachedAggregateQuery, getCachedGroupByQuery, hasCountField, hasStarCount, normalizeCountMap, requireCountSqlCol, resolveGroupByColumns, toCountSelector, } from "./compile-aggregate.js";
|
|
2
|
+
export { buildExistsQuery, buildFindAllQuery, buildFindByIdQuery, buildFindManyQuery, buildPaginateQuery, buildQualifiedSelectColumns, buildSelectColumns, columnsForOutput, compileOrderBy, compileWhere, getCachedFindManyQuery, getCachedOrderByClause, getCachedWhereClause, isImpossibleWhere, isImpossibleWhereSql, normalizeLimitOffset, normalizeSelectColumns, orderByShapeKey, serializeColumnValue, whereShapeKey, } from "./compile-where.js";
|
|
3
|
+
export { buildDeleteManyQuery, buildDeleteQuery, buildFindOrCreateQuery, buildInsertManyQuery, buildInsertManyValueRows, buildInsertQuery, buildReturningPkColumns, buildUpdateManyQuery, buildUpdateQuery, buildUpsertQuery, dataToSqlValues, dataToUpdateAssignments, FIND_OR_CREATE_FLAG, getCachedDeleteManyQuery, getCachedInsertQuery, getCachedUpdateManyQuery, mapRowsToTs, mapRowToTs, parseAtomicUpdate, resolveReturning, rowsToTs, rowsToTsIndexed, rowToTs, rowToTsIndexed, upsertAtomicValues, } from "./compile-write.js";
|
|
1537
4
|
//# sourceMappingURL=compile.js.map
|