@travetto/model-sqlite 8.0.0-alpha.26 → 8.0.0-alpha.27
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/package.json +6 -6
- package/src/connection.ts +10 -4
- package/src/dialect.ts +30 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model-sqlite",
|
|
3
|
-
"version": "8.0.0-alpha.
|
|
3
|
+
"version": "8.0.0-alpha.27",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "SQLite backing for the travetto model module, with real-time modeling support for SQL schemas.",
|
|
6
6
|
"keywords": [
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"directory": "module/model-sqlite"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@travetto/config": "^8.0.0-alpha.
|
|
31
|
-
"@travetto/context": "^8.0.0-alpha.
|
|
32
|
-
"@travetto/model": "^8.0.0-alpha.
|
|
33
|
-
"@travetto/model-query": "^8.0.0-alpha.
|
|
34
|
-
"@travetto/model-sql": "^8.0.0-alpha.
|
|
30
|
+
"@travetto/config": "^8.0.0-alpha.23",
|
|
31
|
+
"@travetto/context": "^8.0.0-alpha.21",
|
|
32
|
+
"@travetto/model": "^8.0.0-alpha.24",
|
|
33
|
+
"@travetto/model-query": "^8.0.0-alpha.25",
|
|
34
|
+
"@travetto/model-sql": "^8.0.0-alpha.27"
|
|
35
35
|
},
|
|
36
36
|
"travetto": {
|
|
37
37
|
"displayName": "SQLite Model Service"
|
package/src/connection.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { createPool, type Pool } from 'generic-pool';
|
|
|
6
6
|
|
|
7
7
|
import type { AsyncContext } from '@travetto/context';
|
|
8
8
|
import { Injectable } from '@travetto/di';
|
|
9
|
-
import { ExistsError } from '@travetto/model';
|
|
9
|
+
import { ExistsError, UniqueError } from '@travetto/model';
|
|
10
10
|
import { SQLConnection } from '@travetto/model-sql';
|
|
11
11
|
import { castTo, JSONUtil, Runtime, RuntimeError, ShutdownManager, Util } from '@travetto/runtime';
|
|
12
12
|
|
|
@@ -176,13 +176,19 @@ export class SqliteConnection extends SQLConnection<DatabaseSync> {
|
|
|
176
176
|
switch (code) {
|
|
177
177
|
case 'ERR_SQLITE_ERROR': {
|
|
178
178
|
if (message?.startsWith('UNIQUE')) {
|
|
179
|
-
|
|
179
|
+
const match = message.match(/UNIQUE constraint failed: (.*)/);
|
|
180
|
+
const key = match ? match[1] : 'query';
|
|
181
|
+
throw new UniqueError('query', key, { message, query });
|
|
180
182
|
}
|
|
181
183
|
break;
|
|
182
184
|
}
|
|
183
|
-
case 'SQLITE_CONSTRAINT_PRIMARYKEY':
|
|
184
185
|
case 'SQLITE_CONSTRAINT_UNIQUE':
|
|
185
|
-
case 'SQLITE_CONSTRAINT_INDEX':
|
|
186
|
+
case 'SQLITE_CONSTRAINT_INDEX': {
|
|
187
|
+
const match = message?.match(/UNIQUE constraint failed: (.*)/);
|
|
188
|
+
const key = match ? match[1] : 'query';
|
|
189
|
+
throw new UniqueError('query', key, { message, query });
|
|
190
|
+
}
|
|
191
|
+
case 'SQLITE_CONSTRAINT_PRIMARYKEY':
|
|
186
192
|
throw new ExistsError('query', query);
|
|
187
193
|
}
|
|
188
194
|
if (/index.*?already exists/.test(message ?? '')) {
|
package/src/dialect.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbstractANSI99Dialect, type TableContext, type TransactionStatements } from '@travetto/model-sql';
|
|
1
|
+
import { AbstractANSI99Dialect, type ResolvedPathContext, type TableContext, type TransactionStatements } from '@travetto/model-sql';
|
|
2
2
|
import { type Class, castTo, JSONUtil } from '@travetto/runtime';
|
|
3
3
|
import type { SchemaFieldConfig } from '@travetto/schema';
|
|
4
4
|
|
|
@@ -41,41 +41,60 @@ export class SqliteDialect extends AbstractANSI99Dialect {
|
|
|
41
41
|
return `json_extract(${columnName}, '$.${jsonPath.join('.')}')`;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
#getSqliteArrayContext(context: ResolvedPathContext): { jsonArrayExpr: string; valueExpr: string } {
|
|
45
|
+
if (!context.arrayPath || context.arrayPath.length === 0) {
|
|
46
|
+
return { jsonArrayExpr: context.sqlPath, valueExpr: 'elem.value' };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const columnName = this.escapeIdentifier(context.arrayPath[0]);
|
|
50
|
+
const jsonArrayExpr =
|
|
51
|
+
context.arrayPath.length > 1 ? `json_extract(${columnName}, '$.${context.arrayPath.slice(1).join('.')}')` : columnName;
|
|
52
|
+
|
|
53
|
+
const valueExpr =
|
|
54
|
+
context.subPath && context.subPath.length > 0 ? `json_extract(elem.value, '$.${context.subPath.join('.')}')` : 'elem.value';
|
|
55
|
+
|
|
56
|
+
return { jsonArrayExpr, valueExpr };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
compileArrayAll(context: ResolvedPathContext, identifier: string, value: unknown[]): { sql: string; formatted: unknown } {
|
|
60
|
+
const { jsonArrayExpr, valueExpr } = this.#getSqliteArrayContext(context);
|
|
45
61
|
return {
|
|
46
|
-
sql: `NOT EXISTS (SELECT 1 FROM json_each(${identifier}) AS req WHERE req.value NOT IN (SELECT
|
|
62
|
+
sql: `NOT EXISTS (SELECT 1 FROM json_each(${identifier}) AS req WHERE req.value NOT IN (SELECT ${valueExpr} FROM json_each(${jsonArrayExpr}) AS elem))`,
|
|
47
63
|
formatted: JSONUtil.toUTF8(value)
|
|
48
64
|
};
|
|
49
65
|
}
|
|
50
66
|
|
|
51
|
-
compileArrayEquals(
|
|
67
|
+
compileArrayEquals(context: ResolvedPathContext, identifier: string, values: unknown): { sql: string; formatted: unknown } {
|
|
68
|
+
const { jsonArrayExpr, valueExpr } = this.#getSqliteArrayContext(context);
|
|
52
69
|
if (Array.isArray(values)) {
|
|
53
70
|
return {
|
|
54
|
-
sql: `NOT EXISTS (SELECT 1 FROM json_each(${identifier}) AS req WHERE req.value NOT IN (SELECT
|
|
71
|
+
sql: `NOT EXISTS (SELECT 1 FROM json_each(${identifier}) AS req WHERE req.value NOT IN (SELECT ${valueExpr} FROM json_each(${jsonArrayExpr}) AS elem))`,
|
|
55
72
|
formatted: JSONUtil.toUTF8(values)
|
|
56
73
|
};
|
|
57
74
|
}
|
|
58
75
|
if (typeof values === 'object' && values !== null) {
|
|
59
76
|
return {
|
|
60
|
-
sql: `EXISTS (SELECT 1 FROM json_each(${
|
|
77
|
+
sql: `EXISTS (SELECT 1 FROM json_each(${jsonArrayExpr}) AS elem WHERE NOT EXISTS (SELECT 1 FROM json_each(${identifier}) AS req WHERE json_extract(elem.value, '$.' || req.key) IS NOT req.value))`,
|
|
61
78
|
formatted: JSONUtil.toUTF8(values)
|
|
62
79
|
};
|
|
63
80
|
}
|
|
64
81
|
return {
|
|
65
|
-
sql: `EXISTS (SELECT 1 FROM json_each(${
|
|
82
|
+
sql: `EXISTS (SELECT 1 FROM json_each(${jsonArrayExpr}) AS elem WHERE ${valueExpr} = ${identifier})`,
|
|
66
83
|
formatted: values
|
|
67
84
|
};
|
|
68
85
|
}
|
|
69
86
|
|
|
70
|
-
compileArrayAny(
|
|
87
|
+
compileArrayAny(context: ResolvedPathContext, identifier: string, values: unknown[]): { sql: string; formatted: unknown } {
|
|
88
|
+
const { jsonArrayExpr, valueExpr } = this.#getSqliteArrayContext(context);
|
|
71
89
|
return {
|
|
72
|
-
sql: `EXISTS (SELECT 1 FROM json_each(${
|
|
90
|
+
sql: `EXISTS (SELECT 1 FROM json_each(${jsonArrayExpr}) AS elem WHERE ${valueExpr} IN (SELECT value FROM json_each(${identifier})))`,
|
|
73
91
|
formatted: JSONUtil.toUTF8(values)
|
|
74
92
|
};
|
|
75
93
|
}
|
|
76
94
|
|
|
77
|
-
compileArrayExists(
|
|
78
|
-
|
|
95
|
+
compileArrayExists(context: ResolvedPathContext, identifier?: string): { sql: string } {
|
|
96
|
+
const { jsonArrayExpr } = this.#getSqliteArrayContext(context);
|
|
97
|
+
return { sql: `(${jsonArrayExpr} IS NOT NULL AND json_array_length(${jsonArrayExpr}) > 0)` };
|
|
79
98
|
}
|
|
80
99
|
|
|
81
100
|
getRegexOperator(caseInsensitive: boolean): string {
|