@travetto/model-mysql 8.0.0-alpha.30 → 8.0.0-alpha.32
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/dialect.ts +37 -37
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model-mysql",
|
|
3
|
-
"version": "8.0.0-alpha.
|
|
3
|
+
"version": "8.0.0-alpha.32",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MySQL backing for the travetto model module, with real-time modeling support for SQL schemas.",
|
|
6
6
|
"keywords": [
|
|
@@ -28,15 +28,15 @@
|
|
|
28
28
|
"directory": "module/model-mysql"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@travetto/config": "^8.0.0-alpha.
|
|
31
|
+
"@travetto/config": "^8.0.0-alpha.25",
|
|
32
32
|
"@travetto/context": "^8.0.0-alpha.22",
|
|
33
|
-
"@travetto/model": "^8.0.0-alpha.
|
|
34
|
-
"@travetto/model-query": "^8.0.0-alpha.
|
|
35
|
-
"@travetto/model-sql": "^8.0.0-alpha.
|
|
33
|
+
"@travetto/model": "^8.0.0-alpha.26",
|
|
34
|
+
"@travetto/model-query": "^8.0.0-alpha.28",
|
|
35
|
+
"@travetto/model-sql": "^8.0.0-alpha.31",
|
|
36
36
|
"mysql2": "^3.23.1"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@travetto/cli": "^8.0.0-alpha.
|
|
39
|
+
"@travetto/cli": "^8.0.0-alpha.31"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
|
42
42
|
"@travetto/cli": {
|
package/src/dialect.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AbstractANSI99Dialect, type JSONSqlPathMode, type ResolvedPathContext, type TableContext } from '@travetto/model-sql';
|
|
2
2
|
import { type Class, castTo, JSONUtil } from '@travetto/runtime';
|
|
3
|
-
import {
|
|
3
|
+
import type { SchemaFieldConfig } from '@travetto/schema';
|
|
4
4
|
|
|
5
5
|
export class MysqlDialect extends AbstractANSI99Dialect {
|
|
6
6
|
override returningSupport = false;
|
|
@@ -54,36 +54,15 @@ export class MysqlDialect extends AbstractANSI99Dialect {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
compileJsonIndexPath(columnName: string, jsonPath: string[], mode: JSONSqlPathMode): string {
|
|
57
|
-
|
|
58
|
-
switch (mode) {
|
|
59
|
-
case 'createIndex':
|
|
60
|
-
return `(CAST(${result} as CHAR(255)) COLLATE utf8mb4_bin)`;
|
|
61
|
-
case 'orderBy':
|
|
62
|
-
case 'read':
|
|
63
|
-
return result;
|
|
64
|
-
}
|
|
57
|
+
return `${columnName}->>'$.${this.formatJsonPath(jsonPath)}'`;
|
|
65
58
|
}
|
|
66
59
|
|
|
67
60
|
#formatSubPath(context: ResolvedPathContext): string {
|
|
68
61
|
if (!context.subPath || context.subPath.length === 0) {
|
|
69
62
|
return '';
|
|
70
63
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
for (let index = 0; index < context.subPath.length; index++) {
|
|
74
|
-
const segment = context.subPath[index];
|
|
75
|
-
if (currentClass) {
|
|
76
|
-
const classConfig = SchemaRegistryIndex.getOptional(currentClass)?.get();
|
|
77
|
-
const fieldConfig = classConfig?.fields[segment];
|
|
78
|
-
if (fieldConfig) {
|
|
79
|
-
parts.push(fieldConfig.array ? `${segment}[*]` : segment);
|
|
80
|
-
currentClass = fieldConfig.type;
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
parts.push(segment);
|
|
85
|
-
}
|
|
86
|
-
return parts.join('.');
|
|
64
|
+
const subPathMetadata = this.getSchemaSubPathMetadata(context.arrayField?.type, context.subPath);
|
|
65
|
+
return subPathMetadata.map(({ segment, isArray }) => (isArray ? `${segment}[*]` : segment)).join('.');
|
|
87
66
|
}
|
|
88
67
|
|
|
89
68
|
#getArraySqlPath(context: ResolvedPathContext): string {
|
|
@@ -150,6 +129,8 @@ export class MysqlDialect extends AbstractANSI99Dialect {
|
|
|
150
129
|
return `CAST(${sqlPath} AS SIGNED)`;
|
|
151
130
|
} else if (type === Date) {
|
|
152
131
|
return `CAST(${sqlPath} AS DATETIME(6))`;
|
|
132
|
+
} else if (type === String) {
|
|
133
|
+
return `(CAST(${sqlPath} AS CHAR(255)) COLLATE utf8mb4_bin)`;
|
|
153
134
|
}
|
|
154
135
|
return sqlPath;
|
|
155
136
|
}
|
|
@@ -161,13 +142,8 @@ export class MysqlDialect extends AbstractANSI99Dialect {
|
|
|
161
142
|
conflictTarget: string[],
|
|
162
143
|
updates: string[]
|
|
163
144
|
): string {
|
|
164
|
-
const
|
|
165
|
-
return `
|
|
166
|
-
INSERT INTO
|
|
167
|
-
${this.escapeIdentifier(context.tableName)} (${columns.join(', ')})
|
|
168
|
-
VALUES
|
|
169
|
-
(${placeholders.join(', ')})
|
|
170
|
-
ON DUPLICATE KEY UPDATE ${mysqlUpdates.join(', ')};`;
|
|
145
|
+
const mysqlUpdateStatements = updates.map(statement => statement.replaceAll(/EXCLUDED\.(.*)/g, 'new_row.$1'));
|
|
146
|
+
return `INSERT INTO ${this.escapeIdentifier(context.tableName)} (${columns.join(', ')}) VALUES (${placeholders.join(', ')}) AS new_row ON DUPLICATE KEY UPDATE ${mysqlUpdateStatements.join(', ')};`;
|
|
171
147
|
}
|
|
172
148
|
|
|
173
149
|
getTableExistsQuery(context: TableContext): { sql: string; parameters?: unknown[] } {
|
|
@@ -191,7 +167,7 @@ WHERE table_schema = ? AND table_name = ?;
|
|
|
191
167
|
sql: `
|
|
192
168
|
SELECT
|
|
193
169
|
COLUMN_NAME as name,
|
|
194
|
-
|
|
170
|
+
COLUMN_TYPE as type
|
|
195
171
|
FROM information_schema.columns
|
|
196
172
|
WHERE table_schema = ? AND table_name = ?;
|
|
197
173
|
`,
|
|
@@ -206,23 +182,47 @@ WHERE table_schema = ? AND table_name = ?;
|
|
|
206
182
|
getExistingIndexesQuery(context: TableContext): { sql: string; parameters?: unknown[] } {
|
|
207
183
|
return {
|
|
208
184
|
sql: `
|
|
209
|
-
SELECT
|
|
210
|
-
INDEX_NAME as name
|
|
185
|
+
SELECT
|
|
186
|
+
INDEX_NAME as name,
|
|
187
|
+
TABLE_NAME as tableName,
|
|
188
|
+
NON_UNIQUE as nonUnique,
|
|
189
|
+
GROUP_CONCAT(COALESCE(EXPRESSION, COLUMN_NAME) ORDER BY SEQ_IN_INDEX SEPARATOR ', ') as indexColumns
|
|
211
190
|
FROM information_schema.statistics
|
|
212
191
|
WHERE
|
|
213
192
|
table_schema = ?
|
|
214
193
|
AND table_name = ?
|
|
215
|
-
AND INDEX_NAME != 'PRIMARY'
|
|
194
|
+
AND INDEX_NAME != 'PRIMARY'
|
|
195
|
+
GROUP BY INDEX_NAME, TABLE_NAME, NON_UNIQUE;
|
|
216
196
|
`,
|
|
217
197
|
parameters: [context.database, context.tableName]
|
|
218
198
|
};
|
|
219
199
|
}
|
|
220
200
|
|
|
221
201
|
parseExistingIndexes(records: unknown[]): Map<string, string> {
|
|
222
|
-
return new Map(
|
|
202
|
+
return new Map(
|
|
203
|
+
castTo<{ name: string; tableName: string; nonUnique: number; indexColumns: string }[]>(records).map(record => {
|
|
204
|
+
const isUnique = Number(record.nonUnique) === 0;
|
|
205
|
+
const indexDefinition = `CREATE ${isUnique ? 'UNIQUE ' : ''}INDEX ${this.escapeIdentifier(record.name)} ON ${this.escapeIdentifier(record.tableName)} (${record.indexColumns});`;
|
|
206
|
+
return [record.name, indexDefinition];
|
|
207
|
+
})
|
|
208
|
+
);
|
|
223
209
|
}
|
|
224
210
|
|
|
225
211
|
override getDropIndexSQL(context: TableContext, indexName: string): string {
|
|
226
212
|
return `DROP INDEX ${this.escapeIdentifier(indexName)} ON ${this.escapeIdentifier(context.tableName)};`;
|
|
227
213
|
}
|
|
214
|
+
|
|
215
|
+
override getTruncateTableSQL(context: TableContext): string {
|
|
216
|
+
return `TRUNCATE TABLE ${this.escapeIdentifier(context.tableName)};`;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
override getAlterColumnTypeSQL(context: TableContext, columnName: string, columnType: string, existingType: string): string | undefined {
|
|
220
|
+
const normalizedExisting = existingType.replaceAll('CHARACTER VARYING', 'VARCHAR').replaceAll('INTEGER', 'INT');
|
|
221
|
+
const normalizedRequested = columnType.toUpperCase().replaceAll('CHARACTER VARYING', 'VARCHAR').replaceAll('INTEGER', 'INT');
|
|
222
|
+
|
|
223
|
+
if (!normalizedExisting.startsWith(normalizedRequested) && !normalizedRequested.startsWith(normalizedExisting)) {
|
|
224
|
+
return `ALTER TABLE ${this.escapeIdentifier(context.tableName)} MODIFY COLUMN ${this.escapeIdentifier(columnName)} ${columnType};`;
|
|
225
|
+
}
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
228
|
}
|