Skip to content

Commit b3c3362

Browse files
authored
feat: re-add the ability to override the connector library (#17219)
BREAKING CHANGE: The `dialectModulePath` has been fully removed to improve compatibility with bundlers. BREAKING CHANGE: The `dialectModule` option has been split into multiple options. Each option is named after the npm library that is being replaced. For instance, `@sequelize/postgres` now accepts `pgModule`. `@sequelize/mssql` now accepts `tediousModule`
1 parent 0808ac1 commit b3c3362

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+499
-254
lines changed

.husky/pre-commit

-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
yarn lint-staged --concurrent false
22
yarn delete-changelog
3-
git add .

dev/delete-changelog.mjs

+23
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { execFile } from 'node:child_process';
12
import fs from 'node:fs/promises';
23
import path from 'node:path';
34
import { fileURLToPath } from 'node:url';
@@ -15,6 +16,16 @@ await Promise.all(
1516
changelogPaths.map(async changelogPath => {
1617
if (await tryAccess(changelogPath)) {
1718
await fs.unlink(changelogPath);
19+
const { stderr, stdout } = await execFileAsync(`git`, ['add', changelogPath]);
20+
21+
if (stdout) {
22+
console.info(`stdout: ${stdout}`);
23+
}
24+
25+
if (stderr) {
26+
console.error(`stderr: ${stderr}`);
27+
}
28+
1829
console.info(`Deleted ${changelogPath}`);
1930
}
2031
}),
@@ -29,3 +40,15 @@ async function tryAccess(filename) {
2940
return false;
3041
}
3142
}
43+
44+
function execFileAsync(file, args) {
45+
return new Promise((resolve, reject) => {
46+
execFile(file, args, (error, stdout, stderr) => {
47+
if (error) {
48+
reject(error);
49+
}
50+
51+
resolve({ stdout, stderr });
52+
});
53+
});
54+
}

packages/core/src/abstract-dialect/connection-manager.ts

+1-34
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { isNodeError } from '@sequelize/utils/node';
21
import cloneDeep from 'lodash/cloneDeep';
32
import semver from 'semver';
43
import { TimeoutError } from 'sequelize-pool';
54
import { ConnectionAcquireTimeoutError } from '../errors';
65
import type { ConnectionOptions, Sequelize } from '../sequelize.js';
76
import * as deprecations from '../utils/deprecations';
87
import { logger } from '../utils/logger';
9-
import type { AbstractDialect } from './index.js';
8+
import type { AbstractDialect } from './dialect.js';
109
import { ReplicationPool } from './replication-pool.js';
1110

1211
const debug = logger.debugContext('connection-manager');
@@ -114,38 +113,6 @@ export class AbstractConnectionManager<
114113
throw new Error(`disconnect not implemented in ${this.constructor.name}`);
115114
}
116115

117-
/**
118-
* Try to load dialect module from various configured options.
119-
* Priority goes like dialectModulePath > dialectModule > require(default)
120-
*
121-
* @param moduleName Name of dialect module to lookup
122-
*
123-
* @private
124-
*/
125-
_loadDialectModule(moduleName: string): unknown {
126-
try {
127-
if (this.sequelize.config.dialectModulePath) {
128-
return require(this.sequelize.config.dialectModulePath);
129-
}
130-
131-
if (this.sequelize.config.dialectModule) {
132-
return this.sequelize.config.dialectModule;
133-
}
134-
135-
return require(moduleName);
136-
} catch (error) {
137-
if (isNodeError(error) && error.code === 'MODULE_NOT_FOUND') {
138-
if (this.sequelize.config.dialectModulePath) {
139-
throw new Error(`Unable to find dialect at ${this.sequelize.config.dialectModulePath}`);
140-
}
141-
142-
throw new Error(`Please install ${moduleName} package manually`);
143-
}
144-
145-
throw error;
146-
}
147-
}
148-
149116
/**
150117
* Handler which executes on process exit or connection manager shutdown
151118
*/

packages/core/src/abstract-dialect/data-types-utils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type {
88
DataTypeInstance,
99
} from './data-types.js';
1010
import { AbstractDataType } from './data-types.js';
11-
import type { AbstractDialect } from './index.js';
11+
import type { AbstractDialect } from './dialect.js';
1212

