diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51433ff..6ea5678 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,13 +18,15 @@ on: [push, pull_request] jobs: test: # Execute our own tests - name: Main - CRDB ${{ matrix.cockroachdb-docker-version }}, Sequelize v${{ matrix.sequelize-version }} + name: Main - CRDB ${{ matrix.cockroachdb-docker-version }} strategy: matrix: - # TODO(richardjcai): Re-enable tests for v5 after we get v6 suite passing. - # Focus on getting tests passing for v6 test suite. - sequelize-version: [5, 6] - cockroachdb-docker-version: ["cockroachdb/cockroach:v21.2.4", "cockroachdb/cockroach:v21.1.13"] + # Test the regular (non-innovation) releases that are still supported. + cockroachdb-docker-version: + - "cockroachdb/cockroach:latest-v24.3" + - "cockroachdb/cockroach:latest-v25.2" + - "cockroachdb/cockroach:latest-v25.4" + - "cockroachdb/cockroach:latest-v26.2" fail-fast: false runs-on: ubuntu-latest steps: @@ -34,44 +36,34 @@ jobs: run: | echo $CONTAINER_ENTRYPOINT docker pull ${{ matrix.cockroachdb-docker-version }} - docker run -d --name roach --hostname roach -p 26257:26257 -p 8080:8080 ${{ matrix.cockroachdb-docker-version }} start-single-node --insecure + docker run -d --name roach --hostname roach -p 26257:26257 -p 8080:8080 ${{ matrix.cockroachdb-docker-version }} start-single-node --insecure --store=type=mem,size=2GiB sudo apt update && sudo apt install wait-for-it -y wait-for-it -h localhost -p 26257 - docker exec roach bash -c "echo 'CREATE DATABASE sequelize_test;' | $CONTAINER_ENTRYPOINT sql --insecure" + docker exec roach $CONTAINER_ENTRYPOINT sql --insecure -e "SET CLUSTER SETTING sql.stats.automatic_collection.enabled = false" -e "SET CLUSTER SETTING kv.range_merge.queue.enabled = false" -e "SET CLUSTER SETTING diagnostics.reporting.enabled = false" -e "CREATE DATABASE sequelize_test" - name: Checkout the repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - name: Setup Node.js 12.x - uses: actions/setup-node@v1 + - name: Setup Node.js 22.x + uses: actions/setup-node@v4 with: - node-version: 12.x + node-version: 22.x - name: Install dependencies run: npm install - - name: Install Sequelize v${{ matrix.sequelize-version }} - run: npm install --save sequelize@^${{ matrix.sequelize-version }} - - name: Run tests run: npm test --crdb_version=${{ matrix.cockroachdb-docker-version }} sequelize-postgres-integration-tests: # Execute Sequelize integration tests for postgres - # This one will spawn 219 jobs + # This one will spawn 110 jobs if: ${{ !endsWith(github.event.head_commit.message, '[[skip sequelize integration tests]]') }} name: (${{ matrix.sequelize-branch }}) ${{ matrix.test-path }} strategy: matrix: - # TODO(richardjcai): Re-enable tests for v5 after we get v6 suite passing. - # Focus on getting tests passing for v6 test suite. - sequelize-branch: [v5, v6] - test-path: [associations/alias, associations/belongs-to-many, associations/belongs-to, associations/has-many, associations/has-one, associations/multiple-level-filters, associations/scope, associations/self, cls, configuration, data-types, dialects/abstract/connection-manager, dialects/postgres/associations, dialects/postgres/connection-manager, dialects/postgres/dao, dialects/postgres/data-types, dialects/postgres/error, dialects/postgres/hstore, dialects/postgres/query-interface, dialects/postgres/query, dialects/postgres/range, dialects/postgres/regressions, error, hooks/associations, hooks/bulkOperation, hooks/count, hooks/create, hooks/destroy, hooks/find, hooks/hooks, hooks/restore, hooks/updateAttributes, hooks/upsert, hooks/validate, include/findAll, include/findAndCountAll, include/findOne, include/limit, include/paranoid, include/schema, include/separate, include, instance/decrement, instance/destroy, instance/increment, instance/reload, instance/save, instance/to-json, instance/update, instance/values, instance, instance.validations, json, model/attributes/field, model/attributes/types, model/attributes, model/bulk-create/include, model/bulk-create, model/count, model/create/include, model/create, model/findAll/group, model/findAll/groupedLimit, model/findAll/order, model/findAll/separate, model/findAll, model/findOne, model/findOrBuild, model/geography, model/geometry, model/increment, model/json, model/optimistic_locking, model/paranoid, model/schema, model/scope/aggregate, model/scope/associations, model/scope/count, model/scope/destroy, model/scope/find, model/scope/findAndCountAll, model/scope/merge, model/scope/update, model/scope, model/searchPath, model/sum, model/sync, model/update, model/upsert, model, operators, pool, query-interface/changeColumn, query-interface/createTable, query-interface/describeTable, query-interface/dropEnum, query-interface/removeColumn, query-interface, replication, schema, sequelize/deferrable, sequelize/log, sequelize, sequelize.transaction, timezone, transaction, trigger, utils, vectors] - include: - - - # Luckily the test files are the same in v5 and v6, except for one extra file in v6: - sequelize-branch: v6 - test-path: sequelize/query + sequelize-branch: [v6] + test-path: [associations/alias, associations/belongs-to-many, associations/belongs-to, associations/has-many, associations/has-one, associations/multiple-level-filters, associations/scope, associations/self, cls, configuration, data-types, dialects/abstract/connection-manager, dialects/postgres/associations, dialects/postgres/connection-manager, dialects/postgres/dao, dialects/postgres/data-types, dialects/postgres/error, dialects/postgres/hstore, dialects/postgres/query-interface, dialects/postgres/query, dialects/postgres/range, dialects/postgres/regressions, error, hooks/associations, hooks/bulkOperation, hooks/count, hooks/create, hooks/destroy, hooks/find, hooks/hooks, hooks/restore, hooks/updateAttributes, hooks/upsert, hooks/validate, include/findAll, include/findAndCountAll, include/findOne, include/limit, include/paranoid, include/schema, include/separate, include, instance/decrement, instance/destroy, instance/increment, instance/reload, instance/save, instance/to-json, instance/update, instance/values, instance, instance.validations, json, model/attributes/field, model/attributes/types, model/attributes, model/bulk-create/include, model/bulk-create, model/count, model/create/include, model/create, model/findAll/group, model/findAll/groupedLimit, model/findAll/order, model/findAll/separate, model/findAll, model/findOne, model/findOrBuild, model/geography, model/geometry, model/increment, model/json, model/optimistic_locking, model/paranoid, model/schema, model/scope/aggregate, model/scope/associations, model/scope/count, model/scope/destroy, model/scope/find, model/scope/findAndCountAll, model/scope/merge, model/scope/update, model/scope, model/searchPath, model/sum, model/sync, model/update, model/upsert, model, operators, pool, query-interface/changeColumn, query-interface/createTable, query-interface/describeTable, query-interface/dropEnum, query-interface/removeColumn, query-interface, replication, schema, sequelize/deferrable, sequelize/log, sequelize, sequelize.transaction, sequelize/query, timezone, transaction, trigger, utils, vectors] fail-fast: false runs-on: ubuntu-latest env: @@ -81,21 +73,21 @@ jobs: SEQ_PW: '' SEQ_DB: sequelize_test steps: - - name: Start a single CockroachDB instance (v21.2.4) with docker + - name: Start a single CockroachDB instance (latest-v26.2) with docker run: | - docker pull cockroachdb/cockroach:v21.2.4 - docker run -d --name roach --hostname roach -p 26257:26257 -p 8080:8080 cockroachdb/cockroach:v21.2.4 start-single-node --insecure + docker pull cockroachdb/cockroach:latest-v26.2 + docker run -d --name roach --hostname roach -p 26257:26257 -p 8080:8080 cockroachdb/cockroach:latest-v26.2 start-single-node --insecure --store=type=mem,size=2GiB sudo apt update && sudo apt install wait-for-it -y wait-for-it -h localhost -p 26257 - docker exec roach bash -c 'echo "CREATE DATABASE sequelize_test;" | cockroach sql --insecure' + docker exec roach cockroach sql --insecure -e "SET CLUSTER SETTING sql.stats.automatic_collection.enabled = false" -e "SET CLUSTER SETTING kv.range_merge.queue.enabled = false" -e "SET CLUSTER SETTING diagnostics.reporting.enabled = false" -e "CREATE DATABASE sequelize_test" - name: Checkout `sequelize-cockroachdb` repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - name: Setup Node.js 12.x - uses: actions/setup-node@v1 + - name: Setup Node.js 22.x + uses: actions/setup-node@v4 with: - node-version: 12.x + node-version: 22.x - name: Install `sequelize-cockroachdb` dependencies run: npm install @@ -107,9 +99,11 @@ jobs: mv temp-unzip-out/* .downloaded-sequelize rmdir temp-unzip-out - - name: Install Sequelize dependencies + - name: Install Sequelize dependencies and build Sequelize working-directory: ./.downloaded-sequelize - run: npm install --ignore-scripts + run: | + npm install --ignore-scripts + node build.js - name: Provide the `sequelize-cockroachdb` patches # This script needs `fs-jetpack` as an extra dependency diff --git a/.github/workflows/ignore_tests/shared/dialects_query.txt b/.github/workflows/ignore_tests/shared/dialects_query.txt index f8f5acd..df68439 100644 --- a/.github/workflows/ignore_tests/shared/dialects_query.txt +++ b/.github/workflows/ignore_tests/shared/dialects_query.txt @@ -1 +1,2 @@ should throw due to alias being truncated +reuses connection after statement timeout diff --git a/.github/workflows/ignore_tests/shared/has_many.txt b/.github/workflows/ignore_tests/shared/has_many.txt index 3057c46..a6748e2 100644 --- a/.github/workflows/ignore_tests/shared/has_many.txt +++ b/.github/workflows/ignore_tests/shared/has_many.txt @@ -1,2 +1,3 @@ supports schemas should fetch associations for multiple instances with limit and order and a belongsTo relation +should ignore group from ancestor on deep separated query diff --git a/.github/workflows/ignore_tests/shared/model_bulk_create.txt b/.github/workflows/ignore_tests/shared/model_bulk_create.txt index 2e6e70f..33c700f 100644 --- a/.github/workflows/ignore_tests/shared/model_bulk_create.txt +++ b/.github/workflows/ignore_tests/shared/model_bulk_create.txt @@ -1,3 +1,4 @@ should make the auto incremented values available on the returned instances should make the auto incremented values available on the returned instances with custom fields should return auto increment primary key values +should upsert existing memberships diff --git a/.github/workflows/ignore_tests/shared/sync.txt b/.github/workflows/ignore_tests/shared/sync.txt index bf84c47..d79580c 100644 --- a/.github/workflows/ignore_tests/shared/sync.txt +++ b/.github/workflows/ignore_tests/shared/sync.txt @@ -1 +1,2 @@ should change a column if it exists in the model but is different in the database +updates the deferrable property of a foreign key diff --git a/.github/workflows/ignore_tests/shared/telemetry.txt b/.github/workflows/ignore_tests/shared/telemetry.txt new file mode 100644 index 0000000..8ad222e --- /dev/null +++ b/.github/workflows/ignore_tests/shared/telemetry.txt @@ -0,0 +1,2 @@ +custom logging with benchmarking has correct CLS context +executes a query with global benchmarking option and custom logger diff --git a/.github/workflows/ignore_tests/shared/transactions.txt b/.github/workflows/ignore_tests/shared/transactions.txt index f2a1701..d54f67a 100644 --- a/.github/workflows/ignore_tests/shared/transactions.txt +++ b/.github/workflows/ignore_tests/shared/transactions.txt @@ -2,3 +2,4 @@ supports transactions does not try to rollback a transaction that failed upon committing with SERIALIZABLE isolation level \(#3689\) should read the most recent committed rows when using the READ COMMITTED isolation level supports for share \(i.e. `SELECT ... LOCK IN SHARE MODE`\) +returns a promise that resolves once the transaction has been rolled back diff --git a/.github/workflows/ignore_tests/v5/create.txt b/.github/workflows/ignore_tests/v5/create.txt deleted file mode 100644 index 8742246..0000000 --- a/.github/workflows/ignore_tests/v5/create.txt +++ /dev/null @@ -1 +0,0 @@ -should release transaction when meeting errors diff --git a/.github/workflows/ignore_tests/v5/transactions.txt b/.github/workflows/ignore_tests/v5/transactions.txt deleted file mode 100644 index f4b4501..0000000 --- a/.github/workflows/ignore_tests/v5/transactions.txt +++ /dev/null @@ -1,3 +0,0 @@ -do not rollback if already committed -supports for share -"after each" hook for "supports for share" diff --git a/.github/workflows/ignore_tests/v5/upsert.txt b/.github/workflows/ignore_tests/v5/upsert.txt deleted file mode 100644 index 6ba690a..0000000 --- a/.github/workflows/ignore_tests/v5/upsert.txt +++ /dev/null @@ -1,15 +0,0 @@ -works with upsert on id -works with upsert on a composite key -works with upsert on a composite primary key -works with BLOBs -works with .field -works with primary key using .field -works with database functions -does not update when setting current values -works when two separate uniqueKeys are passed -works when indexes are created via indexes array -works when composite indexes are created via indexes array -should return default value set by the database (upsert) -works with upsert on id -works for table with custom primary key field -works for non incrementing primaryKey diff --git a/.gitignore b/.gitignore index 3c3629e..0c917a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +.downloaded-sequelize diff --git a/source/index.js b/source/index.js index 1ef71ad..553b743 100644 --- a/source/index.js +++ b/source/index.js @@ -56,8 +56,6 @@ const PostgresDialect = require('sequelize/lib/dialects/postgres/index'); PostgresDialect.prototype.supports.EXCEPTION = false; //// [2.1] Disable lock features support -// lockOuterJoinFailure is not supported. -PostgresDialect.prototype.supports.lockOuterJoinFailure = false; // skipLocked is not supported. PostgresDialect.prototype.supports.skipLocked = false; // lockKey is not supported. @@ -303,6 +301,35 @@ DataTypes.postgres.GEOGRAPHY.prototype.bindParam = (value, options) => { return `ST_GeomFromGeoJSON(${options.bindParam(value)}::json)::geography`; } +// [8] ENUM creation +// Newer versions of Sequelize v6 create ENUM types inside a +// `DO ... EXCEPTION WHEN duplicate_object` block to ignore types that already +// exist. CockroachDB does not support CREATE TYPE inside a function body, so +// use CREATE TYPE IF NOT EXISTS instead. +QueryGenerator.prototype.pgEnum = function ( + tableName, + attr, + dataType, + options +) { + const enumName = this.pgEnumName(tableName, attr, options); + let values; + + if (dataType.values) { + values = `ENUM(${dataType.values + .map(value => this.escape(value)) + .join(', ')})`; + } else { + values = dataType.toString().match(/^ENUM\(.+\)/)[0]; + } + + let sql = `CREATE TYPE IF NOT EXISTS ${enumName} AS ${values};`; + if (!!options && options.force === true) { + sql = this.pgEnumDrop(tableName, attr) + sql; + } + return sql; +}; + //// Done! Sequelize.supportsCockroachDB = true; diff --git a/tests/enum_test.js b/tests/enum_test.js index f5fce64..e0d8024 100644 --- a/tests/enum_test.js +++ b/tests/enum_test.js @@ -35,4 +35,18 @@ describe('Enum', function () { '"C" is not a valid choice in ["A","B"]' ); }); + + it('does not fail if the enum type already exists', async function () { + const queryInterface = this.sequelize.getQueryInterface(); + // Sequelize v5 calls this QueryGenerator. + const queryGenerator = + queryInterface.queryGenerator || queryInterface.QueryGenerator; + const createEnum = queryGenerator.pgEnum( + 'bars', + 'enum', + DataTypes.ENUM('A', 'B') + ); + expect(createEnum).to.include('CREATE TYPE IF NOT EXISTS'); + await this.sequelize.query(createEnum); + }); }); diff --git a/tests/run_tests/getTestsToIgnore.js b/tests/run_tests/getTestsToIgnore.js index 25b727e..b2a0fa4 100644 --- a/tests/run_tests/getTestsToIgnore.js +++ b/tests/run_tests/getTestsToIgnore.js @@ -1,8 +1,6 @@ const fs = require('fs'), path = require('path'), readline = require('readline'); -const version_helper = require ('../../source/version_helper.js') -const semver = require('semver'); const sharedIgnoredTestsPath = './../.github/workflows/ignore_tests/shared'; @@ -28,17 +26,6 @@ function getTestNames() { return path.join(sharedIgnoredTestsPath, f); }); - const sequelizeVersion = version_helper.GetSequelizeVersion() - if (semver.satisfies(sequelizeVersion, '<=5')) { - const v5IgnoredTestsPath = './../.github/workflows/ignore_tests/v5'; - var v5files = fs.readdirSync(v5IgnoredTestsPath) - files = files.concat( - v5files.map(f => { - return path.join(v5IgnoredTestsPath, f); - }) - ); - } - return Promise.all(parseFilesForTests(files)).then(arr => arr.flat().join('|')) } diff --git a/tests/run_tests/runTests.js b/tests/run_tests/runTests.js index af803cb..5dab593 100644 --- a/tests/run_tests/runTests.js +++ b/tests/run_tests/runTests.js @@ -5,10 +5,10 @@ const Mocha = require('mocha'), getTestsToIgnore = require('./getTestsToIgnore'); async function makeMocha() { - const testsToIgnore = getTestsToIgnore(); + const testsToIgnore = await getTestsToIgnore(); const mocha = new Mocha({ - grep: testsToIgnore, + grep: new RegExp(testsToIgnore), checkLeaks: true, reporter: 'spec', timeout: 30000, @@ -25,8 +25,13 @@ async function makeMocha() { } // Run the tests. -makeMocha().then(mocha => - mocha.run(function (failures) { - process.exit(failures ? 1 : 0); // exit with non-zero status if there were failures - }) -); +makeMocha() + .then(mocha => + mocha.run(function (failures) { + process.exit(failures ? 1 : 0); // exit with non-zero status if there were failures + }) + ) + .catch(err => { + console.error(err); + process.exit(1); + });