@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-sqlite",
3
- "version": "8.0.0-alpha.26",
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.22",
31
- "@travetto/context": "^8.0.0-alpha.20",
32
- "@travetto/model": "^8.0.0-alpha.23",
33
- "@travetto/model-query": "^8.0.0-alpha.24",
34
- "@travetto/model-sql": "^8.0.0-alpha.26"
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
- throw new ExistsError('query', query);
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
- compileArrayAll(sqlPath: string, identifier: string, value: unknown[]): { sql: string; formatted: unknown } {
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 value FROM json_each(${sqlPath})))`,
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(sqlPath: string, identifier: string, values: unknown): { sql: string; formatted: unknown } {
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 value FROM json_each(${sqlPath})))`,
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(${sqlPath}) AS elem WHERE NOT EXISTS (SELECT 1 FROM json_each(${identifier}) AS req WHERE json_extract(elem.value, '$.' || req.key) IS NOT req.value))`,
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(${sqlPath}) WHERE json_each.value = ${identifier})`,
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(sqlPath: string, identifier: string, values: unknown[]): { sql: string; formatted: unknown } {
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(${sqlPath}) AS elem WHERE elem.value IN (SELECT value FROM json_each(${identifier})))`,
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(sqlPath: string): { sql: string } {
78
- return { sql: `(${sqlPath} IS NOT NULL AND json_array_length(${sqlPath}) > 0)` };
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 {