@vertz/db 0.2.11 → 0.2.13
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 +65 -4
- package/dist/d1/index.d.ts +3 -11
- package/dist/d1/index.js +1 -1
- package/dist/index.d.ts +73 -72
- package/dist/index.js +188 -663
- package/dist/internals.d.ts +41 -12
- package/dist/internals.js +3 -1
- package/dist/shared/chunk-1x9z0p5e.js +977 -0
- package/dist/shared/chunk-8v70x3hq.js +105 -0
- package/dist/shared/{chunk-pnk6yzjv.js → chunk-ndxe1h28.js} +1 -1
- package/dist/shared/{chunk-sfmyxz6r.js → chunk-pkv8w501.js} +3 -2
- package/dist/shared/{chunk-0e1vy9qd.js → chunk-pxjcpnpx.js} +4 -85
- package/dist/sql/index.js +2 -2
- package/dist/sqlite/index.d.ts +3 -11
- package/dist/sqlite/index.js +1 -1
- package/package.json +3 -3
- package/dist/shared/chunk-agyds4jw.js +0 -302
- package/dist/shared/chunk-v2qm94qp.js +0 -23
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// src/dialect/postgres.ts
|
|
2
|
+
class PostgresDialect {
|
|
3
|
+
name = "postgres";
|
|
4
|
+
supportsReturning = true;
|
|
5
|
+
supportsArrayOps = true;
|
|
6
|
+
supportsJsonbPath = true;
|
|
7
|
+
param(index) {
|
|
8
|
+
return `$${index}`;
|
|
9
|
+
}
|
|
10
|
+
now() {
|
|
11
|
+
return "NOW()";
|
|
12
|
+
}
|
|
13
|
+
mapColumnType(sqlType, meta) {
|
|
14
|
+
switch (sqlType) {
|
|
15
|
+
case "uuid":
|
|
16
|
+
return "UUID";
|
|
17
|
+
case "text":
|
|
18
|
+
return "TEXT";
|
|
19
|
+
case "integer":
|
|
20
|
+
return "INTEGER";
|
|
21
|
+
case "serial":
|
|
22
|
+
return "SERIAL";
|
|
23
|
+
case "boolean":
|
|
24
|
+
return "BOOLEAN";
|
|
25
|
+
case "timestamp":
|
|
26
|
+
return "TIMESTAMPTZ";
|
|
27
|
+
case "float":
|
|
28
|
+
return "DOUBLE PRECISION";
|
|
29
|
+
case "json":
|
|
30
|
+
return "JSONB";
|
|
31
|
+
case "decimal":
|
|
32
|
+
return meta?.precision ? `NUMERIC(${meta.precision},${meta.scale ?? 0})` : "NUMERIC";
|
|
33
|
+
case "varchar":
|
|
34
|
+
return meta?.length ? `VARCHAR(${meta.length})` : "VARCHAR";
|
|
35
|
+
case "enum":
|
|
36
|
+
return meta?.enumName ?? "TEXT";
|
|
37
|
+
default:
|
|
38
|
+
return "TEXT";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
var defaultPostgresDialect = new PostgresDialect;
|
|
43
|
+
|
|
44
|
+
// src/dialect/sqlite.ts
|
|
45
|
+
class SqliteDialect {
|
|
46
|
+
name = "sqlite";
|
|
47
|
+
supportsReturning = true;
|
|
48
|
+
supportsArrayOps = false;
|
|
49
|
+
supportsJsonbPath = false;
|
|
50
|
+
param(_index) {
|
|
51
|
+
return "?";
|
|
52
|
+
}
|
|
53
|
+
now() {
|
|
54
|
+
return "datetime('now')";
|
|
55
|
+
}
|
|
56
|
+
mapColumnType(sqlType, _meta) {
|
|
57
|
+
switch (sqlType) {
|
|
58
|
+
case "uuid":
|
|
59
|
+
return "TEXT";
|
|
60
|
+
case "boolean":
|
|
61
|
+
return "INTEGER";
|
|
62
|
+
case "timestamp":
|
|
63
|
+
return "TEXT";
|
|
64
|
+
case "json":
|
|
65
|
+
case "jsonb":
|
|
66
|
+
return "TEXT";
|
|
67
|
+
case "decimal":
|
|
68
|
+
return "REAL";
|
|
69
|
+
case "text":
|
|
70
|
+
return "TEXT";
|
|
71
|
+
case "integer":
|
|
72
|
+
return "INTEGER";
|
|
73
|
+
case "bigint":
|
|
74
|
+
return "INTEGER";
|
|
75
|
+
case "serial":
|
|
76
|
+
return "INTEGER";
|
|
77
|
+
default:
|
|
78
|
+
return "TEXT";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
var defaultSqliteDialect = new SqliteDialect;
|
|
83
|
+
// src/sql/casing.ts
|
|
84
|
+
function camelToSnake(str, overrides) {
|
|
85
|
+
if (str.length === 0)
|
|
86
|
+
return str;
|
|
87
|
+
if (overrides && str in overrides) {
|
|
88
|
+
return overrides[str];
|
|
89
|
+
}
|
|
90
|
+
return str.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").toLowerCase();
|
|
91
|
+
}
|
|
92
|
+
function snakeToCamel(str, overrides) {
|
|
93
|
+
if (str.length === 0)
|
|
94
|
+
return str;
|
|
95
|
+
if (overrides) {
|
|
96
|
+
for (const [camelKey, snakeVal] of Object.entries(overrides)) {
|
|
97
|
+
if (snakeVal === str) {
|
|
98
|
+
return camelKey;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return str.replace(/([a-zA-Z\d])_([a-zA-Z])/g, (_, prev, char) => prev + char.toUpperCase());
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { PostgresDialect, defaultPostgresDialect, SqliteDialect, defaultSqliteDialect, camelToSnake, snakeToCamel };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/id/generators.ts
|
|
2
2
|
import { createId } from "@paralleldrive/cuid2";
|
|
3
|
-
import { v7 as uuidv7 } from "uuid";
|
|
4
3
|
import { nanoid } from "nanoid";
|
|
4
|
+
import { v7 as uuidv7 } from "uuid";
|
|
5
5
|
function generateId(strategy) {
|
|
6
6
|
switch (strategy) {
|
|
7
7
|
case "cuid":
|
|
@@ -99,7 +99,8 @@ function generateIndexSql(schema) {
|
|
|
99
99
|
for (const index of schema._indexes) {
|
|
100
100
|
const indexName = index.name || `idx_${tableName}_${index.columns.join("_")}`;
|
|
101
101
|
const unique = index.unique ? "UNIQUE " : "";
|
|
102
|
-
|
|
102
|
+
const where = index.where ? ` WHERE ${index.where}` : "";
|
|
103
|
+
sqls.push(`CREATE ${unique}INDEX IF NOT EXISTS ${indexName} ON ${tableName} (${index.columns.join(", ")})${where}`);
|
|
103
104
|
}
|
|
104
105
|
for (const [colName, colBuilder] of Object.entries(schema._columns)) {
|
|
105
106
|
const meta = colBuilder._meta;
|
|
@@ -1,89 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
camelToSnake
|
|
3
|
-
|
|
2
|
+
camelToSnake,
|
|
3
|
+
defaultPostgresDialect
|
|
4
|
+
} from "./chunk-8v70x3hq.js";
|
|
4
5
|
|
|
5
|
-
// src/dialect/postgres.ts
|
|
6
|
-
class PostgresDialect {
|
|
7
|
-
name = "postgres";
|
|
8
|
-
supportsReturning = true;
|
|
9
|
-
supportsArrayOps = true;
|
|
10
|
-
supportsJsonbPath = true;
|
|
11
|
-
param(index) {
|
|
12
|
-
return `$${index}`;
|
|
13
|
-
}
|
|
14
|
-
now() {
|
|
15
|
-
return "NOW()";
|
|
16
|
-
}
|
|
17
|
-
mapColumnType(sqlType, meta) {
|
|
18
|
-
switch (sqlType) {
|
|
19
|
-
case "uuid":
|
|
20
|
-
return "UUID";
|
|
21
|
-
case "text":
|
|
22
|
-
return "TEXT";
|
|
23
|
-
case "integer":
|
|
24
|
-
return "INTEGER";
|
|
25
|
-
case "serial":
|
|
26
|
-
return "SERIAL";
|
|
27
|
-
case "boolean":
|
|
28
|
-
return "BOOLEAN";
|
|
29
|
-
case "timestamp":
|
|
30
|
-
return "TIMESTAMPTZ";
|
|
31
|
-
case "float":
|
|
32
|
-
return "DOUBLE PRECISION";
|
|
33
|
-
case "json":
|
|
34
|
-
return "JSONB";
|
|
35
|
-
case "decimal":
|
|
36
|
-
return meta?.precision ? `NUMERIC(${meta.precision},${meta.scale ?? 0})` : "NUMERIC";
|
|
37
|
-
case "varchar":
|
|
38
|
-
return meta?.length ? `VARCHAR(${meta.length})` : "VARCHAR";
|
|
39
|
-
case "enum":
|
|
40
|
-
return meta?.enumName ?? "TEXT";
|
|
41
|
-
default:
|
|
42
|
-
return "TEXT";
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
var defaultPostgresDialect = new PostgresDialect;
|
|
47
|
-
|
|
48
|
-
// src/dialect/sqlite.ts
|
|
49
|
-
class SqliteDialect {
|
|
50
|
-
name = "sqlite";
|
|
51
|
-
supportsReturning = true;
|
|
52
|
-
supportsArrayOps = false;
|
|
53
|
-
supportsJsonbPath = false;
|
|
54
|
-
param(_index) {
|
|
55
|
-
return "?";
|
|
56
|
-
}
|
|
57
|
-
now() {
|
|
58
|
-
return "datetime('now')";
|
|
59
|
-
}
|
|
60
|
-
mapColumnType(sqlType, _meta) {
|
|
61
|
-
switch (sqlType) {
|
|
62
|
-
case "uuid":
|
|
63
|
-
return "TEXT";
|
|
64
|
-
case "boolean":
|
|
65
|
-
return "INTEGER";
|
|
66
|
-
case "timestamp":
|
|
67
|
-
return "TEXT";
|
|
68
|
-
case "json":
|
|
69
|
-
case "jsonb":
|
|
70
|
-
return "TEXT";
|
|
71
|
-
case "decimal":
|
|
72
|
-
return "REAL";
|
|
73
|
-
case "text":
|
|
74
|
-
return "TEXT";
|
|
75
|
-
case "integer":
|
|
76
|
-
return "INTEGER";
|
|
77
|
-
case "bigint":
|
|
78
|
-
return "INTEGER";
|
|
79
|
-
case "serial":
|
|
80
|
-
return "INTEGER";
|
|
81
|
-
default:
|
|
82
|
-
return "TEXT";
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
var defaultSqliteDialect = new SqliteDialect;
|
|
87
6
|
// src/sql/where.ts
|
|
88
7
|
var OPERATOR_KEYS = new Set([
|
|
89
8
|
"eq",
|
|
@@ -520,4 +439,4 @@ function buildUpdate(options, dialect = options.dialect ?? defaultPostgresDialec
|
|
|
520
439
|
return { sql, params: allParams };
|
|
521
440
|
}
|
|
522
441
|
|
|
523
|
-
export {
|
|
442
|
+
export { buildWhere, buildDelete, buildInsert, buildSelect, buildUpdate };
|
package/dist/sql/index.js
CHANGED
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
buildSelect,
|
|
5
5
|
buildUpdate,
|
|
6
6
|
buildWhere
|
|
7
|
-
} from "../shared/chunk-
|
|
7
|
+
} from "../shared/chunk-pxjcpnpx.js";
|
|
8
8
|
import {
|
|
9
9
|
camelToSnake,
|
|
10
10
|
snakeToCamel
|
|
11
|
-
} from "../shared/chunk-
|
|
11
|
+
} from "../shared/chunk-8v70x3hq.js";
|
|
12
12
|
// src/sql/tagged.ts
|
|
13
13
|
function isSqlFragment(value) {
|
|
14
14
|
return typeof value === "object" && value !== null && "_tag" in value && value._tag === "SqlFragment";
|
package/dist/sqlite/index.d.ts
CHANGED
|
@@ -32,11 +32,6 @@ interface ColumnMetadata {
|
|
|
32
32
|
readonly _annotations: Record<string, true>;
|
|
33
33
|
readonly isReadOnly: boolean;
|
|
34
34
|
readonly isAutoUpdate: boolean;
|
|
35
|
-
readonly isTenant: boolean;
|
|
36
|
-
readonly references: {
|
|
37
|
-
readonly table: string;
|
|
38
|
-
readonly column: string;
|
|
39
|
-
} | null;
|
|
40
35
|
readonly check: string | null;
|
|
41
36
|
readonly defaultValue?: unknown;
|
|
42
37
|
readonly format?: string;
|
|
@@ -87,18 +82,15 @@ interface ColumnBuilder<
|
|
|
87
82
|
check(sql: string): ColumnBuilder<TType, Omit<TMeta, "check"> & {
|
|
88
83
|
readonly check: string;
|
|
89
84
|
}>;
|
|
90
|
-
references(table: string, column?: string): ColumnBuilder<TType, Omit<TMeta, "references"> & {
|
|
91
|
-
readonly references: {
|
|
92
|
-
readonly table: string;
|
|
93
|
-
readonly column: string;
|
|
94
|
-
};
|
|
95
|
-
}>;
|
|
96
85
|
}
|
|
97
86
|
type InferColumnType<C> = C extends ColumnBuilder<infer T, ColumnMetadata> ? T : never;
|
|
87
|
+
type IndexType = "btree" | "hash" | "gin" | "gist" | "brin";
|
|
98
88
|
interface IndexDef {
|
|
99
89
|
readonly columns: readonly string[];
|
|
100
90
|
readonly name?: string;
|
|
101
91
|
readonly unique?: boolean;
|
|
92
|
+
readonly type?: IndexType;
|
|
93
|
+
readonly where?: string;
|
|
102
94
|
}
|
|
103
95
|
/** A record of column builders -- the shape passed to d.table(). */
|
|
104
96
|
type ColumnRecord = Record<string, ColumnBuilder<unknown, ColumnMetadata>>;
|
package/dist/sqlite/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vertz/db",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Database layer for Vertz — typed queries, migrations, codegen",
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
"node": ">=22"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@vertz/errors": "^0.2.
|
|
85
|
-
"@vertz/schema": "^0.2.
|
|
84
|
+
"@vertz/errors": "^0.2.12",
|
|
85
|
+
"@vertz/schema": "^0.2.12",
|
|
86
86
|
"@paralleldrive/cuid2": "^3.3.0",
|
|
87
87
|
"nanoid": "^5.1.5",
|
|
88
88
|
"uuid": "^13.0.0"
|
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
snakeToCamel
|
|
3
|
-
} from "./chunk-v2qm94qp.js";
|
|
4
|
-
|
|
5
|
-
// src/errors/db-error.ts
|
|
6
|
-
class DbError extends Error {
|
|
7
|
-
pgCode;
|
|
8
|
-
table;
|
|
9
|
-
query;
|
|
10
|
-
constructor(message) {
|
|
11
|
-
super(message);
|
|
12
|
-
this.name = new.target.name;
|
|
13
|
-
}
|
|
14
|
-
toJSON() {
|
|
15
|
-
const json = {
|
|
16
|
-
error: this.name,
|
|
17
|
-
code: this.code,
|
|
18
|
-
message: this.message
|
|
19
|
-
};
|
|
20
|
-
if (this.table !== undefined) {
|
|
21
|
-
json.table = this.table;
|
|
22
|
-
}
|
|
23
|
-
return json;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
class UniqueConstraintError extends DbError {
|
|
28
|
-
code = "UNIQUE_VIOLATION";
|
|
29
|
-
pgCode = "23505";
|
|
30
|
-
table;
|
|
31
|
-
query;
|
|
32
|
-
column;
|
|
33
|
-
value;
|
|
34
|
-
constructor(options) {
|
|
35
|
-
super(`Unique constraint violated on ${options.table}.${options.column}${options.value !== undefined ? ` (value: ${options.value})` : ""}`);
|
|
36
|
-
this.table = options.table;
|
|
37
|
-
this.column = options.column;
|
|
38
|
-
this.value = options.value;
|
|
39
|
-
this.query = options.query;
|
|
40
|
-
}
|
|
41
|
-
toJSON() {
|
|
42
|
-
return {
|
|
43
|
-
...super.toJSON(),
|
|
44
|
-
table: this.table,
|
|
45
|
-
column: this.column
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
class ForeignKeyError extends DbError {
|
|
51
|
-
code = "FOREIGN_KEY_VIOLATION";
|
|
52
|
-
pgCode = "23503";
|
|
53
|
-
table;
|
|
54
|
-
query;
|
|
55
|
-
constraint;
|
|
56
|
-
detail;
|
|
57
|
-
constructor(options) {
|
|
58
|
-
super(`Foreign key constraint "${options.constraint}" violated on table ${options.table}`);
|
|
59
|
-
this.table = options.table;
|
|
60
|
-
this.constraint = options.constraint;
|
|
61
|
-
this.detail = options.detail;
|
|
62
|
-
this.query = options.query;
|
|
63
|
-
}
|
|
64
|
-
toJSON() {
|
|
65
|
-
return {
|
|
66
|
-
...super.toJSON(),
|
|
67
|
-
table: this.table
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
class NotNullError extends DbError {
|
|
73
|
-
code = "NOT_NULL_VIOLATION";
|
|
74
|
-
pgCode = "23502";
|
|
75
|
-
table;
|
|
76
|
-
query;
|
|
77
|
-
column;
|
|
78
|
-
constructor(options) {
|
|
79
|
-
super(`Not-null constraint violated on ${options.table}.${options.column}`);
|
|
80
|
-
this.table = options.table;
|
|
81
|
-
this.column = options.column;
|
|
82
|
-
this.query = options.query;
|
|
83
|
-
}
|
|
84
|
-
toJSON() {
|
|
85
|
-
return {
|
|
86
|
-
...super.toJSON(),
|
|
87
|
-
table: this.table,
|
|
88
|
-
column: this.column
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
class CheckConstraintError extends DbError {
|
|
94
|
-
code = "CHECK_VIOLATION";
|
|
95
|
-
pgCode = "23514";
|
|
96
|
-
table;
|
|
97
|
-
query;
|
|
98
|
-
constraint;
|
|
99
|
-
constructor(options) {
|
|
100
|
-
super(`Check constraint "${options.constraint}" violated on table ${options.table}`);
|
|
101
|
-
this.table = options.table;
|
|
102
|
-
this.constraint = options.constraint;
|
|
103
|
-
this.query = options.query;
|
|
104
|
-
}
|
|
105
|
-
toJSON() {
|
|
106
|
-
return {
|
|
107
|
-
...super.toJSON(),
|
|
108
|
-
table: this.table
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
class NotFoundError extends DbError {
|
|
114
|
-
code = "NotFound";
|
|
115
|
-
table;
|
|
116
|
-
query;
|
|
117
|
-
constructor(table, query) {
|
|
118
|
-
super(`Record not found in table ${table}`);
|
|
119
|
-
this.table = table;
|
|
120
|
-
this.query = query;
|
|
121
|
-
}
|
|
122
|
-
toJSON() {
|
|
123
|
-
return {
|
|
124
|
-
...super.toJSON(),
|
|
125
|
-
table: this.table
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
class ConnectionError extends DbError {
|
|
131
|
-
code = "CONNECTION_ERROR";
|
|
132
|
-
constructor(message) {
|
|
133
|
-
super(`Database connection error: ${message}`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
class ConnectionPoolExhaustedError extends ConnectionError {
|
|
138
|
-
code = "POOL_EXHAUSTED";
|
|
139
|
-
constructor(poolSize) {
|
|
140
|
-
super(`Connection pool exhausted (max: ${poolSize})`);
|
|
141
|
-
this.name = "ConnectionPoolExhaustedError";
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// src/errors/pg-parser.ts
|
|
146
|
-
function extractKeyDetail(detail) {
|
|
147
|
-
if (!detail)
|
|
148
|
-
return null;
|
|
149
|
-
const match = detail.match(/^Key \(([^)]+)\)=\(([^)]*)\)/);
|
|
150
|
-
if (!match)
|
|
151
|
-
return null;
|
|
152
|
-
return { column: match[1], value: match[2] };
|
|
153
|
-
}
|
|
154
|
-
function extractNotNullColumn(message) {
|
|
155
|
-
const match = message.match(/null value in column "([^"]+)"/);
|
|
156
|
-
return match ? match[1] : null;
|
|
157
|
-
}
|
|
158
|
-
function extractCheckConstraint(message) {
|
|
159
|
-
const match = message.match(/violates check constraint "([^"]+)"/);
|
|
160
|
-
return match ? match[1] : null;
|
|
161
|
-
}
|
|
162
|
-
function isConnectionErrorCode(code) {
|
|
163
|
-
return code.startsWith("08");
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
class UnknownDbError extends DbError {
|
|
167
|
-
code;
|
|
168
|
-
table;
|
|
169
|
-
query;
|
|
170
|
-
constructor(code, message, table, query) {
|
|
171
|
-
super(message);
|
|
172
|
-
this.code = code;
|
|
173
|
-
this.table = table;
|
|
174
|
-
this.query = query;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
function parsePgError(pgError, query) {
|
|
178
|
-
const { code, message, table, column, constraint, detail } = pgError;
|
|
179
|
-
switch (code) {
|
|
180
|
-
case "23505": {
|
|
181
|
-
const keyDetail = extractKeyDetail(detail);
|
|
182
|
-
return new UniqueConstraintError({
|
|
183
|
-
table: table ?? "unknown",
|
|
184
|
-
column: column ?? keyDetail?.column ?? "unknown",
|
|
185
|
-
value: keyDetail?.value,
|
|
186
|
-
query
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
case "23503": {
|
|
190
|
-
return new ForeignKeyError({
|
|
191
|
-
table: table ?? "unknown",
|
|
192
|
-
constraint: constraint ?? "unknown",
|
|
193
|
-
detail,
|
|
194
|
-
query
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
case "23502": {
|
|
198
|
-
const extractedColumn = extractNotNullColumn(message);
|
|
199
|
-
return new NotNullError({
|
|
200
|
-
table: table ?? "unknown",
|
|
201
|
-
column: column ?? extractedColumn ?? "unknown",
|
|
202
|
-
query
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
case "23514": {
|
|
206
|
-
const extractedConstraint = extractCheckConstraint(message);
|
|
207
|
-
return new CheckConstraintError({
|
|
208
|
-
table: table ?? "unknown",
|
|
209
|
-
constraint: constraint ?? extractedConstraint ?? "unknown",
|
|
210
|
-
query
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
default: {
|
|
214
|
-
if (isConnectionErrorCode(code)) {
|
|
215
|
-
return new ConnectionError(message);
|
|
216
|
-
}
|
|
217
|
-
return new UnknownDbError(code, message, table, query);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// src/query/executor.ts
|
|
223
|
-
function isPgError(error) {
|
|
224
|
-
return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" && "message" in error && typeof error.message === "string";
|
|
225
|
-
}
|
|
226
|
-
async function executeQuery(queryFn, sql, params) {
|
|
227
|
-
try {
|
|
228
|
-
return await queryFn(sql, params);
|
|
229
|
-
} catch (error) {
|
|
230
|
-
if (isPgError(error)) {
|
|
231
|
-
throw parsePgError(error, sql);
|
|
232
|
-
}
|
|
233
|
-
throw error;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// src/query/helpers.ts
|
|
238
|
-
function getColumnNames(table) {
|
|
239
|
-
return Object.keys(table._columns);
|
|
240
|
-
}
|
|
241
|
-
function getDefaultColumns(table) {
|
|
242
|
-
return getColumnsWithoutAnnotations(table, []);
|
|
243
|
-
}
|
|
244
|
-
function getColumnsWithoutAnnotations(table, annotations) {
|
|
245
|
-
const allAnnotations = annotations.includes("hidden") ? annotations : [...annotations, "hidden"];
|
|
246
|
-
return Object.keys(table._columns).filter((key) => {
|
|
247
|
-
const col = table._columns[key];
|
|
248
|
-
if (!col)
|
|
249
|
-
return true;
|
|
250
|
-
const colAnnotations = col._meta._annotations;
|
|
251
|
-
return !allAnnotations.some((f) => colAnnotations[f]);
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
function resolveSelectColumns(table, select) {
|
|
255
|
-
if (!select) {
|
|
256
|
-
return getDefaultColumns(table);
|
|
257
|
-
}
|
|
258
|
-
if ("not" in select && select.not !== undefined) {
|
|
259
|
-
const notValue = select.not;
|
|
260
|
-
const flags = Array.isArray(notValue) ? notValue : [notValue];
|
|
261
|
-
return getColumnsWithoutAnnotations(table, flags);
|
|
262
|
-
}
|
|
263
|
-
return Object.keys(select).filter((k) => select[k] === true);
|
|
264
|
-
}
|
|
265
|
-
function getTimestampColumns(table) {
|
|
266
|
-
return Object.keys(table._columns).filter((key) => {
|
|
267
|
-
const col = table._columns[key];
|
|
268
|
-
return col ? col._meta.sqlType === "timestamp with time zone" : false;
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
function getPrimaryKeyColumns(table) {
|
|
272
|
-
return Object.keys(table._columns).filter((key) => {
|
|
273
|
-
const col = table._columns[key];
|
|
274
|
-
return col ? col._meta.primary : false;
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
function getReadOnlyColumns(table) {
|
|
278
|
-
return Object.keys(table._columns).filter((key) => {
|
|
279
|
-
const col = table._columns[key];
|
|
280
|
-
return col ? col._meta.isReadOnly : false;
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
function getAutoUpdateColumns(table) {
|
|
284
|
-
return Object.keys(table._columns).filter((key) => {
|
|
285
|
-
const col = table._columns[key];
|
|
286
|
-
return col ? col._meta.isAutoUpdate : false;
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// src/query/row-mapper.ts
|
|
291
|
-
function mapRow(row) {
|
|
292
|
-
const result = {};
|
|
293
|
-
for (const key of Object.keys(row)) {
|
|
294
|
-
result[snakeToCamel(key)] = row[key];
|
|
295
|
-
}
|
|
296
|
-
return result;
|
|
297
|
-
}
|
|
298
|
-
function mapRows(rows) {
|
|
299
|
-
return rows.map((row) => mapRow(row));
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
export { DbError, UniqueConstraintError, ForeignKeyError, NotNullError, CheckConstraintError, NotFoundError, ConnectionError, ConnectionPoolExhaustedError, parsePgError, executeQuery, getColumnNames, getDefaultColumns, getColumnsWithoutAnnotations, resolveSelectColumns, getTimestampColumns, getPrimaryKeyColumns, getReadOnlyColumns, getAutoUpdateColumns, mapRow, mapRows };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// src/sql/casing.ts
|
|
2
|
-
function camelToSnake(str, overrides) {
|
|
3
|
-
if (str.length === 0)
|
|
4
|
-
return str;
|
|
5
|
-
if (overrides && str in overrides) {
|
|
6
|
-
return overrides[str];
|
|
7
|
-
}
|
|
8
|
-
return str.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").toLowerCase();
|
|
9
|
-
}
|
|
10
|
-
function snakeToCamel(str, overrides) {
|
|
11
|
-
if (str.length === 0)
|
|
12
|
-
return str;
|
|
13
|
-
if (overrides) {
|
|
14
|
-
for (const [camelKey, snakeVal] of Object.entries(overrides)) {
|
|
15
|
-
if (snakeVal === str) {
|
|
16
|
-
return camelKey;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return str.replace(/([a-zA-Z\d])_([a-zA-Z])/g, (_, prev, char) => prev + char.toUpperCase());
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export { camelToSnake, snakeToCamel };
|