1313
export function isDataType(value: any): value is DataType {
1414
return isDataTypeClass(value) || value instanceof AbstractDataType;

packages/core/src/abstract-dialect/data-types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
isDataTypeClass,
2929
throwUnsupportedDataType,
3030
} from './data-types-utils.js';
31-
import type { AbstractDialect } from './index.js';
31+
import type { AbstractDialect } from './dialect.js';
3232
import type { TableNameWithSchema } from './query-interface.js';
3333

3434
// TODO: try merging "validate" & "sanitize" by making sanitize coerces the type, and if it cannot, throw a ValidationError.

packages/core/src/abstract-dialect/index.ts packages/core/src/abstract-dialect/dialect.ts

+57-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { freezeDeep, isFunction } from '@sequelize/utils';
1+
import { EMPTY_OBJECT, freezeDeep, getImmutablePojo, isFunction, isString } from '@sequelize/utils';
22
import cloneDeep from 'lodash/cloneDeep';
33
import merge from 'lodash/merge';
44
import type { Class } from 'type-fest';
@@ -274,6 +274,22 @@ declare const OptionType: unique symbol;
274274

275275
export type DialectOptions<Dialect extends AbstractDialect> = Dialect[typeof OptionType];
276276

277+
export type AbstractDialectParams<Options> = {
278+
dataTypeOverrides: Record<string, Class<AbstractDataType<any>>>;
279+
dataTypesDocumentationUrl: string;
280+
/**
281+
* The character used to delimit identifiers in SQL queries.
282+
*
283+
* This can be a string, in which case the character will be used for both the start & end of the identifier,
284+
* or an object with `start` and `end` properties.
285+
*/
286+
identifierDelimiter: string | { start: string; end: string };
287+
minimumDatabaseVersion: string;
288+
name: DialectName;
289+
options: Options | undefined;
290+
sequelize: Sequelize;
291+
};
292+
277293
export abstract class AbstractDialect<Options extends object = {}> {
278294
declare [OptionType]: Options;
279295

@@ -475,17 +491,37 @@ export abstract class AbstractDialect<Options extends object = {}> {
475491

476492
readonly sequelize: Sequelize;
477493

478-
abstract readonly defaultVersion: string;
479494
abstract readonly Query: typeof AbstractQuery;
480-
abstract readonly TICK_CHAR_LEFT: string;
481-
abstract readonly TICK_CHAR_RIGHT: string;
482495
abstract readonly queryGenerator: AbstractQueryGenerator;
483496
abstract readonly queryInterface: AbstractQueryInterface;
484497
abstract readonly connectionManager: AbstractConnectionManager<any, any>;
485-
abstract readonly dataTypesDocumentationUrl: string;
486498

499+
/**
500+
* @deprecated use {@link minimumDatabaseVersion}
501+
*/
502+
get defaultVersion(): string {
503+
return this.minimumDatabaseVersion;
504+
}
505+
506+
/**
507+
* @deprecated use {@link identifierDelimiter}.start
508+
*/
509+
get TICK_CHAR_LEFT(): string {
510+
return this.identifierDelimiter.start;
511+
}
512+
513+
/**
514+
* @deprecated use {@link identifierDelimiter}.end
515+
*/
516+
get TICK_CHAR_RIGHT(): string {
517+
return this.identifierDelimiter.end;
518+
}
519+
520+
readonly identifierDelimiter: { readonly start: string; readonly end: string };
521+
readonly minimumDatabaseVersion: string;
522+
readonly dataTypesDocumentationUrl: string;
523+
readonly options: Options;
487524
readonly name: DialectName;
488-
readonly DataTypes: Record<string, Class<AbstractDataType<any>>>;
489525

490526
/** dialect-specific implementation of shared data types */
491527
readonly #dataTypeOverrides: Map<string, Class<AbstractDataType<any>>>;
@@ -499,14 +535,20 @@ export abstract class AbstractDialect<Options extends object = {}> {
499535
return Dialect.supports;
500536
}
501537

502-
constructor(
503-
sequelize: Sequelize,
504-
dialectDataTypes: Record<string, Class<AbstractDataType<any>>>,
505-
dialectName: DialectName,
506-
) {
507-
this.sequelize = sequelize;
508-
this.DataTypes = dialectDataTypes;
509-
this.name = dialectName;
538+
constructor(params: AbstractDialectParams<Options>) {
539+
this.sequelize = params.sequelize;
540+
this.name = params.name;
541+
this.dataTypesDocumentationUrl = params.dataTypesDocumentationUrl;
542+
this.options = params.options ? getImmutablePojo(params.options) : EMPTY_OBJECT;
543+
544+
this.identifierDelimiter = isString(params.identifierDelimiter)
545+
? Object.freeze({
546+
start: params.identifierDelimiter,
547+
end: params.identifierDelimiter,
548+
})
549+
: getImmutablePojo(params.identifierDelimiter);
550+
551+
this.minimumDatabaseVersion = params.minimumDatabaseVersion;
510552

511553
const baseDataTypes = new Map<string, Class<AbstractDataType<any>>>();
512554
for (const dataType of Object.values(BaseDataTypes) as Array<Class<AbstractDataType<any>>>) {
@@ -532,7 +574,7 @@ export abstract class AbstractDialect<Options extends object = {}> {
532574
}
533575

534576
const dataTypeOverrides = new Map<string, Class<AbstractDataType<any>>>();
535-
for (const dataType of Object.values(this.DataTypes)) {
577+
for (const dataType of Object.values(params.dataTypeOverrides)) {
536578
const replacedDataTypeId: string = (
537579
dataType as unknown as typeof AbstractDataType
538580
).getDataTypeId();

packages/core/src/abstract-dialect/query-generator-internal.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type { Sequelize } from '../sequelize.js';
1313
import { extractModelDefinition } from '../utils/model-utils.js';
1414
import { injectReplacements } from '../utils/sql.js';
1515
import { attributeTypeToSql } from './data-types-utils.js';
16-
import type { AbstractDialect } from './index.js';
16+
import type { AbstractDialect } from './dialect.js';
1717
import type { EscapeOptions } from './query-generator-typescript.js';
1818
import type { AddLimitOffsetOptions } from './query-generator.internal-types.js';
1919
import type { GetConstraintSnippetQueryOptions, TableOrModel } from './query-generator.types.js';

packages/core/src/abstract-dialect/query-generator-typescript.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import {
3737
} from '../utils/model-utils.js';
3838
import type { BindParamOptions, DataType } from './data-types.js';
3939
import { AbstractDataType } from './data-types.js';
40-
import type { AbstractDialect } from './index.js';
40+
import type { AbstractDialect } from './dialect.js';
4141
import { AbstractQueryGeneratorInternal } from './query-generator-internal.js';
4242
import type {
4343
AddConstraintQueryOptions,

packages/core/src/abstract-dialect/query-interface-internal.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import assert from 'node:assert';
22
import { QueryTypes } from '../query-types.js';
33
import type { QueryRawOptions, Sequelize } from '../sequelize.js';
4-
import type { AbstractDialect } from './index.js';
4+
import type { AbstractDialect } from './dialect.js';
55
import type { AbstractQueryGenerator } from './query-generator.js';
66
import type { FetchDatabaseVersionOptions } from './query-interface.types.js';
77

packages/core/src/abstract-dialect/query-interface-typescript.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
showAllToListTables,
1616
} from '../utils/deprecations';
1717
import type { Connection } from './connection-manager.js';
18-
import type { AbstractDialect } from './index.js';
18+
import type { AbstractDialect } from './dialect.js';
1919
import type { TableOrModel } from './query-generator.types.js';
2020
import { AbstractQueryInterfaceInternal } from './query-interface-internal.js';
2121
import type { TableNameWithSchema } from './query-interface.js';

packages/core/src/abstract-dialect/query-interface.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type {
1414
import type { QueryRawOptions, QueryRawOptionsWithModel } from '../sequelize';
1515
import type { AllowLowercase } from '../utils/types.js';
1616
import type { DataType } from './data-types.js';
17-
import type { AbstractDialect } from './index.js';
17+
import type { AbstractDialect } from './dialect.js';
1818
import type { AddLimitOffsetOptions } from './query-generator.internal-types.js';
1919
import type { AddColumnQueryOptions } from './query-generator.js';
2020
import type { RemoveIndexQueryOptions, TableOrModel } from './query-generator.types.js';

packages/core/src/expression-builders/dialect-aware-fn.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Class } from 'type-fest';
2-
import type { AbstractDialect } from '../abstract-dialect/index.js';
2+
import type { AbstractDialect } from '../abstract-dialect/dialect.js';
33
import type { EscapeOptions } from '../abstract-dialect/query-generator-typescript.js';
44
import type { Expression } from '../sequelize.js';
55
import { BaseSqlExpression } from './base-sql-expression.js';

packages/core/src/expression-builders/json-sql-null.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { AbstractDialect } from '../abstract-dialect/index.js';
1+
import type { AbstractDialect } from '../abstract-dialect/dialect.js';
22
import { DialectAwareFn } from './dialect-aware-fn.js';
33
import { literal } from './literal.js';
44

packages/core/src/expression-builders/uuid.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import crypto from 'node:crypto';
22
import { v1 as generateUuidV1 } from 'uuid';
3-
import type { AbstractDialect } from '../abstract-dialect/index.js';
3+
import type { AbstractDialect } from '../abstract-dialect/dialect.js';
44
import { DialectAwareFn } from './dialect-aware-fn.js';
55

66
export class SqlUuidV4 extends DialectAwareFn {

packages/core/src/index.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export type {
3131
TimeOptions,
3232
VirtualOptions,
3333
} from './abstract-dialect/data-types.js';
34-
export { AbstractDialect } from './abstract-dialect/index.js';
34+
export { AbstractDialect } from './abstract-dialect/dialect.js';
3535
export { AbstractQueryGenerator } from './abstract-dialect/query-generator.js';
3636
export * from './abstract-dialect/query-generator.types.js';
3737
export * from './abstract-dialect/query-interface.js';

packages/core/src/model-set-view.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { SetView } from '@sequelize/utils';
22
import { inspect } from 'node:util';
33
// @ts-expect-error -- toposort-class definition will be added to sequelize/toposort later
44
import Toposort from 'toposort-class';
5-
import type { AbstractDialect } from './abstract-dialect/index.js';
5+
import type { AbstractDialect } from './abstract-dialect/dialect.js';
66
import type { Model, ModelStatic } from './model';
77
import type { SequelizeTypeScript } from './sequelize-typescript.js';
88

packages/core/src/sequelize-typescript.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import type {
1717
import type { Connection, GetConnectionOptions } from './abstract-dialect/connection-manager.js';
1818
import { normalizeDataType, validateDataType } from './abstract-dialect/data-types-utils.js';
1919
import type { AbstractDataType } from './abstract-dialect/data-types.js';
20-
import type { AbstractDialect } from './abstract-dialect/index.js';
20+
import type { AbstractDialect } from './abstract-dialect/dialect.js';
2121
import type { EscapeOptions } from './abstract-dialect/query-generator-typescript.js';
2222
import type { QiDropAllSchemasOptions } from './abstract-dialect/query-interface.types.js';
2323
import type { AbstractQuery } from './abstract-dialect/query.js';

packages/core/src/sequelize.d.ts

+1-17
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import type {
99
TransactionNestMode,
1010
TransactionType,
1111
} from '.';
12-
import type { AbstractDialect, DialectOptions } from './abstract-dialect';
1312
import type { DataType } from './abstract-dialect/data-types.js';
13+
import type { AbstractDialect, DialectOptions } from './abstract-dialect/dialect.js';
1414
import type {
1515
ColumnsDescription,
1616
RawConstraintDescription,
@@ -164,7 +164,6 @@ export interface NormalizedReplicationOptions {
164164
*/
165165
export interface Config {
166166
readonly database: string;
167-
readonly dialectModule?: object;
168167
readonly host?: string;
169168
readonly port: number;
170169
readonly username: string;
@@ -173,7 +172,6 @@ export interface Config {
173172
readonly protocol: 'tcp';
174173
readonly ssl: boolean;
175174
readonly replication: NormalizedReplicationOptions;
176-
readonly dialectModulePath: null | string;
177175
readonly keepDefaultTimezone?: boolean;
178176
readonly dialectOptions: Readonly<LegacyDialectOptions>;
179177
}
@@ -190,20 +188,6 @@ interface SequelizeCoreOptions<Dialect extends AbstractDialect> extends Logging
190188
*/
191189
dialect?: DialectName | Class<Dialect>;
192190

193-
/**
194-
* If specified, will use the provided module as the dialect.
195-
*
196-
* @example
197-
* `dialectModule: require('@myorg/tedious'),`
198-
*/
199-
dialectModule?: object;
200-
201-
/**
202-
* If specified, load the dialect library from this path. For example, if you want to use pg.js instead of
203-
* pg when connecting to a pg database, you should specify 'pg.js' here
204-
*/
205-
dialectModulePath?: string;
206-
207191
/**
208192
* An object of additional options, which are passed directly to the connection library
209193
*/

packages/core/src/sequelize.internals.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { AbstractDialect } from './abstract-dialect/index.js';
1+
import type { AbstractDialect } from './abstract-dialect/dialect.js';
22
import type { DialectName } from './sequelize.js';
33

44
export function importDialect(dialect: DialectName): typeof AbstractDialect {

0 commit comments

Comments
 (0)