├── .editorconfig ├── .eslintrc.json ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .npmrc ├── dev ├── check-connection.ts ├── ci-db-configs.ts ├── create-sequelize-instance.ts ├── global-adjusts.ts ├── lib-replacements.ts ├── logging.ts ├── mariadb │ ├── latest │ │ ├── docker-compose.yml │ │ ├── reset.sh │ │ ├── start.sh │ │ └── stop.sh │ └── oldest │ │ ├── docker-compose.yml │ │ ├── reset.sh │ │ ├── start.sh │ │ └── stop.sh ├── mssql │ ├── latest │ │ ├── docker-compose.yml │ │ ├── reset.sh │ │ ├── start.sh │ │ └── stop.sh │ └── oldest │ │ ├── docker-compose.yml │ │ ├── reset.sh │ │ ├── start.sh │ │ └── stop.sh ├── mysql │ ├── latest │ │ ├── docker-compose.yml │ │ ├── reset.sh │ │ ├── start.sh │ │ └── stop.sh │ └── oldest │ │ ├── docker-compose.yml │ │ ├── reset.sh │ │ ├── start.sh │ │ └── stop.sh ├── postgres │ ├── latest │ │ ├── docker-compose.yml │ │ ├── reset.sh │ │ ├── start.sh │ │ └── stop.sh │ └── oldest │ │ ├── docker-compose.yml │ │ ├── reset.sh │ │ ├── start.sh │ │ └── stop.sh ├── prepare-ci.sh ├── runner.ts ├── sequelize-version.cjs ├── ts-setup.ts ├── wait-until-healthy.sh └── wrap-options.ts ├── license ├── package.json ├── readme.md ├── src ├── sscce-sequelize-6.ts └── sscce-sequelize-7.ts ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 2 11 | end_of_line = lf 12 | charset = utf-8 13 | trim_trailing_whitespace = true 14 | insert_final_newline = true 15 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@ephys/eslint-config-typescript", 4 | "@ephys/eslint-config-typescript/node" 5 | ], 6 | "rules": { 7 | "unicorn/prefer-node-protocol": "off", 8 | "no-console": "off", 9 | "import/order": "off", 10 | "prefer-object-has-own": "off", 11 | "unicorn/prefer-at": "off", 12 | "@typescript-eslint/no-unused-expressions": "off", 13 | 14 | // we still have to support node 10 while Sequelize 6 remains alive 15 | "unicorn/prefer-module": "off", 16 | "unicorn/prefer-top-level-await": "off" 17 | }, 18 | "ignorePatterns": ["src/*"] 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | 5 | # This configuration cancels previous runs if a new run is started on the same PR. Only one run at a time per PR. 6 | # from https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-using-a-fallback-value 7 | concurrency: 8 | group: ${{ github.head_ref || github.run_id }} 9 | cancel-in-progress: true 10 | 11 | jobs: 12 | test-sqlite: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | node-version: [10, 18, 20] 17 | name: sqlite (Node ${{ matrix.node-version }}) 18 | runs-on: ubuntu-latest 19 | env: 20 | DIALECT: sqlite 21 | steps: 22 | - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 23 | - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | cache: yarn 27 | - run: /bin/bash ./dev/prepare-ci.sh 28 | - name: Execute SSCCE 29 | run: yarn run _test 30 | test-postgres: 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | node-version: [10, 18, 20] 35 | postgres-version: [oldest, latest] 36 | minify-aliases: [true, false] 37 | native: [true, false] 38 | name: postgres ${{ matrix.postgres-version }}${{ matrix.native && ' (native)' || '' }} (Node ${{ matrix.node-version }})${{ matrix.minify-aliases && ' (minified aliases)' || '' }} 39 | runs-on: ubuntu-latest 40 | env: 41 | DIALECT: ${{ matrix.native && 'postgres-native' || 'postgres' }} 42 | SEQ_PG_MINIFY_ALIASES: ${{ matrix.minify-aliases && '1' || '' }} 43 | steps: 44 | - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 45 | - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 46 | with: 47 | node-version: ${{ matrix.node-version }} 48 | cache: yarn 49 | - run: /bin/bash ./dev/prepare-ci.sh 50 | - run: yarn start-postgres-${{ matrix.postgres-version }} 51 | - name: Execute SSCCE 52 | run: yarn run _test 53 | test-oldest-latest: 54 | strategy: 55 | fail-fast: false 56 | matrix: 57 | node-version: [10, 18, 20] 58 | database-version: [oldest, latest] 59 | dialect: [mysql, mariadb, mssql] 60 | name: ${{ matrix.dialect }} ${{ matrix.database-version }} (Node ${{ matrix.node-version }}) 61 | runs-on: ubuntu-latest 62 | env: 63 | DIALECT: ${{ matrix.dialect }} 64 | steps: 65 | - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 66 | - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 67 | with: 68 | node-version: ${{ matrix.node-version }} 69 | cache: yarn 70 | - run: /bin/bash ./dev/prepare-ci.sh 71 | - run: yarn start-${{ matrix.dialect }}-${{ matrix.database-version }} 72 | - name: Execute SSCCE 73 | run: yarn run _test 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .idea 3 | .DS_STORE 4 | npm-debug.log* 5 | *~ 6 | test.sqlite 7 | test.sqlite2 8 | *.sublime* 9 | package-lock.json 10 | pnpm-lock.yaml 11 | 12 | .nyc_output 13 | coverage-* 14 | coverage 15 | tmp 16 | .vscode/ 17 | .typedoc-build 18 | node_modules 19 | *.log 20 | /.nx 21 | 22 | .pnp.* 23 | .yarn/* 24 | !.yarn/patches 25 | !.yarn/plugins 26 | !.yarn/releases 27 | !.yarn/sdks 28 | !.yarn/versions 29 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /dev/check-connection.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | import { createSequelize6Instance } from './create-sequelize-instance'; 4 | 5 | const sequelize = createSequelize6Instance(); 6 | 7 | (async () => { 8 | await sequelize.authenticate(); 9 | await sequelize.close(); 10 | })(); 11 | -------------------------------------------------------------------------------- /dev/ci-db-configs.ts: -------------------------------------------------------------------------------- 1 | const { env } = process; 2 | 3 | export const CiDbConfigs = { 4 | mssql: { 5 | host: env.SEQ_MSSQL_HOST || env.SEQ_HOST || 'localhost', 6 | username: env.SEQ_MSSQL_USER || env.SEQ_USER || 'SA', 7 | password: env.SEQ_MSSQL_PW || env.SEQ_PW || 'Password12!', 8 | port: env.SEQ_MSSQL_PORT || env.SEQ_PORT || 22_019, 9 | database: env.SEQ_MSSQL_DB || env.SEQ_DB || 'sequelize_test', 10 | dialectOptions: { 11 | options: { 12 | encrypt: false, 13 | requestTimeout: 25_000, 14 | }, 15 | }, 16 | pool: { 17 | max: Number(env.SEQ_MSSQL_POOL_MAX || env.SEQ_POOL_MAX || 5), 18 | idle: Number(env.SEQ_MSSQL_POOL_IDLE || env.SEQ_POOL_IDLE || 3000), 19 | }, 20 | }, 21 | 22 | mysql: { 23 | database: env.SEQ_MYSQL_DB || env.SEQ_DB || 'sequelize_test', 24 | username: env.SEQ_MYSQL_USER || env.SEQ_USER || 'sequelize_test', 25 | password: env.SEQ_MYSQL_PW || env.SEQ_PW || 'sequelize_test', 26 | host: env.MYSQL_PORT_3306_TCP_ADDR || env.SEQ_MYSQL_HOST || env.SEQ_HOST || '127.0.0.1', 27 | port: env.MYSQL_PORT_3306_TCP_PORT || env.SEQ_MYSQL_PORT || env.SEQ_PORT || 20_057, 28 | pool: { 29 | max: Number(env.SEQ_MYSQL_POOL_MAX || env.SEQ_POOL_MAX || 5), 30 | idle: Number(env.SEQ_MYSQL_POOL_IDLE || env.SEQ_POOL_IDLE || 3000), 31 | }, 32 | }, 33 | 34 | snowflake: { 35 | username: env.SEQ_SNOWFLAKE_USER || env.SEQ_USER || 'root', 36 | password: env.SEQ_SNOWFLAKE_PW || env.SEQ_PW || '', 37 | database: env.SEQ_SNOWFLAKE_DB || env.SEQ_DB || 'sequelize_test', 38 | dialectOptions: { 39 | account: env.SEQ_SNOWFLAKE_ACCOUNT || env.SEQ_ACCOUNT || 'sequelize_test', 40 | role: env.SEQ_SNOWFLAKE_ROLE || env.SEQ_ROLE || 'role', 41 | warehouse: env.SEQ_SNOWFLAKE_WH || env.SEQ_WH || 'warehouse', 42 | schema: env.SEQ_SNOWFLAKE_SCHEMA || env.SEQ_SCHEMA || '', 43 | }, 44 | }, 45 | 46 | mariadb: { 47 | database: env.SEQ_MARIADB_DB || env.SEQ_DB || 'sequelize_test', 48 | username: env.SEQ_MARIADB_USER || env.SEQ_USER || 'sequelize_test', 49 | password: env.SEQ_MARIADB_PW || env.SEQ_PW || 'sequelize_test', 50 | host: env.MARIADB_PORT_3306_TCP_ADDR || env.SEQ_MARIADB_HOST || env.SEQ_HOST || '127.0.0.1', 51 | port: env.MARIADB_PORT_3306_TCP_PORT || env.SEQ_MARIADB_PORT || env.SEQ_PORT || 21_103, 52 | pool: { 53 | max: Number(env.SEQ_MARIADB_POOL_MAX || env.SEQ_POOL_MAX || 5), 54 | idle: Number(env.SEQ_MARIADB_POOL_IDLE || env.SEQ_POOL_IDLE || 3000), 55 | }, 56 | }, 57 | 58 | sqlite: {}, 59 | 60 | postgres: { 61 | database: env.SEQ_PG_DB || env.SEQ_DB || 'sequelize_test', 62 | username: env.SEQ_PG_USER || env.SEQ_USER || 'sequelize_test', 63 | password: env.SEQ_PG_PW || env.SEQ_PW || 'sequelize_test', 64 | host: env.POSTGRES_PORT_5432_TCP_ADDR || env.SEQ_PG_HOST || env.SEQ_HOST || '127.0.0.1', 65 | port: env.POSTGRES_PORT_5432_TCP_PORT || env.SEQ_PG_PORT || env.SEQ_PORT || 23_010, 66 | pool: { 67 | max: Number(env.SEQ_PG_POOL_MAX || env.SEQ_POOL_MAX || 5), 68 | idle: Number(env.SEQ_PG_POOL_IDLE || env.SEQ_POOL_IDLE || 3000), 69 | }, 70 | minifyAliases: Boolean(env.SEQ_PG_MINIFY_ALIASES), 71 | }, 72 | }; 73 | -------------------------------------------------------------------------------- /dev/create-sequelize-instance.ts: -------------------------------------------------------------------------------- 1 | import type { Options as Sequelize6Options } from 'sequelize'; 2 | import { Sequelize as Sequelize6 } from 'sequelize'; 3 | import type { Options as Sequelize7Options, Sequelize as Sequelize7 } from '@sequelize/core'; 4 | import { wrapOptions } from './wrap-options'; 5 | 6 | export function createSequelize6Instance(options?: Sequelize6Options): Sequelize6 { 7 | return new Sequelize6(wrapOptions(options)); 8 | } 9 | 10 | export function createSequelize7Instance(options?: Sequelize7Options): Sequelize7 { 11 | // not compatible with node 10 12 | const { Sequelize: Sequelize7Constructor } = require('@sequelize/core'); 13 | // @ts-expect-error -- wrapOptions expect sequelize 6. 14 | return new Sequelize7Constructor(wrapOptions(options)); 15 | } 16 | -------------------------------------------------------------------------------- /dev/global-adjusts.ts: -------------------------------------------------------------------------------- 1 | import chai from 'chai'; 2 | import chaiAsPromised from 'chai-as-promised'; 3 | import chaiDatetime from 'chai-datetime'; 4 | import sinonChai from 'sinon-chai'; 5 | 6 | // Enable same settings to chai from Sequelize main repo 7 | chai.use(chaiDatetime); 8 | chai.use(chaiAsPromised); 9 | chai.use(sinonChai); 10 | chai.config.includeStack = true; 11 | chai.should(); 12 | 13 | process.on('uncaughtException', e => { 14 | console.error('An unhandled exception occurred:'); 15 | console.error(e); 16 | 17 | process.exit(1); 18 | }); 19 | 20 | process.on('unhandledRejection', e => { 21 | console.error('An unhandled rejection occurred:'); 22 | console.error(e); 23 | 24 | process.exit(1); 25 | }); 26 | -------------------------------------------------------------------------------- /dev/lib-replacements.ts: -------------------------------------------------------------------------------- 1 | import './global-adjusts.js'; 2 | import { relative } from 'path'; 3 | import Jetpack from 'fs-jetpack'; 4 | import { logBlue, logGreen, logYellow } from './logging.js'; 5 | 6 | const jetpack = Jetpack.cwd(__dirname); 7 | const replacementsSourcePath = './../src/lib-replacements'; 8 | const replacementsTargetPath = './../node_modules/sequelize/lib'; 9 | const replacementsTargetBackupPath = './../node_modules/sequelize/sequelize-sscce-lib-backup'; 10 | 11 | async function ensureLibBackup() { 12 | if (await jetpack.existsAsync(replacementsTargetBackupPath) === 'dir') { 13 | return; 14 | } 15 | 16 | await jetpack.copyAsync(replacementsTargetPath, replacementsTargetBackupPath); 17 | } 18 | 19 | async function undoReplacements() { 20 | if (await jetpack.existsAsync(replacementsTargetBackupPath) !== 'dir') { 21 | logYellow('No replacements to be undone.'); 22 | 23 | return; 24 | } 25 | 26 | logBlue('Undoing replacements...'); 27 | await jetpack.removeAsync(replacementsTargetPath); 28 | await jetpack.moveAsync(replacementsTargetBackupPath, replacementsTargetPath); 29 | logGreen('Success!'); 30 | } 31 | 32 | async function doReplacements() { 33 | const result = await jetpack.listAsync(replacementsSourcePath); 34 | const isEmpty = result == null || result.length === 0; 35 | if (isEmpty) { 36 | logYellow('No source code replacements to apply.'); 37 | 38 | return; 39 | } 40 | 41 | logBlue(`Doing replacements...`); 42 | await ensureLibBackup(); 43 | await jetpack.copyAsync(replacementsSourcePath, replacementsTargetPath, { 44 | overwrite(sourceInspectData/* , destinationInspectData */) { 45 | const path = relative( 46 | jetpack.path(replacementsSourcePath), 47 | sourceInspectData.absolutePath!, 48 | ); 49 | logBlue(` - Overwriting "${path}"`); 50 | 51 | return true; 52 | }, 53 | }); 54 | logGreen('Success!'); 55 | } 56 | 57 | async function run() { 58 | if (process.argv[2] === '--do') { 59 | await doReplacements(); 60 | } else if (process.argv[2] === '--undo') { 61 | await undoReplacements(); 62 | } else { 63 | throw new Error('Invalid call to dev/lib-replacements.js'); 64 | } 65 | } 66 | 67 | void run(); 68 | -------------------------------------------------------------------------------- /dev/logging.ts: -------------------------------------------------------------------------------- 1 | import isPlainObject from 'lodash/isPlainObject.js'; 2 | import type { Chalk } from 'chalk'; 3 | import chalk from 'chalk'; 4 | import type { Options } from 'sequelize'; 5 | 6 | function isOptionsObject(arg: any): arg is Options { 7 | return arg && isPlainObject(arg) && Object.prototype.hasOwnProperty.call(arg, 'logging'); 8 | } 9 | 10 | export function log(...args: any[]): void { 11 | args = args.filter(x => x !== undefined); 12 | if (args.length === 0) { 13 | return; 14 | } 15 | 16 | if (isOptionsObject(args[args.length - 1])) { 17 | args.pop(); 18 | } 19 | 20 | args[0] = chalk.gray(args[0]); 21 | if (args.length === 2) { 22 | // If benchmarking option is enabled, the logging will have a 23 | // second argument last argument which is the elapsed time 24 | args[1] = chalk.blue(`[Elapsed time: ${args[1]} ms]`); 25 | } 26 | 27 | console.log('[Sequelize]', ...args, '\n'); 28 | } 29 | 30 | export function logRed(...args: any[]): void { 31 | return logColor(chalk.red, ...args); 32 | } 33 | 34 | export function logBlue(...args: any[]): void { 35 | return logColor(chalk.blue, ...args); 36 | } 37 | 38 | export function logGreen(...args: any[]): void { 39 | return logColor(chalk.green, ...args); 40 | } 41 | 42 | export function logYellow(...args: any[]): void { 43 | return logColor(chalk.yellow, ...args); 44 | } 45 | 46 | function logColor(color: Chalk, ...args: any[]) { 47 | return console.log(...args.map(arg => { 48 | if (typeof arg !== 'string') { 49 | return arg; 50 | } 51 | 52 | return color(arg); 53 | })); 54 | } 55 | -------------------------------------------------------------------------------- /dev/mariadb/latest/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | mariadb-latest: 3 | container_name: sequelize-mariadb-latest 4 | image: mariadb:11.2.2 5 | environment: 6 | MYSQL_DATABASE: sequelize_test 7 | MYSQL_USER: sequelize_test 8 | MYSQL_PASSWORD: sequelize_test 9 | MYSQL_ROOT_PASSWORD: sequelize_test 10 | ports: 11 | - 21103:3306 12 | volumes: 13 | - mariadb-latest:/var/lib/mysql 14 | healthcheck: 15 | test: ["CMD", "mariadb-admin", "-usequelize_test", "-psequelize_test", "status"] 16 | interval: 3s 17 | timeout: 1s 18 | retries: 10 19 | 20 | networks: 21 | default: 22 | name: sequelize-mariadb-latest-network 23 | 24 | volumes: 25 | mariadb-latest: 26 | name: sequelize-mariadb-latest-volume 27 | -------------------------------------------------------------------------------- /dev/mariadb/latest/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mariadb-latest down --remove-orphans --volumes 6 | -------------------------------------------------------------------------------- /dev/mariadb/latest/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mariadb-latest down --remove-orphans 6 | docker compose -p sequelize-mariadb-latest up -d 7 | 8 | ./../../wait-until-healthy.sh sequelize-mariadb-latest 9 | 10 | docker exec sequelize-mariadb-latest \ 11 | mariadb --host 127.0.0.1 --port 3306 -uroot -psequelize_test -e "GRANT ALL ON *.* TO 'sequelize_test'@'%' with grant option; FLUSH PRIVILEGES;" 12 | 13 | DIALECT=mariadb ts-node ../../check-connection.ts 14 | -------------------------------------------------------------------------------- /dev/mariadb/latest/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mariadb-latest down --remove-orphans 6 | 7 | echo "Local latest supported MariaDB instance stopped (if it was running)." 8 | -------------------------------------------------------------------------------- /dev/mariadb/oldest/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | mariadb-oldest: 3 | container_name: sequelize-mariadb-oldest 4 | image: mariadb:10.4.30 5 | environment: 6 | MYSQL_DATABASE: sequelize_test 7 | MYSQL_USER: sequelize_test 8 | MYSQL_PASSWORD: sequelize_test 9 | MYSQL_ROOT_PASSWORD: sequelize_test 10 | ports: 11 | - 21103:3306 12 | volumes: 13 | - mariadb-oldest:/var/lib/mysql 14 | healthcheck: 15 | test: ["CMD", "mariadb-admin", "-usequelize_test", "-psequelize_test", "status"] 16 | interval: 3s 17 | timeout: 1s 18 | retries: 10 19 | 20 | networks: 21 | default: 22 | name: sequelize-mariadb-oldest-network 23 | 24 | volumes: 25 | mariadb-oldest: 26 | name: sequelize-mariadb-oldest-volume 27 | -------------------------------------------------------------------------------- /dev/mariadb/oldest/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mariadb-oldest down --remove-orphans --volumes 6 | -------------------------------------------------------------------------------- /dev/mariadb/oldest/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mariadb-oldest down --remove-orphans 6 | docker compose -p sequelize-mariadb-oldest up -d 7 | 8 | ./../../wait-until-healthy.sh sequelize-mariadb-oldest 9 | 10 | docker exec sequelize-mariadb-oldest \ 11 | mariadb --host 127.0.0.1 --port 3306 -uroot -psequelize_test -e "GRANT ALL ON *.* TO 'sequelize_test'@'%' with grant option; FLUSH PRIVILEGES;" 12 | 13 | DIALECT=mariadb ts-node ../../check-connection.ts 14 | -------------------------------------------------------------------------------- /dev/mariadb/oldest/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mariadb-oldest down --remove-orphans 6 | 7 | echo "Local oldest supported MariaDB instance stopped (if it was running)." 8 | -------------------------------------------------------------------------------- /dev/mssql/latest/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | mssql-latest: 3 | container_name: sequelize-mssql-latest 4 | image: mcr.microsoft.com/mssql/server:2022-latest 5 | environment: 6 | ACCEPT_EULA: Y 7 | MSSQL_PID: Developer 8 | MSSQL_SA_PASSWORD: Password12! 9 | ports: 10 | - 22019:1433 11 | volumes: 12 | - mssql-latest:/var/opt/mssql 13 | healthcheck: 14 | test: ["CMD", "/opt/mssql-tools/bin/sqlcmd", "-S", "localhost", "-U", "SA", "-P", "Password12!", "-l", "30", "-Q", "SELECT 1"] 15 | interval: 3s 16 | timeout: 1s 17 | retries: 10 18 | 19 | networks: 20 | default: 21 | name: sequelize-mssql-latest-network 22 | 23 | volumes: 24 | mssql-latest: 25 | name: sequelize-mssql-latest-volume 26 | -------------------------------------------------------------------------------- /dev/mssql/latest/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mssql-latest down --remove-orphans --volumes 6 | -------------------------------------------------------------------------------- /dev/mssql/latest/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mssql-latest down --remove-orphans 6 | docker compose -p sequelize-mssql-latest up -d 7 | 8 | ./../../wait-until-healthy.sh sequelize-mssql-latest 9 | 10 | docker exec sequelize-mssql-latest \ 11 | /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "Password12!" -Q "CREATE DATABASE sequelize_test; ALTER DATABASE sequelize_test SET READ_COMMITTED_SNAPSHOT ON;" 12 | 13 | DIALECT=mssql ts-node ../../check-connection.ts 14 | -------------------------------------------------------------------------------- /dev/mssql/latest/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mssql-latest down --remove-orphans 6 | 7 | echo "Local latest supported MSSQL instance stopped (if it was running)." 8 | -------------------------------------------------------------------------------- /dev/mssql/oldest/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | mssql-oldest: 3 | container_name: sequelize-mssql-oldest 4 | image: mcr.microsoft.com/mssql/server:2017-latest 5 | environment: 6 | ACCEPT_EULA: Y 7 | MSSQL_PID: Developer 8 | MSSQL_SA_PASSWORD: Password12! 9 | ports: 10 | - 22019:1433 11 | volumes: 12 | - mssql-oldest:/var/opt/mssql 13 | healthcheck: 14 | test: ["CMD", "/opt/mssql-tools/bin/sqlcmd", "-S", "localhost", "-U", "SA", "-P", "Password12!", "-l", "30", "-Q", "SELECT 1"] 15 | interval: 3s 16 | timeout: 1s 17 | retries: 10 18 | 19 | networks: 20 | default: 21 | name: sequelize-mssql-oldest-network 22 | 23 | volumes: 24 | mssql-oldest: 25 | name: sequelize-mssql-oldest-volume 26 | -------------------------------------------------------------------------------- /dev/mssql/oldest/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mssql-oldest down --remove-orphans --volumes 6 | -------------------------------------------------------------------------------- /dev/mssql/oldest/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mssql-oldest down --remove-orphans 6 | docker compose -p sequelize-mssql-oldest up -d 7 | 8 | ./../../wait-until-healthy.sh sequelize-mssql-oldest 9 | 10 | docker exec sequelize-mssql-oldest \ 11 | /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "Password12!" -Q "CREATE DATABASE sequelize_test; ALTER DATABASE sequelize_test SET READ_COMMITTED_SNAPSHOT ON;" 12 | 13 | DIALECT=mssql ts-node ../../check-connection.ts 14 | -------------------------------------------------------------------------------- /dev/mssql/oldest/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mssql-oldest down --remove-orphans 6 | 7 | echo "Local oldest supported MSSQL instance stopped (if it was running)." 8 | -------------------------------------------------------------------------------- /dev/mysql/latest/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | mysql-latest: 3 | container_name: sequelize-mysql-latest 4 | image: mysql:8.3.0 5 | environment: 6 | MYSQL_DATABASE: sequelize_test 7 | MYSQL_USER: sequelize_test 8 | MYSQL_PASSWORD: sequelize_test 9 | MYSQL_ROOT_PASSWORD: sequelize_test 10 | ports: 11 | - 20057:3306 12 | volumes: 13 | - mysql-latest:/var/lib/mysql 14 | healthcheck: 15 | test: ["CMD", "mysqladmin", "-usequelize_test", "-psequelize_test", "status"] 16 | interval: 3s 17 | timeout: 1s 18 | retries: 10 19 | 20 | networks: 21 | default: 22 | name: sequelize-mysql-latest-network 23 | 24 | volumes: 25 | mysql-latest: 26 | name: sequelize-mysql-latest-volume 27 | -------------------------------------------------------------------------------- /dev/mysql/latest/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mysql-latest down --remove-orphans --volumes 6 | -------------------------------------------------------------------------------- /dev/mysql/latest/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mysql-latest down --remove-orphans 6 | docker compose -p sequelize-mysql-latest up -d 7 | 8 | ./../../wait-until-healthy.sh sequelize-mysql-latest 9 | 10 | sleep 5s 11 | 12 | docker exec sequelize-mysql-latest \ 13 | mysql --host 127.0.0.1 --port 3306 -uroot -psequelize_test -e "GRANT ALL ON *.* TO 'sequelize_test'@'%' with grant option; FLUSH PRIVILEGES;" 14 | 15 | DIALECT=mysql ts-node ../../check-connection.ts 16 | -------------------------------------------------------------------------------- /dev/mysql/latest/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mysql-latest down --remove-orphans 6 | 7 | echo "Local latest supported MySQL instance stopped (if it was running)." 8 | -------------------------------------------------------------------------------- /dev/mysql/oldest/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | mysql-oldest: 3 | container_name: sequelize-mysql-oldest 4 | image: mysql:8.0.19 5 | environment: 6 | MYSQL_DATABASE: sequelize_test 7 | MYSQL_USER: sequelize_test 8 | MYSQL_PASSWORD: sequelize_test 9 | MYSQL_ROOT_PASSWORD: sequelize_test 10 | ports: 11 | - 20057:3306 12 | volumes: 13 | - mysql-oldest:/var/lib/mysql 14 | healthcheck: 15 | test: ["CMD", "mysqladmin", "-usequelize_test", "-psequelize_test", "status"] 16 | interval: 3s 17 | timeout: 1s 18 | retries: 10 19 | 20 | networks: 21 | default: 22 | name: sequelize-mysql-oldest-network 23 | 24 | volumes: 25 | mysql-oldest: 26 | name: sequelize-mysql-oldest-volume 27 | -------------------------------------------------------------------------------- /dev/mysql/oldest/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mysql-oldest down --remove-orphans --volumes 6 | -------------------------------------------------------------------------------- /dev/mysql/oldest/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mysql-oldest down --remove-orphans 6 | docker compose -p sequelize-mysql-oldest up -d 7 | 8 | ./../../wait-until-healthy.sh sequelize-mysql-oldest 9 | 10 | docker exec sequelize-mysql-oldest \ 11 | mysql --host 127.0.0.1 --port 3306 -uroot -psequelize_test -e "GRANT ALL ON *.* TO 'sequelize_test'@'%' with grant option; FLUSH PRIVILEGES;" 12 | 13 | DIALECT=mysql ts-node ../../check-connection.ts 14 | -------------------------------------------------------------------------------- /dev/mysql/oldest/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-mysql-oldest down --remove-orphans 6 | 7 | echo "Local oldest supported MySQL instance stopped (if it was running)." 8 | -------------------------------------------------------------------------------- /dev/postgres/latest/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | postgres-latest: 3 | container_name: sequelize-postgres-latest 4 | image: postgis/postgis:15-3.3 5 | environment: 6 | POSTGRES_USER: sequelize_test 7 | POSTGRES_PASSWORD: sequelize_test 8 | POSTGRES_DB: sequelize_test 9 | ports: 10 | - 23010:5432 11 | volumes: 12 | - postgres-latest:/var/lib/postgresql/data 13 | healthcheck: 14 | test: ["CMD", "pg_isready", "-U", "sequelize_test"] 15 | interval: 3s 16 | timeout: 1s 17 | retries: 10 18 | 19 | networks: 20 | default: 21 | name: sequelize-postgres-latest-network 22 | 23 | volumes: 24 | postgres-latest: 25 | name: sequelize-postgres-latest-volume 26 | -------------------------------------------------------------------------------- /dev/postgres/latest/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-postgres-latest down --remove-orphans --volumes 6 | -------------------------------------------------------------------------------- /dev/postgres/latest/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-postgres-latest down --remove-orphans 6 | docker compose -p sequelize-postgres-latest up -d 7 | 8 | ./../../wait-until-healthy.sh sequelize-postgres-latest 9 | 10 | DIALECT=postgres ts-node ../../check-connection.ts 11 | 12 | docker exec sequelize-postgres-latest \ 13 | bash -c "export PGPASSWORD=sequelize_test && psql -h localhost -p 5432 -U sequelize_test sequelize_test -c 'CREATE EXTENSION IF NOT EXISTS btree_gist; CREATE EXTENSION IF NOT EXISTS hstore; CREATE EXTENSION IF NOT EXISTS citext;'" 14 | -------------------------------------------------------------------------------- /dev/postgres/latest/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-postgres-latest down --remove-orphans 6 | 7 | echo "Local latest supported Postgres instance with postgis stopped (if it was running)." 8 | -------------------------------------------------------------------------------- /dev/postgres/oldest/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | postgres-oldest: 3 | container_name: sequelize-postgres-oldest 4 | image: postgis/postgis:11-2.5 5 | environment: 6 | POSTGRES_USER: sequelize_test 7 | POSTGRES_PASSWORD: sequelize_test 8 | POSTGRES_DB: sequelize_test 9 | ports: 10 | - 23010:5432 11 | volumes: 12 | - postgres-oldest:/var/lib/postgresql/data 13 | healthcheck: 14 | test: ["CMD", "pg_isready", "-U", "sequelize_test"] 15 | interval: 3s 16 | timeout: 1s 17 | retries: 10 18 | 19 | networks: 20 | default: 21 | name: sequelize-postgres-oldest-network 22 | 23 | volumes: 24 | postgres-oldest: 25 | name: sequelize-postgres-oldest-volume 26 | -------------------------------------------------------------------------------- /dev/postgres/oldest/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-postgres-oldest down --remove-orphans --volumes 6 | -------------------------------------------------------------------------------- /dev/postgres/oldest/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-postgres-oldest down --remove-orphans 6 | docker compose -p sequelize-postgres-oldest up -d 7 | 8 | ./../../wait-until-healthy.sh sequelize-postgres-oldest 9 | 10 | DIALECT=postgres ts-node ../../check-connection.ts 11 | 12 | docker exec sequelize-postgres-oldest \ 13 | bash -c "export PGPASSWORD=sequelize_test && psql -h localhost -p 5432 -U sequelize_test sequelize_test -c 'CREATE EXTENSION IF NOT EXISTS btree_gist; CREATE EXTENSION IF NOT EXISTS hstore; CREATE EXTENSION IF NOT EXISTS citext;'" 14 | -------------------------------------------------------------------------------- /dev/postgres/oldest/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuxo pipefail # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 3 | cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # https://stackoverflow.com/a/17744637 4 | 5 | docker compose -p sequelize-postgres-oldest down --remove-orphans 6 | 7 | echo "Local oldest supported Postgres instance with postgis stopped (if it was running)." 8 | -------------------------------------------------------------------------------- /dev/prepare-ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -c 2 | 3 | yarn install --ignore-engines; 4 | 5 | if [ "$DIALECT" = "postgres" ]; then 6 | yarn add pg@^8 pg-hstore@^2 pg-types@^2 --ignore-engines; 7 | elif [ "$DIALECT" = "postgres-native" ]; then 8 | yarn add pg@^8 pg-hstore@^2 pg-types@^2 pg-native --ignore-engines; 9 | elif [ "$DIALECT" = "mysql" ]; then 10 | yarn add mysql2@^2 --ignore-engines; 11 | elif [ "$DIALECT" = "mariadb" ]; then 12 | yarn add mariadb@^2 --ignore-engines; 13 | elif [ "$DIALECT" = "sqlite" ]; then 14 | yarn add sqlite3@^5 --ignore-engines; 15 | elif [ "$DIALECT" = "mssql" ]; then 16 | yarn add tedious@^8 --ignore-engines; 17 | fi 18 | -------------------------------------------------------------------------------- /dev/runner.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // @ts-expect-error - it's fine for this to be "any" 4 | import versions from './sequelize-version.cjs'; 5 | import './global-adjusts'; 6 | import assert from 'assert'; 7 | import { existsSync } from 'fs'; 8 | import { logBlue, logGreen, logRed } from './logging'; 9 | 10 | const majorNodeVersion = Number.parseInt(process.version.slice(1), 10); 11 | 12 | async function wrappedRun() { 13 | const dialect = process.env.DIALECT; 14 | assert(dialect, 'Must provide DIALECT environment variable. Use one of the `test:` npm scripts available. (e.g. `npm run test:sqlite`)'); 15 | 16 | let failed = false; 17 | 18 | if (existsSync(`${__dirname}/../src/sscce-sequelize-6.ts`)) { 19 | let heading = `Running SSCCE for ${dialect.toUpperCase()} with Sequelize ${versions.sequelize6}`; 20 | heading = `===== ${heading} =====`; 21 | 22 | logBlue(`\n${'-'.repeat(heading.length)}`); 23 | logBlue(heading); 24 | logBlue(`${'-'.repeat(heading.length)}\n`); 25 | 26 | const { run, testingOnDialects } = require('../src/sscce-sequelize-6'); 27 | if (!testingOnDialects.has(process.env.DIALECT!)) { 28 | logRed(`Skipping dialect ${process.env.DIALECT} as it has been omitted from 'testingOnDialects'`); 29 | 30 | return; 31 | } 32 | 33 | try { 34 | await run(); 35 | } catch (error) { 36 | logRed('Sequelize 6 test failed'); 37 | logRed(error); 38 | failed = true; 39 | } 40 | } 41 | 42 | if (existsSync(`${__dirname}/../src/sscce-sequelize-7.ts`)) { 43 | let heading = `Running SSCCE for ${dialect.toUpperCase()} with Sequelize ${versions.sequelize7}`; 44 | heading = `===== ${heading} =====`; 45 | 46 | logBlue(`\n${'-'.repeat(heading.length)}`); 47 | logBlue(heading); 48 | logBlue(`${'-'.repeat(heading.length)}\n`); 49 | 50 | if (majorNodeVersion >= 18) { 51 | const { run, testingOnDialects } = require('../src/sscce-sequelize-7'); 52 | if (!testingOnDialects.has(process.env.DIALECT!)) { 53 | logRed(`Skipping dialect ${process.env.DIALECT} as it has been omitted from 'testingOnDialects'`); 54 | 55 | return; 56 | } 57 | 58 | try { 59 | await run(); 60 | } catch (error) { 61 | logRed('Sequelize 7 test failed'); 62 | logRed(error); 63 | failed = true; 64 | } 65 | } else { 66 | logRed(`Current node version ${process.version} is insufficient for Sequelize 7, skipping this test`); 67 | } 68 | } 69 | 70 | if (failed) { 71 | console.log(`\n${'-'.repeat(40)}\n`); 72 | logRed('SSCCE done with error (see above).'); 73 | process.exit(1); 74 | } 75 | 76 | console.log(`\n${'-'.repeat(40)}\n`); 77 | logGreen('SSCCE done without errors!'); 78 | } 79 | 80 | (async () => { 81 | await wrappedRun(); 82 | })(); 83 | -------------------------------------------------------------------------------- /dev/sequelize-version.cjs: -------------------------------------------------------------------------------- 1 | // this file is a .cjs file because ESM can't import JSON quite yet 2 | module.exports = { 3 | sequelize6: require('sequelize/package.json').version.replace(/^v?/, 'v'), 4 | sequelize7: require('@sequelize/core/package.json').version.replace(/^v?/, 'v'), 5 | }; 6 | -------------------------------------------------------------------------------- /dev/ts-setup.ts: -------------------------------------------------------------------------------- 1 | import './global-adjusts.js'; 2 | 3 | import { cwd } from 'fs-jetpack'; 4 | import path from 'path'; 5 | import url from 'url'; 6 | 7 | const jetpack = cwd(path.dirname(url.fileURLToPath(import.meta.url))); 8 | jetpack.copy('./../src/utils', './../ts-dist/utils'); 9 | -------------------------------------------------------------------------------- /dev/wait-until-healthy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ "$#" -ne 1 ]; then 4 | >&2 echo "Please provide the container name or hash" 5 | exit 1 6 | fi 7 | 8 | for _ in {1..50} 9 | do 10 | state=$(docker inspect -f '{{ .State.Health.Status }}' $1 2>&1) 11 | return_code=$? 12 | if [ ${return_code} -eq 0 ] && [ "$state" == "healthy" ]; then 13 | echo "$1 is healthy!" 14 | exit 0 15 | fi 16 | sleep 0.4 17 | done 18 | 19 | >&2 echo "Timeout of 20s exceeded when waiting for container to be healthy: $1" 20 | exit 1 21 | -------------------------------------------------------------------------------- /dev/wrap-options.ts: -------------------------------------------------------------------------------- 1 | import defaults from 'lodash/defaults.js'; 2 | import { CiDbConfigs } from './ci-db-configs'; 3 | import { log } from './logging'; 4 | import type { Dialect, Options } from 'sequelize'; 5 | 6 | export function wrapOptions(options: Options = {}) { 7 | if (!process.env.DIALECT) { 8 | throw new Error('Dialect is not defined! Aborting.'); 9 | } 10 | 11 | const isPostgresNative = process.env.DIALECT === 'postgres-native'; 12 | const dialect = (isPostgresNative ? 'postgres' : process.env.DIALECT) as Dialect; 13 | 14 | // this fails in the CI due to mismatch between Sequelize 6 & 7. Should be resolved once we drop Sequelize 6. 15 | // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error 16 | // @ts-ignore 17 | const config = CiDbConfigs[dialect]; 18 | 19 | options.dialect = dialect; 20 | if (isPostgresNative) { 21 | options.native = true; 22 | } 23 | 24 | defaults(options, { 25 | logging: log, 26 | ...config, 27 | }); 28 | 29 | // @ts-expect-error 30 | options.__isOptionsObject__ = true; 31 | 32 | return options; 33 | } 34 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Pedro Augusto de Paula Barbosa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "engines": { 4 | "node": ">=10.0.0" 5 | }, 6 | "type": "commonjs", 7 | "license": "MIT", 8 | "dependencies": { 9 | "chai": "^4", 10 | "chai-as-promised": "^7", 11 | "chai-datetime": "^1", 12 | "chalk": "^4.1.2", 13 | "cross-env": "^7", 14 | "fs-jetpack": "^4", 15 | "sequelize": "^6", 16 | "@sequelize/core": "alpha", 17 | "sinon": "^13", 18 | "sinon-chai": "^3" 19 | }, 20 | "scripts": { 21 | "_test": "ts-node dev/runner.ts", 22 | "test:sqlite": "cross-env DIALECT=sqlite yarn run _test", 23 | "test:postgres": "cross-env DIALECT=postgres yarn run _test", 24 | "test:postgres-native": "cross-env DIALECT=postgres-native yarn run _test", 25 | "test:mariadb": "cross-env DIALECT=mariadb yarn run _test", 26 | "test:mysql": "cross-env DIALECT=mysql yarn run _test", 27 | "test:mssql": "cross-env DIALECT=mssql yarn run _test", 28 | "------------------------------------- local test dbs --------------------------------------": "", 29 | "reset-mariadb": "bash dev/mariadb/oldest/reset.sh; bash dev/mariadb/latest/reset.sh", 30 | "reset-mysql": "bash dev/mysql/oldest/reset.sh; bash dev/mysql/latest/reset.sh", 31 | "reset-postgres": "bash dev/postgres/oldest/reset.sh; bash dev/postgres/latest/reset.sh", 32 | "reset-mssql": "bash dev/mssql/oldest/reset.sh; bash dev/mssql/latest/reset.sh", 33 | "reset-all": "concurrently \"npm:reset-*(!all)\"", 34 | "start-mariadb-oldest": "bash dev/mariadb/oldest/start.sh", 35 | "start-mariadb-latest": "bash dev/mariadb/latest/start.sh", 36 | "start-mysql-oldest": "bash dev/mysql/oldest/start.sh", 37 | "start-mysql-latest": "bash dev/mysql/latest/start.sh", 38 | "start-postgres-oldest": "bash dev/postgres/oldest/start.sh", 39 | "start-postgres-latest": "bash dev/postgres/latest/start.sh", 40 | "start-mssql-oldest": "bash dev/mssql/oldest/start.sh", 41 | "start-mssql-latest": "bash dev/mssql/latest/start.sh", 42 | "start-oldest": "concurrently \"npm:start-*-oldest\"", 43 | "start-latest": "concurrently \"npm:start-*-latest\"", 44 | "stop-mariadb": "bash dev/mariadb/oldest/stop.sh; bash dev/mariadb/latest/stop.sh", 45 | "stop-mysql": "bash dev/mysql/oldest/stop.sh; bash dev/mysql/latest/stop.sh", 46 | "stop-postgres": "bash dev/postgres/oldest/stop.sh; bash dev/postgres/latest/stop.sh", 47 | "stop-mssql": "bash dev/mssql/oldest/stop.sh; bash dev/mssql/latest/stop.sh", 48 | "stop-all": "concurrently \"npm:stop-*(!all)\"", 49 | "do-replace": "node dev/lib-replacements.ts --do", 50 | "undo-replace": "node dev/lib-replacements.ts --undo", 51 | "lint": "eslint . --fix" 52 | }, 53 | "devDependencies": { 54 | "@ephys/eslint-config-typescript": "^14.1.1", 55 | "@types/chai": "^4", 56 | "@types/chai-as-promised": "^7", 57 | "@types/chai-datetime": "^0.0.37", 58 | "@types/lodash": "^4.14.178", 59 | "@types/node": "^10", 60 | "@types/sinon": "^10", 61 | "@types/sinon-chai": "^3", 62 | "@types/validator": "*", 63 | "concurrently": "^8", 64 | "del-cli": "^4", 65 | "eslint": "^8", 66 | "lodash": "^4.17.21", 67 | "sqlite3": "^5", 68 | "ts-node": "^10.4.0", 69 | "typescript": "~4.5" 70 | }, 71 | "resolutions": { 72 | "chai-datetime/chai": "^4" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Sequelize Quick SSCCE Base Repository 2 | 3 | Use this repository to create an [SSCCE](http://www.sscce.org/) for your issue! It will greatly help us figure out what is going wrong and your issue 4 | will be much easier to investigate. 5 | 6 | ## Method 1: Create your SSCCE locally (preferred) 7 | 8 | ### Step 1 - Install this repository locally 9 | 10 | Start by [Forking this repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo), 11 | then [clone it on your machine](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository). 12 | 13 | Run `npm install` or `yarn` to install the necessary dependencies. 14 | 15 | ### Step 1 - Create the SSCCE 16 | 17 | You now need to create a failing test that accurately represents the issue you're experiencing. 18 | 19 | If you want to test against Sequelize 6, modify [src/sscce-sequelize-6.ts](./src/sscce-sequelize-6.ts). 20 | If you want to test against Sequelize 7, modify [src/sscce-sequelize-7.ts](./src/sscce-sequelize-7.ts). 21 | 22 | If you are using a version older than Sequelize 6, unfortunately these versions are now EOL and won't receive support. 23 | You should consider migrating to Sequelize 6. 24 | 25 | Remember the [SSCCE rules](http://www.sscce.org/). It should be: 26 | 27 | - *Short (Small)* - It should not include anything that is not relevant to your issue. 28 | - *Self Contained* - Ensure everything is included, ready to go. 29 | - *Correct* - It should demonstrate the problem you're encountering (i.e. the sscce should fail, but with the right error). 30 | - *Example* - Displays the problem we are trying to solve. 31 | 32 | ### Step 2 - Run the SSCCE 33 | 34 | Use one of our npm scripts to run your SSCCE. 35 | 36 | Running with a dialect other than sqlite will require installing an extra package 37 | & having a database running. For convenience, we provide docker containers for each database. 38 | 39 | You can also opt to open a pull request, and run the code directly in our CI. 40 | 41 | #### sqlite 42 | 43 | The easiest of the bunch. Simply run: 44 | 45 | ```shell 46 | npm run test:sqlite 47 | ``` 48 | 49 | #### postgres 50 | 51 | You'll need to install the `pg` package and have a postgres database running. 52 | 53 | ```shell 54 | # Do this only once. 55 | npm install pg 56 | # or 57 | npm install pg-native 58 | 59 | # if you need to use DataTypes.HSTORE, you also need this dependency 60 | npm install pg-hstore 61 | 62 | # Start the postgres database using docker. 63 | # Requires docker. You can also run your own database if you prefer. 64 | npm run start:postgres 65 | 66 | # run the sscce! 67 | npm run test:postgres 68 | # or 69 | npm run test:postgres-native 70 | 71 | # Remember to stop the docker container once you're done. 72 | npm run stop:postgres 73 | ``` 74 | 75 | #### mariadb 76 | 77 | ```shell 78 | # Do this only once. 79 | npm install mariadb 80 | 81 | # Start the mariadb database using docker. 82 | # Requires docker. You can also run your own database if you prefer. 83 | npm run start:mariadb 84 | 85 | # run the sscce! 86 | npm run test:mariadb 87 | 88 | # Remember to stop the docker container once you're done. 89 | npm run stop:mariadb 90 | ``` 91 | 92 | #### mysql 93 | 94 | ```shell 95 | # Do this only once. 96 | npm install mysql2 97 | 98 | # Start the mysql database using docker. 99 | # Requires docker. You can also run your own database if you prefer. 100 | npm run start:mysql 101 | 102 | # run the sscce! 103 | npm run test:mysql 104 | 105 | # Remember to stop the docker container once you're done. 106 | npm run stop:mysql 107 | ``` 108 | 109 | #### mssql (SQL Server) 110 | 111 | ```shell 112 | # Do this only once. 113 | npm install tedious 114 | 115 | # Start the mssql database using docker. 116 | # Requires docker. You can also run your own database if you prefer. 117 | npm run start:mssql 118 | 119 | # run the sscce! 120 | npm run test:mssql 121 | 122 | # Remember to stop the docker container once you're done. 123 | npm run stop:mssql 124 | ``` 125 | 126 | ### Step 3 - Commit your SSCCE & sent it to us 127 | 128 | Open an issue on the [main sequelize repo](https://github.com/sequelize/sequelize/) describing 129 | your problem and include a link to your SSCCE in it. 130 | 131 | You can also open a PR of your fork to [this repository](https://github.com/sequelize/sequelize-sscce), 132 | this way your SSCCE will be run on our CI and will continue existing even if you delete your fork. 133 | 134 | ## Method 2: Create your SSCCE on GitHub 135 | 136 | By using this method, you won't have to worry about setting up any database. 137 | You don't need to install anything, you don't need docker, you don't need to spend time configuring a development environment to create your SSCCE. 138 | Everything is already set up for you in our GitHub actions. 139 | 140 | **You just write your code and it works, directly from GitHub!** 141 | 142 | ### Step 1 - Create the SSCCE 143 | 144 | If you want to test against Sequelize 6, go to this file: [src/sscce-sequelize-6.ts](./src/sscce-sequelize-6.ts). 145 | If you want to test against Sequelize 7, go to this file: [src/sscce-sequelize-7.ts](./src/sscce-sequelize-7.ts). 146 | 147 | Then click the edit button (a pencil). 148 | 149 | Since this is not your repository, a fork will be automatically created for you to perform your edit. You will see this message: 150 | 151 |
152 | 153 | Just create your SSCCE in that file, and commit it to your fork: 154 | 155 |
156 | 157 | ### Step 2 - Run your SSCCE with GitHub Actions 158 | 159 | This step is **extremely easy**. Now that you have commited your SSCCE to your fork, just open a Pull Request (don't worry, *I won't accept it!*): 160 | 161 |
162 | 163 | The idea here is that once you open the pull request, GitHub Actions will automatically execute it for you, since I have it configured in the main repository. I won't accept the pull request, since the goal is just to have your code executed. 164 | 165 | It will run your SSCCE and show a green checkmark (or a red X) next to the commit: 166 | 167 |
168 | 169 | ## FAQ 170 | 171 | ### What if you want to make some changes to the SSCCE? 172 | 173 | Just add more commits on top of it, in your fork, and your PR will be updated automatically, and the SSCCE will be executed again. 174 | 175 | ### I don't want to open a pull request for this 176 | 177 | You don't have to! If you've opted for method 1, you can just add a link to your forked repository in your issue. 178 | 179 | However, opening a pull request will ensure the SSCCE continues to exist even if you delete your fork. Less clutter in your repository list! 180 | 181 | ### Creating a dialect-specific SSCCE 182 | 183 | By default, your SSCCE will be executed on all dialects. If you only want a specific dialect, 184 | you can remove dialects you don't need to test on from the `testingOnDialects` variable in your `sscce-sequelize-x.ts` file. 185 | 186 | For example, if you only want to run your SSCCE for postgres, change the following line: 187 | 188 | ```typescript 189 | // if your issue is dialect specific, remove the dialects you don't need to test on. 190 | export const testingOnDialects = new Set(['mssql', 'sqlite', 'mysql', 'mariadb', 'postgres', 'postgres-native']); 191 | ``` 192 | 193 | to this: 194 | 195 | ```typescript 196 | // if your issue is dialect specific, remove the dialects you don't need to test on. 197 | export const testingOnDialects = new Set(['postgres']); 198 | ``` 199 | 200 | ### Enabling specific postgres extensions 201 | 202 | If your issue needs a postgres extension such as `uuid-ossp`, you should enable it at the beginning of your SSCCE: 203 | 204 | ```js 205 | export async function run() { 206 | const sequelize = createSequelize6Instance(); 207 | 208 | // add it here, after createSequelizeInstance: 209 | await sequelize.query(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`); 210 | 211 | // The rest of the SSCCE goes here... 212 | } 213 | ``` 214 | 215 | ## License 216 | 217 | MIT (c) Pedro Augusto de Paula Barbosa & The Sequelize Team 218 | -------------------------------------------------------------------------------- /src/sscce-sequelize-6.ts: -------------------------------------------------------------------------------- 1 | import { DataTypes, Model } from 'sequelize'; 2 | import { createSequelize6Instance } from '../dev/create-sequelize-instance'; 3 | import { expect } from 'chai'; 4 | import sinon from 'sinon'; 5 | 6 | // if your issue is dialect specific, remove the dialects you don't need to test on. 7 | export const testingOnDialects = new Set(['mssql', 'sqlite', 'mysql', 'mariadb', 'postgres', 'postgres-native']); 8 | 9 | // You can delete this file if you don't want your SSCCE to be tested against Sequelize 6 10 | 11 | // Your SSCCE goes inside this function. 12 | export async function run() { 13 | // This function should be used instead of `new Sequelize()`. 14 | // It applies the config for your SSCCE to work on CI. 15 | const sequelize = createSequelize6Instance({ 16 | logQueryParameters: true, 17 | benchmark: true, 18 | define: { 19 | // For less clutter in the SSCCE 20 | timestamps: false, 21 | }, 22 | }); 23 | 24 | class Foo extends Model {} 25 | 26 | Foo.init({ 27 | name: DataTypes.TEXT, 28 | }, { 29 | sequelize, 30 | modelName: 'Foo', 31 | }); 32 | 33 | // You can use sinon and chai assertions directly in your SSCCE. 34 | const spy = sinon.spy(); 35 | sequelize.afterBulkSync(() => spy()); 36 | await sequelize.sync({ force: true }); 37 | expect(spy).to.have.been.called; 38 | 39 | console.log(await Foo.create({ name: 'TS foo' })); 40 | expect(await Foo.count()).to.equal(1); 41 | } 42 | -------------------------------------------------------------------------------- /src/sscce-sequelize-7.ts: -------------------------------------------------------------------------------- 1 | import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from '@sequelize/core'; 2 | import { Attribute, NotNull } from '@sequelize/core/decorators-legacy'; 3 | import { createSequelize7Instance } from '../dev/create-sequelize-instance'; 4 | import { expect } from 'chai'; 5 | import sinon from 'sinon'; 6 | 7 | // if your issue is dialect specific, remove the dialects you don't need to test on. 8 | export const testingOnDialects = new Set(['mssql', 'sqlite', 'mysql', 'mariadb', 'postgres', 'postgres-native']); 9 | 10 | // You can delete this file if you don't want your SSCCE to be tested against Sequelize 7 11 | 12 | // Your SSCCE goes inside this function. 13 | export async function run() { 14 | // This function should be used instead of `new Sequelize()`. 15 | // It applies the config for your SSCCE to work on CI. 16 | const sequelize = createSequelize7Instance({ 17 | logQueryParameters: true, 18 | benchmark: true, 19 | define: { 20 | // For less clutter in the SSCCE 21 | timestamps: false, 22 | }, 23 | }); 24 | 25 | class Foo extends Model, InferCreationAttributes> { 26 | declare id: CreationOptional; 27 | 28 | @Attribute(DataTypes.TEXT) 29 | @NotNull 30 | declare name: string; 31 | } 32 | 33 | sequelize.addModels([Foo]); 34 | 35 | // You can use sinon and chai assertions directly in your SSCCE. 36 | const spy = sinon.spy(); 37 | sequelize.afterBulkSync(() => spy()); 38 | await sequelize.sync({ force: true }); 39 | expect(spy).to.have.been.called; 40 | 41 | console.log(await Foo.create({ name: 'TS foo' })); 42 | expect(await Foo.count()).to.equal(1); 43 | } 44 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "src/*", 4 | "dev/*" 5 | ], 6 | "compilerOptions": { 7 | "target": "es2021", 8 | "module": "nodenext", 9 | "experimentalDecorators": true, 10 | "moduleResolution": "nodenext", 11 | "esModuleInterop": true, 12 | "resolveJsonModule": true, 13 | "newLine": "lf", 14 | "stripInternal": true, 15 | "strict": true, 16 | "skipLibCheck": true, 17 | "allowSyntheticDefaultImports": true 18 | } 19 | } 20 | --------------------------------------------------------------------------------