@mikro-orm/sql 7.1.9-dev.0 → 7.1.9-dev.10
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/dialects/mssql/MsSqlNativeQueryBuilder.js +1 -1
- package/dialects/oracledb/OracleNativeQueryBuilder.js +1 -1
- package/dialects/sqlite/BaseSqliteConnection.d.ts +3 -0
- package/dialects/sqlite/BaseSqliteConnection.js +15 -5
- package/package.json +2 -2
- package/query/NativeQueryBuilder.js +1 -1
- package/query/QueryBuilderHelper.js +6 -1
- package/schema/SchemaComparator.js +9 -1
|
@@ -168,7 +168,7 @@ export class MsSqlNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
168
168
|
const fields = this.options.groupBy.map(field => this.quote(field));
|
|
169
169
|
this.parts.push(`group by ${fields.join(', ')}`);
|
|
170
170
|
}
|
|
171
|
-
if (this.options.having) {
|
|
171
|
+
if (this.options.having?.sql.trim()) {
|
|
172
172
|
this.parts.push(`having ${this.options.having.sql}`);
|
|
173
173
|
this.params.push(...this.options.having.params);
|
|
174
174
|
}
|
|
@@ -234,7 +234,7 @@ export class OracleNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
234
234
|
const fields = this.options.groupBy.map(field => this.quote(field));
|
|
235
235
|
this.parts.push(`group by ${fields.join(', ')}`);
|
|
236
236
|
}
|
|
237
|
-
if (this.options.having) {
|
|
237
|
+
if (this.options.having?.sql.trim()) {
|
|
238
238
|
this.parts.push(`having ${this.options.having.sql}`);
|
|
239
239
|
this.params.push(...this.options.having.params);
|
|
240
240
|
}
|
|
@@ -7,4 +7,7 @@ export declare class BaseSqliteConnection extends AbstractSqlConnection {
|
|
|
7
7
|
skipOnConnect?: boolean;
|
|
8
8
|
}): Promise<void>;
|
|
9
9
|
protected attachDatabases(): Promise<void>;
|
|
10
|
+
/** Per-connection state, lost whenever the underlying connection is recreated, so it has to be replayed. */
|
|
11
|
+
protected getConnectionSetupSql(): Promise<string[]>;
|
|
12
|
+
private getAttachDatabasesSql;
|
|
10
13
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CompiledQuery } from 'kysely';
|
|
2
2
|
import { AbstractSqlConnection } from '../../AbstractSqlConnection.js';
|
|
3
|
+
const FOREIGN_KEYS_PRAGMA = 'pragma foreign_keys = on';
|
|
3
4
|
export class BaseSqliteConnection extends AbstractSqlConnection {
|
|
4
5
|
createKyselyDialect(options) {
|
|
5
6
|
throw new Error('No SQLite dialect configured. Pass a Kysely dialect via the `driverOptions` config option, ' +
|
|
@@ -7,19 +8,28 @@ export class BaseSqliteConnection extends AbstractSqlConnection {
|
|
|
7
8
|
}
|
|
8
9
|
async connect(options) {
|
|
9
10
|
await super.connect(options);
|
|
10
|
-
await this.getClient().executeQuery(CompiledQuery.raw(
|
|
11
|
+
await this.getClient().executeQuery(CompiledQuery.raw(FOREIGN_KEYS_PRAGMA));
|
|
11
12
|
await this.attachDatabases();
|
|
12
13
|
}
|
|
13
14
|
async attachDatabases() {
|
|
15
|
+
for (const sql of await this.getAttachDatabasesSql()) {
|
|
16
|
+
await this.execute(sql);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Per-connection state, lost whenever the underlying connection is recreated, so it has to be replayed. */
|
|
20
|
+
async getConnectionSetupSql() {
|
|
21
|
+
return [FOREIGN_KEYS_PRAGMA, ...(await this.getAttachDatabasesSql())];
|
|
22
|
+
}
|
|
23
|
+
async getAttachDatabasesSql() {
|
|
14
24
|
const attachDatabases = this.config.get('attachDatabases');
|
|
15
25
|
if (!attachDatabases?.length) {
|
|
16
|
-
return;
|
|
26
|
+
return [];
|
|
17
27
|
}
|
|
18
28
|
const { fs } = await import('@mikro-orm/core/fs-utils');
|
|
19
29
|
const baseDir = this.config.get('baseDir');
|
|
20
|
-
|
|
30
|
+
return attachDatabases.map(db => {
|
|
21
31
|
const path = fs.absolutePath(db.path, baseDir);
|
|
22
|
-
|
|
23
|
-
}
|
|
32
|
+
return `attach database '${path}' as ${this.platform.quoteIdentifier(db.name)}`;
|
|
33
|
+
});
|
|
24
34
|
}
|
|
25
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/sql",
|
|
3
|
-
"version": "7.1.9-dev.
|
|
3
|
+
"version": "7.1.9-dev.10",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"data-mapper",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@mikro-orm/core": "^7.1.8"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@mikro-orm/core": "7.1.9-dev.
|
|
56
|
+
"@mikro-orm/core": "7.1.9-dev.10"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">= 22.17.0"
|
|
@@ -308,7 +308,7 @@ export class NativeQueryBuilder {
|
|
|
308
308
|
const fields = this.options.groupBy.map(field => this.quote(field));
|
|
309
309
|
this.parts.push(`group by ${fields.join(', ')}`);
|
|
310
310
|
}
|
|
311
|
-
if (this.options.having) {
|
|
311
|
+
if (this.options.having?.sql.trim()) {
|
|
312
312
|
this.parts.push(`having ${this.options.having.sql}`);
|
|
313
313
|
this.params.push(...this.options.having.params);
|
|
314
314
|
}
|
|
@@ -414,7 +414,8 @@ export class QueryBuilderHelper {
|
|
|
414
414
|
}
|
|
415
415
|
if (k === '$not') {
|
|
416
416
|
const res = this._appendQueryCondition(type, cond[k]);
|
|
417
|
-
|
|
417
|
+
// negating a vacuously true condition (e.g. an empty `$and`) matches nothing
|
|
418
|
+
parts.push(res.sql ? `not (${res.sql})` : '1 = 0');
|
|
418
419
|
res.params.forEach(p => params.push(p));
|
|
419
420
|
continue;
|
|
420
421
|
}
|
|
@@ -785,6 +786,10 @@ export class QueryBuilderHelper {
|
|
|
785
786
|
appendGroupCondition(type, operator, subCondition) {
|
|
786
787
|
const parts = [];
|
|
787
788
|
const params = [];
|
|
789
|
+
// an empty disjunction is false, same as `$in: []`, while an empty conjunction is vacuously true
|
|
790
|
+
if (operator === '$or' && subCondition.length === 0) {
|
|
791
|
+
return { sql: '1 = 0', params };
|
|
792
|
+
}
|
|
788
793
|
// single sub-condition can be ignored to reduce nesting of parens
|
|
789
794
|
if (subCondition.length === 1 || operator === '$and') {
|
|
790
795
|
for (const sub of subCondition) {
|
|
@@ -897,9 +897,13 @@ export class SchemaComparator {
|
|
|
897
897
|
// lookbehind: only strip a real charset introducer, never an underscore inside a literal like 'a_b'
|
|
898
898
|
?.replace(/(?<![\w'])_\w+'(.*?)'/g, '$1')
|
|
899
899
|
.replace(/!=/g, '<>')
|
|
900
|
-
|
|
900
|
+
// `\b` keeps this from firing inside identifiers like `min(...)`
|
|
901
|
+
.replace(/\bin\s*\((.*?)\)/gi, '= any (array[$1])')
|
|
901
902
|
// MySQL normalizes count(*) to count(0)
|
|
902
903
|
.replace(/\bcount\s*\(\s*0\s*\)/gi, 'count(*)')
|
|
904
|
+
// multi word type names in casts, the generic `::\w+` below only covers single word ones
|
|
905
|
+
// the precision is kept, so `timestamptz(3)` and `timestamp(3) with time zone` leave the same residue
|
|
906
|
+
.replace(/::\s*(?:character\s+varying|bit\s+varying|double\s+precision|(?:timestamp|time)\b(\s*\(\d+\))?(?:\s+with(?:out)?\s+time\s+zone)?)/gi, '$1')
|
|
903
907
|
// Remove quotes first so we can process identifiers
|
|
904
908
|
.replace(/['"`]/g, '')
|
|
905
909
|
// MySQL adds table/alias prefixes to columns (e.g., a.name or table_name.column vs just column)
|
|
@@ -907,6 +911,10 @@ export class SchemaComparator {
|
|
|
907
911
|
.replace(/\b\w+\.(\w+)/g, '$1')
|
|
908
912
|
// Normalize JOIN syntax: inner join -> join (equivalent in SQL)
|
|
909
913
|
.replace(/\binner\s+join\b/gi, 'join')
|
|
914
|
+
// PostgreSQL names an unaliased bare function call after the function itself,
|
|
915
|
+
// so `max(created_at)` comes back as `max(created_at) AS max`
|
|
916
|
+
// the lookahead skips table function column alias lists like `unnest(a) AS unnest(c)`, which are meaningful
|
|
917
|
+
.replace(/\b(\w+)\s*\(((?:[^()]|\([^()]*\))*)\)\s+as\s+\1\b(?!\s*\()/gi, '$1($2)')
|
|
910
918
|
// Remove redundant column aliases like `title AS title` -> `title`
|
|
911
919
|
.replace(/\b(\w+)\s+as\s+\1\b/gi, '$1')
|
|
912
920
|
// Remove AS keyword (optional in SQL, MySQL may add/remove it)
|