relq 1.0.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/LICENSE +21 -0
- package/README.md +862 -0
- package/dist/addons/buffer.js +1869 -0
- package/dist/addons/pg-cursor.js +1425 -0
- package/dist/addons/pg-format.js +2248 -0
- package/dist/addons/pg.js +4790 -0
- package/dist/bin/relq.js +2 -0
- package/dist/cjs/cache/index.cjs +9 -0
- package/dist/cjs/cache/query-cache.cjs +311 -0
- package/dist/cjs/cli/commands/add.cjs +82 -0
- package/dist/cjs/cli/commands/commit.cjs +145 -0
- package/dist/cjs/cli/commands/diff.cjs +84 -0
- package/dist/cjs/cli/commands/export.cjs +333 -0
- package/dist/cjs/cli/commands/fetch.cjs +59 -0
- package/dist/cjs/cli/commands/generate.cjs +242 -0
- package/dist/cjs/cli/commands/history.cjs +165 -0
- package/dist/cjs/cli/commands/import.cjs +524 -0
- package/dist/cjs/cli/commands/init.cjs +437 -0
- package/dist/cjs/cli/commands/introspect.cjs +142 -0
- package/dist/cjs/cli/commands/log.cjs +62 -0
- package/dist/cjs/cli/commands/migrate.cjs +167 -0
- package/dist/cjs/cli/commands/pull.cjs +410 -0
- package/dist/cjs/cli/commands/push.cjs +165 -0
- package/dist/cjs/cli/commands/rollback.cjs +169 -0
- package/dist/cjs/cli/commands/status.cjs +110 -0
- package/dist/cjs/cli/commands/sync.cjs +79 -0
- package/dist/cjs/cli/index.cjs +275 -0
- package/dist/cjs/cli/utils/change-tracker.cjs +446 -0
- package/dist/cjs/cli/utils/commit-manager.cjs +239 -0
- package/dist/cjs/cli/utils/config-loader.cjs +127 -0
- package/dist/cjs/cli/utils/env-loader.cjs +62 -0
- package/dist/cjs/cli/utils/fast-introspect.cjs +398 -0
- package/dist/cjs/cli/utils/git-utils.cjs +404 -0
- package/dist/cjs/cli/utils/migration-generator.cjs +269 -0
- package/dist/cjs/cli/utils/relqignore.cjs +114 -0
- package/dist/cjs/cli/utils/repo-manager.cjs +515 -0
- package/dist/cjs/cli/utils/schema-comparator.cjs +313 -0
- package/dist/cjs/cli/utils/schema-diff.cjs +284 -0
- package/dist/cjs/cli/utils/schema-hash.cjs +108 -0
- package/dist/cjs/cli/utils/schema-introspect.cjs +455 -0
- package/dist/cjs/cli/utils/snapshot-manager.cjs +223 -0
- package/dist/cjs/cli/utils/spinner.cjs +108 -0
- package/dist/cjs/cli/utils/sql-generator.cjs +520 -0
- package/dist/cjs/cli/utils/sql-parser.cjs +999 -0
- package/dist/cjs/cli/utils/type-generator.cjs +2061 -0
- package/dist/cjs/condition/array-condition-builder.cjs +503 -0
- package/dist/cjs/condition/array-numeric-condition-builder.cjs +186 -0
- package/dist/cjs/condition/array-specialized-condition-builder.cjs +206 -0
- package/dist/cjs/condition/array-string-condition-builder.cjs +146 -0
- package/dist/cjs/condition/base-condition-builder.cjs +2 -0
- package/dist/cjs/condition/condition-collector.cjs +284 -0
- package/dist/cjs/condition/fulltext-condition-builder.cjs +61 -0
- package/dist/cjs/condition/geometric-condition-builder.cjs +208 -0
- package/dist/cjs/condition/index.cjs +25 -0
- package/dist/cjs/condition/jsonb-condition-builder.cjs +160 -0
- package/dist/cjs/condition/network-condition-builder.cjs +230 -0
- package/dist/cjs/condition/range-condition-builder.cjs +82 -0
- package/dist/cjs/config/config.cjs +190 -0
- package/dist/cjs/config/index.cjs +9 -0
- package/dist/cjs/constants/pg-values.cjs +68 -0
- package/dist/cjs/copy/copy-builder.cjs +316 -0
- package/dist/cjs/copy/index.cjs +6 -0
- package/dist/cjs/core/query-builder.cjs +440 -0
- package/dist/cjs/core/relq-client.cjs +1831 -0
- package/dist/cjs/core/typed-kuery-client.cjs +2 -0
- package/dist/cjs/count/count-builder.cjs +88 -0
- package/dist/cjs/count/index.cjs +5 -0
- package/dist/cjs/cte/cte-builder.cjs +89 -0
- package/dist/cjs/cte/index.cjs +5 -0
- package/dist/cjs/ddl/function.cjs +48 -0
- package/dist/cjs/ddl/index.cjs +7 -0
- package/dist/cjs/ddl/sql.cjs +54 -0
- package/dist/cjs/delete/delete-builder.cjs +135 -0
- package/dist/cjs/delete/index.cjs +5 -0
- package/dist/cjs/errors/relq-errors.cjs +329 -0
- package/dist/cjs/examples/fulltext-search-test.cjs +122 -0
- package/dist/cjs/explain/explain-builder.cjs +99 -0
- package/dist/cjs/explain/index.cjs +5 -0
- package/dist/cjs/function/create-function-builder.cjs +196 -0
- package/dist/cjs/function/index.cjs +6 -0
- package/dist/cjs/functions/advanced-functions.cjs +241 -0
- package/dist/cjs/functions/case-builder.cjs +66 -0
- package/dist/cjs/functions/geometric-functions.cjs +104 -0
- package/dist/cjs/functions/index.cjs +184 -0
- package/dist/cjs/functions/network-functions.cjs +86 -0
- package/dist/cjs/functions/sql-functions.cjs +431 -0
- package/dist/cjs/index.cjs +164 -0
- package/dist/cjs/indexing/create-index-builder.cjs +187 -0
- package/dist/cjs/indexing/drop-index-builder.cjs +89 -0
- package/dist/cjs/indexing/index-types.cjs +2 -0
- package/dist/cjs/indexing/index.cjs +8 -0
- package/dist/cjs/insert/conflict-builder.cjs +173 -0
- package/dist/cjs/insert/index.cjs +5 -0
- package/dist/cjs/insert/insert-builder.cjs +254 -0
- package/dist/cjs/introspect/index.cjs +229 -0
- package/dist/cjs/maintenance/index.cjs +6 -0
- package/dist/cjs/maintenance/vacuum-builder.cjs +166 -0
- package/dist/cjs/pubsub/index.cjs +7 -0
- package/dist/cjs/pubsub/listen-notify-builder.cjs +57 -0
- package/dist/cjs/pubsub/listener-connection.cjs +180 -0
- package/dist/cjs/raw/index.cjs +5 -0
- package/dist/cjs/raw/raw-query-builder.cjs +27 -0
- package/dist/cjs/schema/index.cjs +15 -0
- package/dist/cjs/schema/schema-builder.cjs +1167 -0
- package/dist/cjs/schema-builder.cjs +21 -0
- package/dist/cjs/schema-definition/column-types.cjs +829 -0
- package/dist/cjs/schema-definition/index.cjs +62 -0
- package/dist/cjs/schema-definition/introspection.cjs +620 -0
- package/dist/cjs/schema-definition/partitions.cjs +129 -0
- package/dist/cjs/schema-definition/pg-enum.cjs +76 -0
- package/dist/cjs/schema-definition/pg-function.cjs +91 -0
- package/dist/cjs/schema-definition/pg-sequence.cjs +56 -0
- package/dist/cjs/schema-definition/pg-trigger.cjs +108 -0
- package/dist/cjs/schema-definition/relations.cjs +98 -0
- package/dist/cjs/schema-definition/sql-expressions.cjs +202 -0
- package/dist/cjs/schema-definition/table-definition.cjs +636 -0
- package/dist/cjs/select/aggregate-builder.cjs +179 -0
- package/dist/cjs/select/index.cjs +5 -0
- package/dist/cjs/select/select-builder.cjs +233 -0
- package/dist/cjs/sequence/index.cjs +7 -0
- package/dist/cjs/sequence/sequence-builder.cjs +264 -0
- package/dist/cjs/table/alter-table-builder.cjs +146 -0
- package/dist/cjs/table/constraint-builder.cjs +102 -0
- package/dist/cjs/table/create-table-builder.cjs +248 -0
- package/dist/cjs/table/index.cjs +17 -0
- package/dist/cjs/table/partition-builder.cjs +131 -0
- package/dist/cjs/table/truncate-builder.cjs +70 -0
- package/dist/cjs/transaction/index.cjs +6 -0
- package/dist/cjs/transaction/transaction-builder.cjs +78 -0
- package/dist/cjs/trigger/create-trigger-builder.cjs +174 -0
- package/dist/cjs/trigger/index.cjs +6 -0
- package/dist/cjs/types/aggregate-types.cjs +2 -0
- package/dist/cjs/types/config-types.cjs +40 -0
- package/dist/cjs/types/inference-types.cjs +18 -0
- package/dist/cjs/types/pagination-types.cjs +7 -0
- package/dist/cjs/types/result-types.cjs +2 -0
- package/dist/cjs/types/schema-types.cjs +2 -0
- package/dist/cjs/types/subscription-types.cjs +2 -0
- package/dist/cjs/types.cjs +2 -0
- package/dist/cjs/update/array-update-builder.cjs +205 -0
- package/dist/cjs/update/index.cjs +13 -0
- package/dist/cjs/update/update-builder.cjs +195 -0
- package/dist/cjs/utils/case-converter.cjs +58 -0
- package/dist/cjs/utils/environment-detection.cjs +120 -0
- package/dist/cjs/utils/index.cjs +10 -0
- package/dist/cjs/utils/pool-defaults.cjs +106 -0
- package/dist/cjs/utils/type-coercion.cjs +118 -0
- package/dist/cjs/view/create-view-builder.cjs +180 -0
- package/dist/cjs/view/index.cjs +7 -0
- package/dist/cjs/window/index.cjs +5 -0
- package/dist/cjs/window/window-builder.cjs +80 -0
- package/dist/config.cjs +1 -0
- package/dist/config.d.ts +655 -0
- package/dist/config.js +1 -0
- package/dist/esm/cache/index.js +1 -0
- package/dist/esm/cache/query-cache.js +303 -0
- package/dist/esm/cli/commands/add.js +78 -0
- package/dist/esm/cli/commands/commit.js +109 -0
- package/dist/esm/cli/commands/diff.js +81 -0
- package/dist/esm/cli/commands/export.js +297 -0
- package/dist/esm/cli/commands/fetch.js +56 -0
- package/dist/esm/cli/commands/generate.js +206 -0
- package/dist/esm/cli/commands/history.js +129 -0
- package/dist/esm/cli/commands/import.js +488 -0
- package/dist/esm/cli/commands/init.js +401 -0
- package/dist/esm/cli/commands/introspect.js +106 -0
- package/dist/esm/cli/commands/log.js +59 -0
- package/dist/esm/cli/commands/migrate.js +131 -0
- package/dist/esm/cli/commands/pull.js +374 -0
- package/dist/esm/cli/commands/push.js +129 -0
- package/dist/esm/cli/commands/rollback.js +133 -0
- package/dist/esm/cli/commands/status.js +107 -0
- package/dist/esm/cli/commands/sync.js +76 -0
- package/dist/esm/cli/index.js +240 -0
- package/dist/esm/cli/utils/change-tracker.js +405 -0
- package/dist/esm/cli/utils/commit-manager.js +191 -0
- package/dist/esm/cli/utils/config-loader.js +86 -0
- package/dist/esm/cli/utils/env-loader.js +57 -0
- package/dist/esm/cli/utils/fast-introspect.js +362 -0
- package/dist/esm/cli/utils/git-utils.js +347 -0
- package/dist/esm/cli/utils/migration-generator.js +263 -0
- package/dist/esm/cli/utils/relqignore.js +74 -0
- package/dist/esm/cli/utils/repo-manager.js +444 -0
- package/dist/esm/cli/utils/schema-comparator.js +307 -0
- package/dist/esm/cli/utils/schema-diff.js +276 -0
- package/dist/esm/cli/utils/schema-hash.js +69 -0
- package/dist/esm/cli/utils/schema-introspect.js +418 -0
- package/dist/esm/cli/utils/snapshot-manager.js +179 -0
- package/dist/esm/cli/utils/spinner.js +101 -0
- package/dist/esm/cli/utils/sql-generator.js +504 -0
- package/dist/esm/cli/utils/sql-parser.js +992 -0
- package/dist/esm/cli/utils/type-generator.js +2058 -0
- package/dist/esm/condition/array-condition-builder.js +495 -0
- package/dist/esm/condition/array-numeric-condition-builder.js +182 -0
- package/dist/esm/condition/array-specialized-condition-builder.js +200 -0
- package/dist/esm/condition/array-string-condition-builder.js +142 -0
- package/dist/esm/condition/base-condition-builder.js +1 -0
- package/dist/esm/condition/condition-collector.js +275 -0
- package/dist/esm/condition/fulltext-condition-builder.js +53 -0
- package/dist/esm/condition/geometric-condition-builder.js +200 -0
- package/dist/esm/condition/index.js +7 -0
- package/dist/esm/condition/jsonb-condition-builder.js +152 -0
- package/dist/esm/condition/network-condition-builder.js +222 -0
- package/dist/esm/condition/range-condition-builder.js +74 -0
- package/dist/esm/config/config.js +150 -0
- package/dist/esm/config/index.js +1 -0
- package/dist/esm/constants/pg-values.js +63 -0
- package/dist/esm/copy/copy-builder.js +308 -0
- package/dist/esm/copy/index.js +1 -0
- package/dist/esm/core/query-builder.js +426 -0
- package/dist/esm/core/relq-client.js +1791 -0
- package/dist/esm/core/typed-kuery-client.js +1 -0
- package/dist/esm/count/count-builder.js +81 -0
- package/dist/esm/count/index.js +1 -0
- package/dist/esm/cte/cte-builder.js +82 -0
- package/dist/esm/cte/index.js +1 -0
- package/dist/esm/ddl/function.js +45 -0
- package/dist/esm/ddl/index.js +2 -0
- package/dist/esm/ddl/sql.js +51 -0
- package/dist/esm/delete/delete-builder.js +128 -0
- package/dist/esm/delete/index.js +1 -0
- package/dist/esm/errors/relq-errors.js +310 -0
- package/dist/esm/examples/fulltext-search-test.js +117 -0
- package/dist/esm/explain/explain-builder.js +95 -0
- package/dist/esm/explain/index.js +1 -0
- package/dist/esm/function/create-function-builder.js +188 -0
- package/dist/esm/function/index.js +1 -0
- package/dist/esm/functions/advanced-functions.js +231 -0
- package/dist/esm/functions/case-builder.js +58 -0
- package/dist/esm/functions/geometric-functions.js +97 -0
- package/dist/esm/functions/index.js +171 -0
- package/dist/esm/functions/network-functions.js +79 -0
- package/dist/esm/functions/sql-functions.js +421 -0
- package/dist/esm/index.js +34 -0
- package/dist/esm/indexing/create-index-builder.js +180 -0
- package/dist/esm/indexing/drop-index-builder.js +81 -0
- package/dist/esm/indexing/index-types.js +1 -0
- package/dist/esm/indexing/index.js +2 -0
- package/dist/esm/insert/conflict-builder.js +162 -0
- package/dist/esm/insert/index.js +1 -0
- package/dist/esm/insert/insert-builder.js +247 -0
- package/dist/esm/introspect/index.js +224 -0
- package/dist/esm/maintenance/index.js +1 -0
- package/dist/esm/maintenance/vacuum-builder.js +158 -0
- package/dist/esm/pubsub/index.js +1 -0
- package/dist/esm/pubsub/listen-notify-builder.js +48 -0
- package/dist/esm/pubsub/listener-connection.js +173 -0
- package/dist/esm/raw/index.js +1 -0
- package/dist/esm/raw/raw-query-builder.js +20 -0
- package/dist/esm/schema/index.js +1 -0
- package/dist/esm/schema/schema-builder.js +1150 -0
- package/dist/esm/schema-builder.js +2 -0
- package/dist/esm/schema-definition/column-types.js +738 -0
- package/dist/esm/schema-definition/index.js +10 -0
- package/dist/esm/schema-definition/introspection.js +614 -0
- package/dist/esm/schema-definition/partitions.js +123 -0
- package/dist/esm/schema-definition/pg-enum.js +70 -0
- package/dist/esm/schema-definition/pg-function.js +85 -0
- package/dist/esm/schema-definition/pg-sequence.js +50 -0
- package/dist/esm/schema-definition/pg-trigger.js +102 -0
- package/dist/esm/schema-definition/relations.js +90 -0
- package/dist/esm/schema-definition/sql-expressions.js +193 -0
- package/dist/esm/schema-definition/table-definition.js +630 -0
- package/dist/esm/select/aggregate-builder.js +172 -0
- package/dist/esm/select/index.js +1 -0
- package/dist/esm/select/select-builder.js +226 -0
- package/dist/esm/sequence/index.js +1 -0
- package/dist/esm/sequence/sequence-builder.js +255 -0
- package/dist/esm/table/alter-table-builder.js +138 -0
- package/dist/esm/table/constraint-builder.js +95 -0
- package/dist/esm/table/create-table-builder.js +241 -0
- package/dist/esm/table/index.js +5 -0
- package/dist/esm/table/partition-builder.js +121 -0
- package/dist/esm/table/truncate-builder.js +63 -0
- package/dist/esm/transaction/index.js +1 -0
- package/dist/esm/transaction/transaction-builder.js +70 -0
- package/dist/esm/trigger/create-trigger-builder.js +166 -0
- package/dist/esm/trigger/index.js +1 -0
- package/dist/esm/types/aggregate-types.js +1 -0
- package/dist/esm/types/config-types.js +36 -0
- package/dist/esm/types/inference-types.js +12 -0
- package/dist/esm/types/pagination-types.js +4 -0
- package/dist/esm/types/result-types.js +1 -0
- package/dist/esm/types/schema-types.js +1 -0
- package/dist/esm/types/subscription-types.js +1 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/update/array-update-builder.js +192 -0
- package/dist/esm/update/index.js +2 -0
- package/dist/esm/update/update-builder.js +188 -0
- package/dist/esm/utils/case-converter.js +55 -0
- package/dist/esm/utils/environment-detection.js +113 -0
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/utils/pool-defaults.js +100 -0
- package/dist/esm/utils/type-coercion.js +110 -0
- package/dist/esm/view/create-view-builder.js +171 -0
- package/dist/esm/view/index.js +1 -0
- package/dist/esm/window/index.js +1 -0
- package/dist/esm/window/window-builder.js +73 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +10341 -0
- package/dist/index.js +1 -0
- package/dist/schema-builder.cjs +1 -0
- package/dist/schema-builder.d.ts +2272 -0
- package/dist/schema-builder.js +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
export const EMPTY_OBJECT = Symbol.for('relq:emptyObject');
|
|
2
|
+
export const EMPTY_ARRAY = Symbol.for('relq:emptyArray');
|
|
3
|
+
function formatGenValue(val) {
|
|
4
|
+
if (val === null)
|
|
5
|
+
return 'NULL';
|
|
6
|
+
if (typeof val === 'number')
|
|
7
|
+
return String(val);
|
|
8
|
+
if (typeof val === 'string')
|
|
9
|
+
return `'${val.replace(/'/g, "''")}'`;
|
|
10
|
+
return val.$sql;
|
|
11
|
+
}
|
|
12
|
+
function chainableExpr(sql) {
|
|
13
|
+
const expr = {
|
|
14
|
+
$sql: sql,
|
|
15
|
+
$expr: true,
|
|
16
|
+
add(value) { return chainableExpr(`(${this.$sql} + ${formatGenValue(value)})`); },
|
|
17
|
+
plus(value) { return this.add(value); },
|
|
18
|
+
subtract(value) { return chainableExpr(`(${this.$sql} - ${formatGenValue(value)})`); },
|
|
19
|
+
minus(value) { return this.subtract(value); },
|
|
20
|
+
multiply(value) { return chainableExpr(`(${this.$sql} * ${formatGenValue(value)})`); },
|
|
21
|
+
times(value) { return this.multiply(value); },
|
|
22
|
+
divide(value) { return chainableExpr(`(${this.$sql} / ${formatGenValue(value)})`); },
|
|
23
|
+
dividedBy(value) { return this.divide(value); },
|
|
24
|
+
mod(value) { return chainableExpr(`(${this.$sql} % ${formatGenValue(value)})`); },
|
|
25
|
+
concat(...args) {
|
|
26
|
+
const allParts = [this.$sql, ...args.map(formatGenValue)];
|
|
27
|
+
return chainableExpr(`CONCAT(${allParts.join(', ')})`);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
return expr;
|
|
31
|
+
}
|
|
32
|
+
function createCaseBuilder() {
|
|
33
|
+
const whens = [];
|
|
34
|
+
let elseResult = null;
|
|
35
|
+
const builder = {
|
|
36
|
+
when(condition, result) {
|
|
37
|
+
const condSql = typeof condition === 'string' ? condition : condition.$sql;
|
|
38
|
+
whens.push({ condition: condSql, result: formatGenValue(result) });
|
|
39
|
+
return builder;
|
|
40
|
+
},
|
|
41
|
+
else(result) {
|
|
42
|
+
elseResult = formatGenValue(result);
|
|
43
|
+
return this.end();
|
|
44
|
+
},
|
|
45
|
+
end() {
|
|
46
|
+
let sql = 'CASE';
|
|
47
|
+
for (const w of whens) {
|
|
48
|
+
sql += ` WHEN ${w.condition} THEN ${w.result}`;
|
|
49
|
+
}
|
|
50
|
+
if (elseResult !== null) {
|
|
51
|
+
sql += ` ELSE ${elseResult}`;
|
|
52
|
+
}
|
|
53
|
+
sql += ' END';
|
|
54
|
+
return chainableExpr(sql);
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
return builder;
|
|
58
|
+
}
|
|
59
|
+
const generatedFnMethods = {
|
|
60
|
+
lower: (col) => chainableExpr(`LOWER(${col.$sql})`),
|
|
61
|
+
upper: (col) => chainableExpr(`UPPER(${col.$sql})`),
|
|
62
|
+
trim: (col) => chainableExpr(`TRIM(${col.$sql})`),
|
|
63
|
+
ltrim: (col) => chainableExpr(`LTRIM(${col.$sql})`),
|
|
64
|
+
rtrim: (col) => chainableExpr(`RTRIM(${col.$sql})`),
|
|
65
|
+
length: (col) => chainableExpr(`LENGTH(${col.$sql})`),
|
|
66
|
+
substring: (col, start, length) => length !== undefined
|
|
67
|
+
? chainableExpr(`SUBSTRING(${col.$sql} FROM ${start} FOR ${length})`)
|
|
68
|
+
: chainableExpr(`SUBSTRING(${col.$sql} FROM ${start})`),
|
|
69
|
+
concat: (...args) => chainableExpr(`CONCAT(${args.map(formatGenValue).join(', ')})`),
|
|
70
|
+
replace: (col, from, to) => chainableExpr(`REPLACE(${col.$sql}, '${from}', '${to}')`),
|
|
71
|
+
left: (col, n) => chainableExpr(`LEFT(${col.$sql}, ${n})`),
|
|
72
|
+
right: (col, n) => chainableExpr(`RIGHT(${col.$sql}, ${n})`),
|
|
73
|
+
abs: (col) => chainableExpr(`ABS(${col.$sql})`),
|
|
74
|
+
ceil: (col) => chainableExpr(`CEIL(${col.$sql})`),
|
|
75
|
+
floor: (col) => chainableExpr(`FLOOR(${col.$sql})`),
|
|
76
|
+
round: (col, decimals) => decimals !== undefined
|
|
77
|
+
? chainableExpr(`ROUND(${col.$sql}, ${decimals})`)
|
|
78
|
+
: chainableExpr(`ROUND(${col.$sql})`),
|
|
79
|
+
trunc: (col, decimals) => decimals !== undefined
|
|
80
|
+
? chainableExpr(`TRUNC(${col.$sql}, ${decimals})`)
|
|
81
|
+
: chainableExpr(`TRUNC(${col.$sql})`),
|
|
82
|
+
sign: (col) => chainableExpr(`SIGN(${col.$sql})`),
|
|
83
|
+
power: (col, exponent) => chainableExpr(`POWER(${col.$sql}, ${exponent})`),
|
|
84
|
+
sqrt: (col) => chainableExpr(`SQRT(${col.$sql})`),
|
|
85
|
+
exp: (col) => chainableExpr(`EXP(${col.$sql})`),
|
|
86
|
+
ln: (col) => chainableExpr(`LN(${col.$sql})`),
|
|
87
|
+
log: (col, base) => base !== undefined
|
|
88
|
+
? chainableExpr(`LOG(${base}, ${col.$sql})`)
|
|
89
|
+
: chainableExpr(`LOG(${col.$sql})`),
|
|
90
|
+
greatest: (...args) => chainableExpr(`GREATEST(${args.map(formatGenValue).join(', ')})`),
|
|
91
|
+
least: (...args) => chainableExpr(`LEAST(${args.map(formatGenValue).join(', ')})`),
|
|
92
|
+
add: (a, b) => chainableExpr(`(${formatGenValue(a)} + ${formatGenValue(b)})`),
|
|
93
|
+
subtract: (a, b) => chainableExpr(`(${formatGenValue(a)} - ${formatGenValue(b)})`),
|
|
94
|
+
multiply: (a, b) => chainableExpr(`(${formatGenValue(a)} * ${formatGenValue(b)})`),
|
|
95
|
+
divide: (a, b) => chainableExpr(`(${formatGenValue(a)} / ${formatGenValue(b)})`),
|
|
96
|
+
mod: (a, b) => chainableExpr(`(${formatGenValue(a)} % ${formatGenValue(b)})`),
|
|
97
|
+
asText: (col) => chainableExpr(`(${col.$sql})::TEXT`),
|
|
98
|
+
asInteger: (col) => chainableExpr(`(${col.$sql})::INTEGER`),
|
|
99
|
+
asNumeric: (col) => chainableExpr(`(${col.$sql})::NUMERIC`),
|
|
100
|
+
asBoolean: (col) => chainableExpr(`(${col.$sql})::BOOLEAN`),
|
|
101
|
+
asDate: (col) => chainableExpr(`(${col.$sql})::DATE`),
|
|
102
|
+
asTimestamp: (col) => chainableExpr(`(${col.$sql})::TIMESTAMP`),
|
|
103
|
+
coalesce: (...args) => chainableExpr(`COALESCE(${args.map(formatGenValue).join(', ')})`),
|
|
104
|
+
nullif: (col, value) => chainableExpr(`NULLIF(${col.$sql}, ${formatGenValue(value)})`),
|
|
105
|
+
ifNull: (col, defaultValue) => chainableExpr(`COALESCE(${col.$sql}, ${formatGenValue(defaultValue)})`),
|
|
106
|
+
case: () => createCaseBuilder(),
|
|
107
|
+
jsonExtract: (col, path) => chainableExpr(`${col.$sql}->'${path}'`),
|
|
108
|
+
jsonExtractText: (col, path) => chainableExpr(`${col.$sql}->>'${path}'`),
|
|
109
|
+
jsonbExtract: (col, path) => chainableExpr(`${col.$sql}->'${path}'`),
|
|
110
|
+
jsonbExtractText: (col, path) => chainableExpr(`${col.$sql}->>'${path}'`),
|
|
111
|
+
jsonArrayLength: (col) => chainableExpr(`JSONB_ARRAY_LENGTH(${col.$sql})`),
|
|
112
|
+
extract: (field, col) => chainableExpr(`EXTRACT(${field.toUpperCase()} FROM ${col.$sql})`),
|
|
113
|
+
datePart: (field, col) => chainableExpr(`DATE_PART('${field}', ${col.$sql})`),
|
|
114
|
+
age: (col1, col2) => chainableExpr(`AGE(${col1.$sql}, ${col2.$sql})`),
|
|
115
|
+
toTsvector: (config, col) => chainableExpr(`TO_TSVECTOR('${config}', ${col.$sql})`),
|
|
116
|
+
similarity: (col1, col2) => chainableExpr(`SIMILARITY(${col1.$sql}, ${formatGenValue(col2)})`),
|
|
117
|
+
point: (x, y) => chainableExpr(`POINT(${formatGenValue(x)}, ${formatGenValue(y)})`),
|
|
118
|
+
arrayLength: (col, dim = 1) => chainableExpr(`ARRAY_LENGTH(${col.$sql}, ${dim})`),
|
|
119
|
+
arrayPosition: (arr, elem) => chainableExpr(`ARRAY_POSITION(${arr.$sql}, ${formatGenValue(elem)})`),
|
|
120
|
+
md5: (col) => chainableExpr(`MD5(${col.$sql})`),
|
|
121
|
+
sha256: (col) => chainableExpr(`ENCODE(SHA256(${col.$sql}::BYTEA), 'hex')`),
|
|
122
|
+
};
|
|
123
|
+
const generatedFn = new Proxy(function (col) {
|
|
124
|
+
return chainableExpr(col.$sql);
|
|
125
|
+
}, {
|
|
126
|
+
get(target, prop) {
|
|
127
|
+
if (prop in generatedFnMethods) {
|
|
128
|
+
return generatedFnMethods[prop];
|
|
129
|
+
}
|
|
130
|
+
return Reflect.get(target, prop);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
function createColumn(type) {
|
|
134
|
+
const config = { $type: type };
|
|
135
|
+
const builder = {
|
|
136
|
+
...config,
|
|
137
|
+
$sqlType: type,
|
|
138
|
+
notNull() {
|
|
139
|
+
config.$nullable = false;
|
|
140
|
+
return Object.assign(this, { $nullable: false });
|
|
141
|
+
},
|
|
142
|
+
nullable() {
|
|
143
|
+
config.$nullable = true;
|
|
144
|
+
return Object.assign(this, { $nullable: true });
|
|
145
|
+
},
|
|
146
|
+
default(value) {
|
|
147
|
+
config.$default = value;
|
|
148
|
+
return Object.assign(this, { $default: value });
|
|
149
|
+
},
|
|
150
|
+
primaryKey() {
|
|
151
|
+
config.$primaryKey = true;
|
|
152
|
+
return Object.assign(this, { $primaryKey: true });
|
|
153
|
+
},
|
|
154
|
+
unique() {
|
|
155
|
+
config.$unique = true;
|
|
156
|
+
return Object.assign(this, { $unique: true });
|
|
157
|
+
},
|
|
158
|
+
references(table, column, options) {
|
|
159
|
+
config.$references = { table, column, ...options };
|
|
160
|
+
return Object.assign(this, { $references: config.$references });
|
|
161
|
+
},
|
|
162
|
+
check(...values) {
|
|
163
|
+
if (values.length === 1 && /[<>=!()&|+\-*/ ]/.test(values[0])) {
|
|
164
|
+
config.$check = values[0];
|
|
165
|
+
return Object.assign(this, { $check: values[0] });
|
|
166
|
+
}
|
|
167
|
+
const expression = `IN ('${values.join("', '")}')`;
|
|
168
|
+
config.$checkValues = values;
|
|
169
|
+
config.$check = expression;
|
|
170
|
+
return Object.assign(this, { $check: expression, $checkValues: values });
|
|
171
|
+
},
|
|
172
|
+
checkNot(...values) {
|
|
173
|
+
const expression = `NOT IN ('${values.join("', '")}')`;
|
|
174
|
+
config.$checkNotValues = values;
|
|
175
|
+
config.$checkNot = expression;
|
|
176
|
+
return Object.assign(this, { $checkNot: expression, $checkNotValues: values });
|
|
177
|
+
},
|
|
178
|
+
generatedAs(expression, stored = true) {
|
|
179
|
+
config.$generated = { expression, stored };
|
|
180
|
+
return Object.assign(this, { $generated: config.$generated });
|
|
181
|
+
},
|
|
182
|
+
generatedAlwaysAs(callback, options) {
|
|
183
|
+
const tableProxy = new Proxy({}, {
|
|
184
|
+
get(_target, prop) {
|
|
185
|
+
return chainableExpr(`"${prop}"`);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
const result = callback(tableProxy, generatedFn);
|
|
189
|
+
const stored = options?.stored !== false;
|
|
190
|
+
config.$generated = { expression: result.$sql, stored };
|
|
191
|
+
return Object.assign(this, { $generated: config.$generated });
|
|
192
|
+
},
|
|
193
|
+
array(dimensions = 1) {
|
|
194
|
+
config.$array = true;
|
|
195
|
+
config.$dimensions = dimensions;
|
|
196
|
+
return Object.assign(this, { $array: true, $dimensions: dimensions });
|
|
197
|
+
},
|
|
198
|
+
$type() {
|
|
199
|
+
return this;
|
|
200
|
+
},
|
|
201
|
+
length(len) {
|
|
202
|
+
config.$length = len;
|
|
203
|
+
const baseType = config.$type.replace(/\(\d+\)/, '');
|
|
204
|
+
config.$type = `${baseType}(${len})`;
|
|
205
|
+
return Object.assign(this, { $length: len, $type: config.$type });
|
|
206
|
+
},
|
|
207
|
+
precision(p) {
|
|
208
|
+
config.$precision = p;
|
|
209
|
+
const base = config.$type.replace(/\([\d,\s]+\)/, '');
|
|
210
|
+
config.$type = config.$scale !== undefined
|
|
211
|
+
? `${base}(${p}, ${config.$scale})`
|
|
212
|
+
: `${base}(${p})`;
|
|
213
|
+
return Object.assign(this, { $precision: p, $type: config.$type });
|
|
214
|
+
},
|
|
215
|
+
scale(s) {
|
|
216
|
+
config.$scale = s;
|
|
217
|
+
const base = config.$type.replace(/\([\d,\s]+\)/, '');
|
|
218
|
+
config.$type = config.$precision !== undefined
|
|
219
|
+
? `${base}(${config.$precision}, ${s})`
|
|
220
|
+
: `${base}(38, ${s})`;
|
|
221
|
+
return Object.assign(this, { $scale: s, $type: config.$type });
|
|
222
|
+
},
|
|
223
|
+
withTimezone() {
|
|
224
|
+
config.$withTimezone = true;
|
|
225
|
+
if (config.$type === 'TIMESTAMP') {
|
|
226
|
+
config.$type = 'TIMESTAMPTZ';
|
|
227
|
+
}
|
|
228
|
+
else if (config.$type === 'TIME') {
|
|
229
|
+
config.$type = 'TIMETZ';
|
|
230
|
+
}
|
|
231
|
+
return Object.assign(this, { $withTimezone: true, $type: config.$type });
|
|
232
|
+
},
|
|
233
|
+
dimensions(d) {
|
|
234
|
+
config.$dimensions = d;
|
|
235
|
+
config.$type = `VECTOR(${d})`;
|
|
236
|
+
return Object.assign(this, { $dimensions: d, $type: config.$type });
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
return builder;
|
|
240
|
+
}
|
|
241
|
+
function createColumnWithName(type, columnName) {
|
|
242
|
+
const col = createColumn(type);
|
|
243
|
+
if (columnName) {
|
|
244
|
+
col.$columnName = columnName;
|
|
245
|
+
}
|
|
246
|
+
return col;
|
|
247
|
+
}
|
|
248
|
+
export const integer = (columnName) => createColumnWithName('INTEGER', columnName);
|
|
249
|
+
export const int = integer;
|
|
250
|
+
export const int4 = integer;
|
|
251
|
+
export const smallint = (columnName) => createColumnWithName('SMALLINT', columnName);
|
|
252
|
+
export const int2 = smallint;
|
|
253
|
+
export const bigint = (columnName) => createColumnWithName('BIGINT', columnName);
|
|
254
|
+
export const int8 = bigint;
|
|
255
|
+
export const serial = (columnName) => createColumnWithName('SERIAL', columnName);
|
|
256
|
+
export const serial4 = serial;
|
|
257
|
+
export const smallserial = (columnName) => createColumnWithName('SMALLSERIAL', columnName);
|
|
258
|
+
export const serial2 = smallserial;
|
|
259
|
+
export const bigserial = (columnName) => createColumnWithName('BIGSERIAL', columnName);
|
|
260
|
+
export const serial8 = bigserial;
|
|
261
|
+
export const decimal = (columnNameOrOpts, scale) => {
|
|
262
|
+
if (typeof columnNameOrOpts === 'string' && !columnNameOrOpts.includes('.')) {
|
|
263
|
+
return createColumnWithName('DECIMAL', columnNameOrOpts);
|
|
264
|
+
}
|
|
265
|
+
if (typeof columnNameOrOpts === 'number') {
|
|
266
|
+
const type = scale !== undefined
|
|
267
|
+
? `DECIMAL(${columnNameOrOpts}, ${scale})`
|
|
268
|
+
: `DECIMAL(${columnNameOrOpts})`;
|
|
269
|
+
return createColumn(type);
|
|
270
|
+
}
|
|
271
|
+
if (columnNameOrOpts && typeof columnNameOrOpts === 'object') {
|
|
272
|
+
const type = columnNameOrOpts.precision !== undefined
|
|
273
|
+
? columnNameOrOpts.scale !== undefined
|
|
274
|
+
? `DECIMAL(${columnNameOrOpts.precision}, ${columnNameOrOpts.scale})`
|
|
275
|
+
: `DECIMAL(${columnNameOrOpts.precision})`
|
|
276
|
+
: 'DECIMAL';
|
|
277
|
+
return createColumn(type);
|
|
278
|
+
}
|
|
279
|
+
return createColumn('DECIMAL');
|
|
280
|
+
};
|
|
281
|
+
export const numeric = decimal;
|
|
282
|
+
export const real = (columnName) => createColumnWithName('REAL', columnName);
|
|
283
|
+
export const float4 = real;
|
|
284
|
+
export const doublePrecision = (columnName) => createColumnWithName('DOUBLE PRECISION', columnName);
|
|
285
|
+
export const float8 = doublePrecision;
|
|
286
|
+
export const money = (columnName) => createColumnWithName('MONEY', columnName);
|
|
287
|
+
export function varchar(arg1, arg2) {
|
|
288
|
+
if (arg1 === undefined) {
|
|
289
|
+
return createColumn('VARCHAR');
|
|
290
|
+
}
|
|
291
|
+
if (typeof arg1 === 'number') {
|
|
292
|
+
return createColumn(`VARCHAR(${arg1})`);
|
|
293
|
+
}
|
|
294
|
+
if (typeof arg1 === 'object') {
|
|
295
|
+
const length = arg1.length;
|
|
296
|
+
return createColumn(length ? `VARCHAR(${length})` : 'VARCHAR');
|
|
297
|
+
}
|
|
298
|
+
const length = arg2?.length;
|
|
299
|
+
const col = createColumn(length ? `VARCHAR(${length})` : 'VARCHAR');
|
|
300
|
+
col.$columnName = arg1;
|
|
301
|
+
return col;
|
|
302
|
+
}
|
|
303
|
+
export const characterVarying = varchar;
|
|
304
|
+
export function char(arg1, arg2) {
|
|
305
|
+
if (arg1 === undefined) {
|
|
306
|
+
return createColumn('CHAR(1)');
|
|
307
|
+
}
|
|
308
|
+
if (typeof arg1 === 'number') {
|
|
309
|
+
return createColumn(`CHAR(${arg1})`);
|
|
310
|
+
}
|
|
311
|
+
if (typeof arg1 === 'object') {
|
|
312
|
+
const length = arg1.length ?? 1;
|
|
313
|
+
return createColumn(`CHAR(${length})`);
|
|
314
|
+
}
|
|
315
|
+
const length = arg2?.length ?? 1;
|
|
316
|
+
const col = createColumn(`CHAR(${length})`);
|
|
317
|
+
col.$columnName = arg1;
|
|
318
|
+
return col;
|
|
319
|
+
}
|
|
320
|
+
export const character = char;
|
|
321
|
+
export const text = (columnName) => createColumnWithName('TEXT', columnName);
|
|
322
|
+
export const bytea = (columnName) => createColumnWithName('BYTEA', columnName);
|
|
323
|
+
export function timestamp(arg1, arg2) {
|
|
324
|
+
if (typeof arg1 === 'string') {
|
|
325
|
+
const opts = arg2;
|
|
326
|
+
const base = opts?.withTimezone ? 'TIMESTAMPTZ' : 'TIMESTAMP';
|
|
327
|
+
const type = opts?.precision !== undefined ? `${base}(${opts.precision})` : base;
|
|
328
|
+
const col = createColumn(type);
|
|
329
|
+
col.$columnName = arg1;
|
|
330
|
+
return col;
|
|
331
|
+
}
|
|
332
|
+
if (typeof arg1 === 'number') {
|
|
333
|
+
return createColumn(`TIMESTAMP(${arg1})`);
|
|
334
|
+
}
|
|
335
|
+
if (arg1 && typeof arg1 === 'object') {
|
|
336
|
+
const base = arg1.withTimezone ? 'TIMESTAMPTZ' : 'TIMESTAMP';
|
|
337
|
+
if (arg1.precision !== undefined) {
|
|
338
|
+
return createColumn(`${base}(${arg1.precision})`);
|
|
339
|
+
}
|
|
340
|
+
return createColumn(base);
|
|
341
|
+
}
|
|
342
|
+
return createColumn('TIMESTAMP');
|
|
343
|
+
}
|
|
344
|
+
export function timestamptz(arg1, arg2) {
|
|
345
|
+
if (typeof arg1 === 'string') {
|
|
346
|
+
const opts = arg2;
|
|
347
|
+
const type = opts?.precision !== undefined ? `TIMESTAMPTZ(${opts.precision})` : 'TIMESTAMPTZ';
|
|
348
|
+
const col = createColumn(type);
|
|
349
|
+
col.$columnName = arg1;
|
|
350
|
+
return col;
|
|
351
|
+
}
|
|
352
|
+
if (typeof arg1 === 'number') {
|
|
353
|
+
return createColumn(`TIMESTAMPTZ(${arg1})`);
|
|
354
|
+
}
|
|
355
|
+
if (arg1 && typeof arg1 === 'object' && arg1.precision !== undefined) {
|
|
356
|
+
return createColumn(`TIMESTAMPTZ(${arg1.precision})`);
|
|
357
|
+
}
|
|
358
|
+
return createColumn('TIMESTAMPTZ');
|
|
359
|
+
}
|
|
360
|
+
export const timestampWithTimeZone = timestamptz;
|
|
361
|
+
export const date = (columnName) => createColumnWithName('DATE', columnName);
|
|
362
|
+
export function time(arg1, arg2) {
|
|
363
|
+
if (typeof arg1 === 'string') {
|
|
364
|
+
const opts = arg2;
|
|
365
|
+
const base = opts?.withTimezone ? 'TIMETZ' : 'TIME';
|
|
366
|
+
const type = opts?.precision !== undefined ? `${base}(${opts.precision})` : base;
|
|
367
|
+
return createColumnWithName(type, arg1);
|
|
368
|
+
}
|
|
369
|
+
if (arg1 && typeof arg1 === 'object') {
|
|
370
|
+
const base = arg1.withTimezone ? 'TIMETZ' : 'TIME';
|
|
371
|
+
if (arg1.precision !== undefined) {
|
|
372
|
+
return createColumn(`${base}(${arg1.precision})`);
|
|
373
|
+
}
|
|
374
|
+
return createColumn(base);
|
|
375
|
+
}
|
|
376
|
+
return createColumn('TIME');
|
|
377
|
+
}
|
|
378
|
+
export function timetz(arg1, arg2) {
|
|
379
|
+
if (typeof arg1 === 'string') {
|
|
380
|
+
const opts = arg2;
|
|
381
|
+
const type = opts?.precision !== undefined ? `TIMETZ(${opts.precision})` : 'TIMETZ';
|
|
382
|
+
return createColumnWithName(type, arg1);
|
|
383
|
+
}
|
|
384
|
+
if (arg1 && typeof arg1 === 'object' && arg1.precision !== undefined) {
|
|
385
|
+
return createColumn(`TIMETZ(${arg1.precision})`);
|
|
386
|
+
}
|
|
387
|
+
return createColumn('TIMETZ');
|
|
388
|
+
}
|
|
389
|
+
export const timeWithTimeZone = timetz;
|
|
390
|
+
export function interval(arg1, arg2) {
|
|
391
|
+
if (arg1 && !arg1.includes(' ') && arg2 !== undefined) {
|
|
392
|
+
const type = arg2 ? `INTERVAL ${arg2}` : 'INTERVAL';
|
|
393
|
+
return createColumnWithName(type, arg1);
|
|
394
|
+
}
|
|
395
|
+
if (arg1 && !arg1.includes(' ') && arg2 === undefined) {
|
|
396
|
+
const validFields = ['YEAR', 'MONTH', 'DAY', 'HOUR', 'MINUTE', 'SECOND'];
|
|
397
|
+
const isField = validFields.some(f => arg1.toUpperCase().startsWith(f));
|
|
398
|
+
if (isField) {
|
|
399
|
+
return createColumn(`INTERVAL ${arg1}`);
|
|
400
|
+
}
|
|
401
|
+
return createColumnWithName('INTERVAL', arg1);
|
|
402
|
+
}
|
|
403
|
+
if (arg1) {
|
|
404
|
+
return createColumn(`INTERVAL ${arg1}`);
|
|
405
|
+
}
|
|
406
|
+
return createColumn('INTERVAL');
|
|
407
|
+
}
|
|
408
|
+
export const boolean = (columnName) => createColumnWithName('BOOLEAN', columnName);
|
|
409
|
+
export const bool = boolean;
|
|
410
|
+
export const point = (columnName) => createColumnWithName('POINT', columnName);
|
|
411
|
+
export const line = (columnName) => createColumnWithName('LINE', columnName);
|
|
412
|
+
export const lseg = (columnName) => createColumnWithName('LSEG', columnName);
|
|
413
|
+
export const box = (columnName) => createColumnWithName('BOX', columnName);
|
|
414
|
+
export const path = (columnName) => createColumnWithName('PATH', columnName);
|
|
415
|
+
export const polygon = (columnName) => createColumnWithName('POLYGON', columnName);
|
|
416
|
+
export const circle = (columnName) => createColumnWithName('CIRCLE', columnName);
|
|
417
|
+
export const cidr = (columnName) => createColumnWithName('CIDR', columnName);
|
|
418
|
+
export const inet = (columnName) => createColumnWithName('INET', columnName);
|
|
419
|
+
export const macaddr = (columnName) => createColumnWithName('MACADDR', columnName);
|
|
420
|
+
export const macaddr8 = (columnName) => createColumnWithName('MACADDR8', columnName);
|
|
421
|
+
export const bit = (length) => createColumn(length ? `BIT(${length})` : 'BIT(1)');
|
|
422
|
+
export const bitVarying = (length) => createColumn(length ? `BIT VARYING(${length})` : 'BIT VARYING');
|
|
423
|
+
export const varbit = bitVarying;
|
|
424
|
+
export const tsvector = (columnName) => createColumnWithName('TSVECTOR', columnName);
|
|
425
|
+
export const tsquery = (columnName) => createColumnWithName('TSQUERY', columnName);
|
|
426
|
+
export const uuid = (columnName) => createColumnWithName('UUID', columnName);
|
|
427
|
+
export const xml = (columnName) => createColumnWithName('XML', columnName);
|
|
428
|
+
export const json = (columnName) => createColumnWithName('JSON', columnName);
|
|
429
|
+
export const jsonb = (columnName) => createColumnWithName('JSONB', columnName);
|
|
430
|
+
export const int4range = () => createColumn('INT4RANGE');
|
|
431
|
+
export const int8range = () => createColumn('INT8RANGE');
|
|
432
|
+
export const numrange = () => createColumn('NUMRANGE');
|
|
433
|
+
export const tsrange = () => createColumn('TSRANGE');
|
|
434
|
+
export const tstzrange = () => createColumn('TSTZRANGE');
|
|
435
|
+
export const daterange = () => createColumn('DATERANGE');
|
|
436
|
+
export const int4multirange = () => createColumn('INT4MULTIRANGE');
|
|
437
|
+
export const int8multirange = () => createColumn('INT8MULTIRANGE');
|
|
438
|
+
export const nummultirange = () => createColumn('NUMMULTIRANGE');
|
|
439
|
+
export const tsmultirange = () => createColumn('TSMULTIRANGE');
|
|
440
|
+
export const tstzmultirange = () => createColumn('TSTZMULTIRANGE');
|
|
441
|
+
export const datemultirange = () => createColumn('DATEMULTIRANGE');
|
|
442
|
+
export const oid = () => createColumn('OID');
|
|
443
|
+
export const regclass = () => createColumn('REGCLASS');
|
|
444
|
+
export const regproc = () => createColumn('REGPROC');
|
|
445
|
+
export const regtype = () => createColumn('REGTYPE');
|
|
446
|
+
export const pgLsn = () => createColumn('PG_LSN');
|
|
447
|
+
export const pgSnapshot = () => createColumn('PG_SNAPSHOT');
|
|
448
|
+
export const citext = (columnName) => createColumnWithName('CITEXT', columnName);
|
|
449
|
+
export const ltree = (columnName) => createColumnWithName('LTREE', columnName);
|
|
450
|
+
export const lquery = (columnName) => createColumnWithName('LQUERY', columnName);
|
|
451
|
+
export const ltxtquery = (columnName) => createColumnWithName('LTXTQUERY', columnName);
|
|
452
|
+
export const hstore = (columnName) => createColumnWithName('HSTORE', columnName);
|
|
453
|
+
export const cube = (columnName) => createColumnWithName('CUBE', columnName);
|
|
454
|
+
export const semver = (columnName) => createColumnWithName('SEMVER', columnName);
|
|
455
|
+
export const geometry = (columnName, srid, geometryType) => {
|
|
456
|
+
let typeName = 'GEOMETRY';
|
|
457
|
+
if (geometryType && srid) {
|
|
458
|
+
typeName = `GEOMETRY(${geometryType}, ${srid})`;
|
|
459
|
+
}
|
|
460
|
+
else if (geometryType) {
|
|
461
|
+
typeName = `GEOMETRY(${geometryType})`;
|
|
462
|
+
}
|
|
463
|
+
else if (srid) {
|
|
464
|
+
typeName = `GEOMETRY(GEOMETRY, ${srid})`;
|
|
465
|
+
}
|
|
466
|
+
return createColumnWithName(typeName, columnName);
|
|
467
|
+
};
|
|
468
|
+
export const geography = (columnName, srid = 4326, geometryType) => {
|
|
469
|
+
let typeName = 'GEOGRAPHY';
|
|
470
|
+
if (geometryType) {
|
|
471
|
+
typeName = `GEOGRAPHY(${geometryType}, ${srid})`;
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
typeName = `GEOGRAPHY(GEOMETRY, ${srid})`;
|
|
475
|
+
}
|
|
476
|
+
return createColumnWithName(typeName, columnName);
|
|
477
|
+
};
|
|
478
|
+
export const geoPoint = (columnName, srid = 4326) => {
|
|
479
|
+
return createColumnWithName(`GEOMETRY(POINT, ${srid})`, columnName);
|
|
480
|
+
};
|
|
481
|
+
export const box2d = (columnName) => createColumnWithName('BOX2D', columnName);
|
|
482
|
+
export const box3d = (columnName) => createColumnWithName('BOX3D', columnName);
|
|
483
|
+
function createDomainCheckCondition(sql, validate, name) {
|
|
484
|
+
return {
|
|
485
|
+
$sql: sql,
|
|
486
|
+
$name: name,
|
|
487
|
+
$validate: validate,
|
|
488
|
+
and(other) {
|
|
489
|
+
return createDomainCheckCondition(`(${this.$sql}) AND (${other.$sql})`, (val) => this.$validate(val) && other.$validate(val), this.$name || other.$name);
|
|
490
|
+
},
|
|
491
|
+
or(other) {
|
|
492
|
+
return createDomainCheckCondition(`(${this.$sql}) OR (${other.$sql})`, (val) => this.$validate(val) || other.$validate(val), this.$name || other.$name);
|
|
493
|
+
},
|
|
494
|
+
as(constraintName) {
|
|
495
|
+
return createDomainCheckCondition(this.$sql, this.$validate, constraintName);
|
|
496
|
+
},
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
function formatDomainValue(val) {
|
|
500
|
+
if (val === null)
|
|
501
|
+
return 'NULL';
|
|
502
|
+
if (typeof val === 'number')
|
|
503
|
+
return String(val);
|
|
504
|
+
if (typeof val === 'boolean')
|
|
505
|
+
return val ? 'TRUE' : 'FALSE';
|
|
506
|
+
if (typeof val === 'string')
|
|
507
|
+
return `'${val.replace(/'/g, "''")}'`;
|
|
508
|
+
return String(val);
|
|
509
|
+
}
|
|
510
|
+
function createDomainValueExpr() {
|
|
511
|
+
return {
|
|
512
|
+
eq(value) {
|
|
513
|
+
return createDomainCheckCondition(`VALUE = ${formatDomainValue(value)}`, (val) => val === value);
|
|
514
|
+
},
|
|
515
|
+
neq(value) {
|
|
516
|
+
return createDomainCheckCondition(`VALUE <> ${formatDomainValue(value)}`, (val) => val !== value);
|
|
517
|
+
},
|
|
518
|
+
gt(value) {
|
|
519
|
+
return createDomainCheckCondition(`VALUE > ${formatDomainValue(value)}`, (val) => val > value);
|
|
520
|
+
},
|
|
521
|
+
gte(value) {
|
|
522
|
+
return createDomainCheckCondition(`VALUE >= ${formatDomainValue(value)}`, (val) => val >= value);
|
|
523
|
+
},
|
|
524
|
+
lt(value) {
|
|
525
|
+
return createDomainCheckCondition(`VALUE < ${formatDomainValue(value)}`, (val) => val < value);
|
|
526
|
+
},
|
|
527
|
+
lte(value) {
|
|
528
|
+
return createDomainCheckCondition(`VALUE <= ${formatDomainValue(value)}`, (val) => val <= value);
|
|
529
|
+
},
|
|
530
|
+
between(min, max) {
|
|
531
|
+
return createDomainCheckCondition(`${formatDomainValue(min)} AND ${formatDomainValue(max)}`, (val) => val >= min && val <= max);
|
|
532
|
+
},
|
|
533
|
+
in(values) {
|
|
534
|
+
const formatted = values.map(formatDomainValue).join(', ');
|
|
535
|
+
return createDomainCheckCondition(`VALUE IN (${formatted})`, (val) => values.includes(val));
|
|
536
|
+
},
|
|
537
|
+
notIn(values) {
|
|
538
|
+
const formatted = values.map(formatDomainValue).join(', ');
|
|
539
|
+
return createDomainCheckCondition(`VALUE NOT IN (${formatted})`, (val) => !values.includes(val));
|
|
540
|
+
},
|
|
541
|
+
isNull() {
|
|
542
|
+
return createDomainCheckCondition(`VALUE IS NULL`, (val) => val === null);
|
|
543
|
+
},
|
|
544
|
+
isNotNull() {
|
|
545
|
+
return createDomainCheckCondition(`VALUE IS NOT NULL`, (val) => val !== null);
|
|
546
|
+
},
|
|
547
|
+
like(pattern) {
|
|
548
|
+
try {
|
|
549
|
+
const regex = new RegExp('^' + pattern.replace(/%/g, '.*').replace(/_/g, '.') + '$');
|
|
550
|
+
return createDomainCheckCondition(`VALUE LIKE ${formatDomainValue(pattern)}`, (val) => typeof val === 'string' && regex.test(val));
|
|
551
|
+
}
|
|
552
|
+
catch (e) {
|
|
553
|
+
throw new Error(`[Relq] Invalid LIKE pattern in domain: "${pattern}". ${e instanceof Error ? e.message : String(e)}`);
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
notLike(pattern) {
|
|
557
|
+
try {
|
|
558
|
+
const regex = new RegExp('^' + pattern.replace(/%/g, '.*').replace(/_/g, '.') + '$');
|
|
559
|
+
return createDomainCheckCondition(`VALUE NOT LIKE ${formatDomainValue(pattern)}`, (val) => typeof val === 'string' && !regex.test(val));
|
|
560
|
+
}
|
|
561
|
+
catch (e) {
|
|
562
|
+
throw new Error(`[Relq] Invalid NOT LIKE pattern in domain: "${pattern}". ${e instanceof Error ? e.message : String(e)}`);
|
|
563
|
+
}
|
|
564
|
+
},
|
|
565
|
+
ilike(pattern) {
|
|
566
|
+
try {
|
|
567
|
+
const regex = new RegExp('^' + pattern.replace(/%/g, '.*').replace(/_/g, '.') + '$', 'i');
|
|
568
|
+
return createDomainCheckCondition(`VALUE ILIKE ${formatDomainValue(pattern)}`, (val) => typeof val === 'string' && regex.test(val));
|
|
569
|
+
}
|
|
570
|
+
catch (e) {
|
|
571
|
+
throw new Error(`[Relq] Invalid ILIKE pattern in domain: "${pattern}". ${e instanceof Error ? e.message : String(e)}`);
|
|
572
|
+
}
|
|
573
|
+
},
|
|
574
|
+
notIlike(pattern) {
|
|
575
|
+
try {
|
|
576
|
+
const regex = new RegExp('^' + pattern.replace(/%/g, '.*').replace(/_/g, '.') + '$', 'i');
|
|
577
|
+
return createDomainCheckCondition(`VALUE NOT ILIKE ${formatDomainValue(pattern)}`, (val) => typeof val === 'string' && !regex.test(val));
|
|
578
|
+
}
|
|
579
|
+
catch (e) {
|
|
580
|
+
throw new Error(`[Relq] Invalid NOT ILIKE pattern in domain: "${pattern}". ${e instanceof Error ? e.message : String(e)}`);
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
matches(regex) {
|
|
584
|
+
try {
|
|
585
|
+
const re = new RegExp(regex, 'i');
|
|
586
|
+
return createDomainCheckCondition(`VALUE ~* ${formatDomainValue(regex)}`, (val) => typeof val === 'string' && re.test(val));
|
|
587
|
+
}
|
|
588
|
+
catch (e) {
|
|
589
|
+
throw new Error(`[Relq] Invalid regex pattern in domain matches(): "${regex}". Tip: Use double backslashes (\\\\d instead of \\d) in string literals. ${e instanceof Error ? e.message : String(e)}`);
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
matchesCaseSensitive(regex) {
|
|
593
|
+
try {
|
|
594
|
+
const re = new RegExp(regex);
|
|
595
|
+
return createDomainCheckCondition(`VALUE ~ ${formatDomainValue(regex)}`, (val) => typeof val === 'string' && re.test(val));
|
|
596
|
+
}
|
|
597
|
+
catch (e) {
|
|
598
|
+
throw new Error(`[Relq] Invalid regex pattern in domain matchesCaseSensitive(): "${regex}". Tip: Use double backslashes (\\\\d instead of \\d) in string literals. ${e instanceof Error ? e.message : String(e)}`);
|
|
599
|
+
}
|
|
600
|
+
},
|
|
601
|
+
lengthGt(n) {
|
|
602
|
+
return createDomainCheckCondition(`LENGTH(VALUE) > ${n}`, (val) => typeof val === 'string' && val.length > n);
|
|
603
|
+
},
|
|
604
|
+
lengthGte(n) {
|
|
605
|
+
return createDomainCheckCondition(`LENGTH(VALUE) >= ${n}`, (val) => typeof val === 'string' && val.length >= n);
|
|
606
|
+
},
|
|
607
|
+
lengthLt(n) {
|
|
608
|
+
return createDomainCheckCondition(`LENGTH(VALUE) < ${n}`, (val) => typeof val === 'string' && val.length < n);
|
|
609
|
+
},
|
|
610
|
+
lengthLte(n) {
|
|
611
|
+
return createDomainCheckCondition(`LENGTH(VALUE) <= ${n}`, (val) => typeof val === 'string' && val.length <= n);
|
|
612
|
+
},
|
|
613
|
+
lengthEq(n) {
|
|
614
|
+
return createDomainCheckCondition(`LENGTH(VALUE) = ${n}`, (val) => typeof val === 'string' && val.length === n);
|
|
615
|
+
},
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
export function pgDomain(name, baseType, checks) {
|
|
619
|
+
const config = baseType.$config;
|
|
620
|
+
const baseTypeStr = config?.$type || 'TEXT';
|
|
621
|
+
const constraints = [];
|
|
622
|
+
let validateFn;
|
|
623
|
+
if (checks) {
|
|
624
|
+
const valueExpr = createDomainValueExpr();
|
|
625
|
+
const conditions = checks(valueExpr);
|
|
626
|
+
for (const cond of conditions) {
|
|
627
|
+
if (cond.$name) {
|
|
628
|
+
constraints.push(`CONSTRAINT ${cond.$name} CHECK (${cond.$sql})`);
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
constraints.push(`CHECK (${cond.$sql})`);
|
|
632
|
+
}
|
|
633
|
+
const currentValidate = cond.$validate;
|
|
634
|
+
if (!validateFn) {
|
|
635
|
+
validateFn = currentValidate;
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
const prev = validateFn;
|
|
639
|
+
validateFn = (val) => prev(val) && currentValidate(val);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
const notNull = config?.$nullable === false;
|
|
644
|
+
const defaultValue = config?.$default;
|
|
645
|
+
const domainFn = (columnName) => {
|
|
646
|
+
const col = createColumnWithName(name, columnName);
|
|
647
|
+
if (validateFn) {
|
|
648
|
+
col.$validate = validateFn;
|
|
649
|
+
}
|
|
650
|
+
return col;
|
|
651
|
+
};
|
|
652
|
+
Object.assign(domainFn, {
|
|
653
|
+
$domainName: name,
|
|
654
|
+
$baseType: baseTypeStr,
|
|
655
|
+
$constraints: constraints.length > 0 ? constraints : undefined,
|
|
656
|
+
$domainDefault: defaultValue,
|
|
657
|
+
$notNull: notNull,
|
|
658
|
+
$columnBuilder: baseType,
|
|
659
|
+
$validate: validateFn,
|
|
660
|
+
});
|
|
661
|
+
return domainFn;
|
|
662
|
+
}
|
|
663
|
+
export function generateDomainSQL(domain) {
|
|
664
|
+
let sql = `CREATE DOMAIN "${domain.$domainName}" AS ${domain.$baseType}`;
|
|
665
|
+
if (domain.$collation) {
|
|
666
|
+
sql += ` COLLATE "${domain.$collation}"`;
|
|
667
|
+
}
|
|
668
|
+
if (domain.$domainDefault !== undefined) {
|
|
669
|
+
sql += ` DEFAULT ${typeof domain.$domainDefault === 'string' ? `'${domain.$domainDefault}'` : domain.$domainDefault}`;
|
|
670
|
+
}
|
|
671
|
+
if (domain.$constraints) {
|
|
672
|
+
sql += ' ' + domain.$constraints.join(' ');
|
|
673
|
+
}
|
|
674
|
+
return sql + ';';
|
|
675
|
+
}
|
|
676
|
+
export function pgComposite(name, fields) {
|
|
677
|
+
const compositeFn = (columnName) => {
|
|
678
|
+
const col = createColumnWithName(name, columnName);
|
|
679
|
+
col.$fields = fields;
|
|
680
|
+
return col;
|
|
681
|
+
};
|
|
682
|
+
Object.assign(compositeFn, {
|
|
683
|
+
$typeName: name,
|
|
684
|
+
$fields: fields,
|
|
685
|
+
$inferType: {},
|
|
686
|
+
});
|
|
687
|
+
return compositeFn;
|
|
688
|
+
}
|
|
689
|
+
export function generateCompositeTypeSQL(composite) {
|
|
690
|
+
const fieldDefs = [];
|
|
691
|
+
for (const [fieldName, fieldConfig] of Object.entries(composite.$fields)) {
|
|
692
|
+
const config = fieldConfig;
|
|
693
|
+
let fieldDef = `"${fieldName}" ${config.$type}`;
|
|
694
|
+
if (config.$nullable === false) {
|
|
695
|
+
fieldDef += ' NOT NULL';
|
|
696
|
+
}
|
|
697
|
+
fieldDefs.push(fieldDef);
|
|
698
|
+
}
|
|
699
|
+
return `CREATE TYPE "${composite.$typeName}" AS (\n ${fieldDefs.join(',\n ')}\n);`;
|
|
700
|
+
}
|
|
701
|
+
export const customType = (typeName, columnName) => createColumnWithName(typeName, columnName);
|
|
702
|
+
export const enumType = (name, values, columnName) => {
|
|
703
|
+
const col = createColumnWithName(name, columnName);
|
|
704
|
+
col.$enumValues = values;
|
|
705
|
+
return col;
|
|
706
|
+
};
|
|
707
|
+
export const compositeType = (typeName, columnName) => createColumnWithName(typeName, columnName);
|
|
708
|
+
function sqlExpr(sql) {
|
|
709
|
+
const branded = Object.create(null);
|
|
710
|
+
Object.defineProperty(branded, '$sql', { value: sql, enumerable: false });
|
|
711
|
+
return branded;
|
|
712
|
+
}
|
|
713
|
+
export const genRandomUuid = () => sqlExpr('gen_random_uuid()');
|
|
714
|
+
export const uuidV4 = () => sqlExpr('uuid_generate_v4()');
|
|
715
|
+
export const now = () => sqlExpr('NOW()');
|
|
716
|
+
export const currentTimestamp = () => sqlExpr('CURRENT_TIMESTAMP');
|
|
717
|
+
export const currentDate = () => sqlExpr('CURRENT_DATE');
|
|
718
|
+
export const emptyObject = () => sqlExpr("'{}'");
|
|
719
|
+
export const emptyArray = () => sqlExpr("'[]'");
|
|
720
|
+
export function sql(strings, ...values) {
|
|
721
|
+
let result = strings[0];
|
|
722
|
+
for (let i = 0; i < values.length; i++) {
|
|
723
|
+
result += String(values[i]) + strings[i + 1];
|
|
724
|
+
}
|
|
725
|
+
return sqlExpr(result);
|
|
726
|
+
}
|
|
727
|
+
export const raw = (expression) => sqlExpr(expression);
|
|
728
|
+
export const index = (name) => ({
|
|
729
|
+
name,
|
|
730
|
+
on: (...columns) => ({
|
|
731
|
+
name,
|
|
732
|
+
columns,
|
|
733
|
+
unique() { return { name, columns, unique: true, isUnique: true }; },
|
|
734
|
+
using(method) {
|
|
735
|
+
return { name, columns, using: method, method };
|
|
736
|
+
},
|
|
737
|
+
}),
|
|
738
|
+
});
|