-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
feat(oracle): Add support for oracle dialect in v7 #18050
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…d showConstraints and test cases related to that
…createTableQuery() and data-type tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (7)
packages/oracle/src/query-generator.js (5)
174-176: Consider aliasing the version column.The query returns
VERSION_FULLwithout an alias. Aliasing it to"version"would standardize the output and potentially avoid the need to overridequeryInterface.fetchDatabaseVersionin other parts of the codebase.versionQuery() { - return `SELECT VERSION_FULL FROM PRODUCT_COMPONENT_VERSION WHERE PRODUCT LIKE 'Oracle%'`; + return `SELECT VERSION_FULL AS "version" FROM PRODUCT_COMPONENT_VERSION WHERE PRODUCT LIKE 'Oracle%'`; }
1-1291: Migrate this entire file to TypeScript.This file is implemented in JavaScript but the coding guidelines require: "Write all new implementations in TypeScript; avoid creating new .js files in src". The base
OracleQueryGeneratorTypeScriptalready exists inpackages/oracle/src/query-generator-typescript.internal.ts, so these Oracle-specific methods should be migrated into that TypeScript file rather than maintained in a separate JavaScript file.Based on coding guidelines and learnings.
324-326: Fix array splice bug when removing processed indexes.Splicing in forward order causes index misalignment. After the first
splice, all subsequent indices shift down by one, making the remaining indices inidxToDeletepoint to wrong elements.Apply this diff to fix by iterating in reverse:
- idxToDelete.forEach(idx => { - options.indexes.splice(idx, 1); - }); + for (let i = idxToDelete.length - 1; i >= 0; i--) { + options.indexes.splice(idxToDelete[i], 1); + }
741-747: Fix auto-increment detection across multiple rows.
allColumns[key]is overwritten for each row, so only the last row's value determines whether the column is treated as auto-increment. If rows have mixednulland non-nullvalues for an auto-increment column, the detection will be incorrect unless the last row happens to benull.The check at lines 773-777 partially catches this, but only when processing rows after
allColumns[key]was already set totrue. To properly enforce the invariant ("either all rows are null or all are non-null"), track both states:+ const sawNull = {}; + const sawNonNull = {}; + for (const fieldValueHash of fieldValueHashes) { forOwn(fieldValueHash, (value, key) => { + if (!fieldMappedAttributes[key]?.autoIncrement) { + allColumns[key] = false; + return; + } + + const isNull = value === null; + sawNull[key] ||= isNull; + sawNonNull[key] ||= !isNull; + + if (sawNull[key] && sawNonNull[key]) { + throw new Error( + 'For an auto-increment column either all rows must be null or non-null; a mix is not allowed.', + ); + } + - allColumns[key] = - fieldMappedAttributes[key] && - fieldMappedAttributes[key].autoIncrement === true && - value === null; + allColumns[key] = sawNull[key]; }); }
947-950: Fix unreachable DOUBLE condition.Line 949 compares
attribute.type === 'DOUBLE'against a string, butattribute.typeis a DataType instance, not a string. This condition is unreachable and will never execute. The pattern at lines 921, 933, and 940 correctly usesinstanceof.Change to:
if (attribute.autoIncrement) { template = ' NUMBER(*,0) GENERATED BY DEFAULT ON NULL AS IDENTITY'; - } else if (attribute.type && attribute.type === 'DOUBLE') { - template = attribute.type.toSql(); + } else if (attribute.type instanceof DataTypes.DOUBLE) { + template = attribute.type.toSql(); } else if (attribute.type) {packages/core/test/integration/sequelize/query.test.js (2)
122-125: Verify Date object vs string handling for Oracle timestamps.Oracle uses
Dateobjects forcreatedAtandupdatedAtwhile other dialects use strings. This differs from theinsertQueryconstruction (lines 79-83) which uses string literals formatted bydateLiteral(). Please verify this discrepancy is intentional and reflects Oracle driver behavior for bind parameters vs literals.Run the following script to check how Oracle bind parameters handle Date objects:
#!/bin/bash # Search for Oracle date/timestamp handling in driver and serialization code rg -nP --type=ts --type=js -C5 'oracle.*date|timestamp.*oracle' -g '!**/test/**' -g '**/oracle/**'
555-560: Unique constraint violations return generic DatabaseError for Oracle.Oracle returns
DatabaseErrorinstead ofUniqueConstraintErrorfor duplicate key violations, preventing applications from catching and handling unique constraint errors specifically. This is a functional limitation that should either be fixed in the Oracle error classification logic or properly documented.Verify whether Oracle error codes can be mapped to
UniqueConstraintError:#!/bin/bash # Search for Oracle error classification logic ast-grep --pattern 'class $_ extends DatabaseError { $$$ }' # Find Oracle unique constraint error codes (typically ORA-00001) rg -nP 'ORA-00001|unique.*constraint.*oracle|oracle.*unique.*constraint' -g '!**/test/**'
🧹 Nitpick comments (2)
packages/oracle/src/query-generator.js (1)
464-471: Remove commented-out code.Large blocks of commented code (lines 464-471 and 1114-1156) should be removed. If this code might be needed later, it's preserved in version control history. Keeping commented code in the source reduces readability and maintainability.
Also applies to: 1114-1156
packages/core/test/integration/sequelize/query.test.js (1)
892-918: Document why Oracle skips the duplicate named parameter test.The test is excluded for Oracle (and db2) without explanation. If Oracle doesn't support reusing the same named bind parameter multiple times in a query, consider adding a comment or using a
dialect.supportsfeature check instead of a direct dialect name check.As per coding guidelines.
If this is a known Oracle limitation, add a clarifying comment:
- if (!['db2', 'oracle'].includes(dialectName)) { + // Oracle and db2 don't support reusing named bind parameters in the same query + if (!['db2', 'oracle'].includes(dialectName)) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
packages/core/test/integration/query-interface/add-show-remove-constraint.test.ts(5 hunks)packages/core/test/integration/sequelize/query.test.js(27 hunks)packages/core/test/unit/query-generator/show-constraints-query.test.ts(9 hunks)packages/oracle/src/query-generator.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/core/test/unit/query-generator/show-constraints-query.test.ts
- packages/core/test/integration/query-interface/add-show-remove-constraint.test.ts
🧰 Additional context used
📓 Path-based instructions (5)
packages/**/test/**/*.test.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Name integration tests with the .test.js suffix
Files:
packages/core/test/integration/sequelize/query.test.js
packages/**/test/**/*.test.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/test/**/*.test.{js,ts}: Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Use beforeEach/afterEach to sync with { force: true } and close Sequelize instances in tests
In tests, skip unsupported behavior with dialect.supports.featureName checks
Files:
packages/core/test/integration/sequelize/query.test.js
packages/*/src/query-generator.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Files:
packages/oracle/src/query-generator.js
packages/**/src/**/*.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write all new implementations in TypeScript; avoid creating new .js files in src
Files:
packages/oracle/src/query-generator.js
packages/**/src/**/query-generator.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
When modifying query generation, update both the base query generator and all dialect-specific implementations
Files:
packages/oracle/src/query-generator.js
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Applied to files:
packages/core/test/integration/sequelize/query.test.jspackages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/query-generator.{js,ts} : When modifying query generation, update both the base query generator and all dialect-specific implementations
Applied to files:
packages/core/test/integration/sequelize/query.test.jspackages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
Applied to files:
packages/core/test/integration/sequelize/query.test.jspackages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Applied to files:
packages/core/test/integration/sequelize/query.test.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : Use beforeEach/afterEach to sync with { force: true } and close Sequelize instances in tests
Applied to files:
packages/core/test/integration/sequelize/query.test.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : In tests, skip unsupported behavior with dialect.supports.featureName checks
Applied to files:
packages/core/test/integration/sequelize/query.test.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/dialect.ts : When adding a dialect feature, update packages/{dialect}/src/dialect.ts to declare feature support flags
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Co-locate TypeScript type definitions with their implementation files
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/*.js : Write all new implementations in TypeScript; avoid creating new .js files in src
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-11-08T03:05:56.951Z
Learnt from: SippieCup
Repo: sequelize/sequelize PR: 18051
File: packages/core/src/utils/undot.ts:177-177
Timestamp: 2025-11-08T03:05:56.951Z
Learning: In packages/core/src/utils/undot.ts, the defensive check "if (!Array.isArray(obj))" before numeric leaf assignment in setByPathArray is intentional to handle edge cases where table aliases or oddly-named columns produce single-segment numeric keys (e.g., "0").
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Prefer TypeScript for all new code; only modify existing .js files when necessary
Applied to files:
packages/oracle/src/query-generator.js
🧬 Code graph analysis (2)
packages/core/test/integration/sequelize/query.test.js (2)
packages/core/test/integration/transaction.test.js (3)
fromQuery(23-29)sequelize(858-860)sequelize(876-878)packages/core/test/integration/sequelize.test.js (1)
packages/oracle/src/query-generator.js (5)
packages/oracle/src/query-generator-typescript.internal.ts (1)
OracleQueryGeneratorTypeScript(33-331)packages/core/src/utils/check.ts (1)
rejectInvalidOptions(33-54)packages/core/src/abstract-dialect/query-generator.js (5)
CREATE_TABLE_QUERY_SUPPORTABLE_OPTIONS(43-51)CREATE_TABLE_QUERY_SUPPORTABLE_OPTIONS(43-51)ADD_COLUMN_QUERY_SUPPORTABLE_OPTIONS(52-52)ADD_COLUMN_QUERY_SUPPORTABLE_OPTIONS(52-52)DataTypes(38-38)packages/core/src/utils/object.ts (2)
EMPTY_SET(16-16)getObjectFromMap(227-237)packages/core/src/utils/query-builder-utils.ts (1)
defaultValueSchemable(15-35)
🪛 Biome (2.1.2)
packages/oracle/src/query-generator.js
[error] 4-5: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 5-6: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 6-7: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 7-8: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 8-9: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 9-10: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 11-12: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 12-13: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 13-17: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 17-18: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 18-19: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 19-20: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 20-25: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 25-26: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 26-27: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 154-1286: Illegal use of an export declaration outside of a module
not allowed inside scripts
(parse)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 20)
- GitHub Check: Upload install and build artifact (Node 18)
🔇 Additional comments (3)
packages/core/test/integration/sequelize/query.test.js (3)
28-57: LGTM! Helper functions correctly implement Oracle-specific SQL syntax.The additions to
qq()and the newfromQuery()anddateLiteral()helpers properly centralize Oracle-specific SQL generation patterns. Oracle's requirement forFROM DUAL, double-quoted identifiers, andto_date()format are all correctly handled.
574-579: Oracle timestamp literal correctly uses TO_TIMESTAMP.The Oracle-specific query construction properly uses
TO_TIMESTAMP('2012-01-01 10:10:10', 'YYYY-MM-DD HH24:MI:SS')format. Note that foreign key constraint errors are properly classified (line 593 expectsForeignKeyConstraintError), which contrasts with the unique constraint error issue flagged earlier.
159-1000: Comprehensive Oracle integration looks correct.The extensive use of
fromQuery(), proper handling of Oracle's uppercase column names in results, inclusion of Oracle in appropriate dialect lists, and use ofSYSDATEfor timestamps all follow correct Oracle conventions and are consistently applied throughout the test suite.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
packages/core/test/integration/json.test.ts (2)
68-70: Usethis.skip()instead of earlyreturnto mark unsupported Oracle JSON as skippedRight now this test just returns early on unsupported Oracle versions, which Mocha reports as a passing test instead of a skipped one, and the arrow function prevents access to the Mocha context (
this.skip()).You can make the intent explicit and align with the other Oracle JSON guards by switching to a regular function and calling
this.skip():- it('should be able to store strings that require escaping', async () => { - if (dialect.name === 'oracle' && !(await isOracleJSONConstraintsSupported())) { - return; - } + it('should be able to store strings that require escaping', async function (this: Mocha.Context) { + if (dialect.name === 'oracle' && !(await isOracleJSONConstraintsSupported())) { + this.skip(); + }This makes unsupported Oracle configurations clearly show up as skipped rather than silently passing.
88-96: Simplify Oracle JSON version guardbeforehookThe logic here is correct and nicely addresses the earlier feedback about skipping only unsupported Oracle versions. The nested async IIFE is redundant, though; you can await the helper directly:
- if (dialect.name === 'oracle') { - before(async function checkOracleVersionForJSONSupport(this: Mocha.Context) { - return (async () => { - if (!(await isOracleJSONConstraintsSupported())) { - this.skip(); - } - })(); - }); - } + if (dialect.name === 'oracle') { + before(async function checkOracleVersionForJSONSupport(this: Mocha.Context) { + if (!(await isOracleJSONConstraintsSupported())) { + this.skip(); + } + }); + }Behavior stays the same, but the hook is easier to read.
packages/core/test/integration/sequelize/query.test.js (1)
51-57: Inconsistent date literal format with inline usage.The
dateLiteral()helper usesto_date(...)for Oracle, but lines 533-534 and 572 useTO_TIMESTAMP(...)directly. Consider whether both formats are needed or if one should be standardized.Apply this diff if you want to align the helper with the inline usage:
const dateLiteral = str => { if (dialectName === 'oracle') { - return `to_date('${str}','YYYY-MM-DD HH24:MI:SS')`; + return `TO_TIMESTAMP('${str}','YYYY-MM-DD HH24:MI:SS')`; } return `'${str}'`; };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/core/test/integration/json.test.ts(3 hunks)packages/core/test/integration/sequelize/query.test.js(27 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
packages/**/test/**/*.test.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Name unit tests with the .test.ts suffix
Files:
packages/core/test/integration/json.test.ts
packages/**/test/**/*.test.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/test/**/*.test.{js,ts}: Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Use beforeEach/afterEach to sync with { force: true } and close Sequelize instances in tests
In tests, skip unsupported behavior with dialect.supports.featureName checks
Files:
packages/core/test/integration/json.test.tspackages/core/test/integration/sequelize/query.test.js
packages/**/test/**/*.test.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Name integration tests with the .test.js suffix
Files:
packages/core/test/integration/sequelize/query.test.js
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : In tests, skip unsupported behavior with dialect.supports.featureName checks
Applied to files:
packages/core/test/integration/json.test.tspackages/core/test/integration/sequelize/query.test.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Applied to files:
packages/core/test/integration/json.test.tspackages/core/test/integration/sequelize/query.test.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
Applied to files:
packages/core/test/integration/json.test.tspackages/core/test/integration/sequelize/query.test.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/dialect.ts : When adding a dialect feature, update packages/{dialect}/src/dialect.ts to declare feature support flags
Applied to files:
packages/core/test/integration/json.test.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/core/test/chai-extensions.d.ts : Use Chai assertions with the project’s custom extensions available in packages/core/test/chai-extensions.d.ts
Applied to files:
packages/core/test/integration/json.test.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Applied to files:
packages/core/test/integration/json.test.tspackages/core/test/integration/sequelize/query.test.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/query-generator.{js,ts} : When modifying query generation, update both the base query generator and all dialect-specific implementations
Applied to files:
packages/core/test/integration/json.test.tspackages/core/test/integration/sequelize/query.test.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : Use beforeEach/afterEach to sync with { force: true } and close Sequelize instances in tests
Applied to files:
packages/core/test/integration/json.test.tspackages/core/test/integration/sequelize/query.test.js
🧬 Code graph analysis (2)
packages/core/test/integration/json.test.ts (1)
packages/core/test/integration/support.ts (1)
isOracleJSONConstraintsSupported(360-380)
packages/core/test/integration/sequelize/query.test.js (2)
packages/core/test/integration/transaction.test.js (3)
fromQuery(23-29)sequelize(858-860)sequelize(876-878)packages/core/test/integration/sequelize.test.js (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 18)
- GitHub Check: Upload install and build artifact (Node 20)
🔇 Additional comments (7)
packages/core/test/integration/json.test.ts (1)
11-18: ImportingisOracleJSONConstraintsSupportedhere looks goodCentralizing the Oracle JSON constraint version check via the shared helper keeps these tests consistent with the rest of the suite; no issues with this import block.
packages/core/test/integration/sequelize/query.test.js (6)
28-57: LGTM! Helper functions follow established patterns.The
qq(),fromQuery(), anddateLiteral()helpers correctly implement Oracle-specific test utilities and follow the same pattern used in other test files (e.g., transaction.test.js).Based on learnings
159-220: LGTM! Logging tests correctly use fromQuery().All logging-related tests properly append
fromQuery()to SELECT statements, ensuring Oracle gets the requiredFROM DUALclause.
286-287: LGTM! Oracle correctly categorized with positional bind dialects.Oracle is appropriately grouped with db2, postgres, mariadb, and mysql as dialects that use positional bind parameters.
531-538: LGTM! TO_TIMESTAMP syntax correct for Oracle error tests.The Oracle-specific query construction using
TO_TIMESTAMP('2012-01-01 10:10:10', 'YYYY-MM-DD HH24:MI:SS')is correct and ensures proper error handling tests for unique constraints and foreign key constraints.Also applies to: 571-576
923-926: LGTM! Uppercase identifier handling correct for Oracle.Oracle's default behavior of returning unquoted identifiers in uppercase is correctly handled in the expected results across all bind parameter tests.
Also applies to: 943-946, 959-962, 971-974
889-915: Verify whether Sequelize's Oracle dialect truly cannot reuse named bind parameters.Node-oracledb supports reusing the same named bind variable multiple times in a SQL statement (e.g.,
SELECT :x, :x FROM dualwith{ x: 42 }). However, the test at line 889 excludes Oracle without explanation, suggesting Sequelize's Oracle dialect may have its own limitation.Please confirm whether:
- This is a known Sequelize limitation, or
- Whether the exclusion can be safely removed and the test run against Oracle
If supported, this test should be enabled for Oracle to ensure consistency with actual driver capabilities.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (5)
packages/oracle/src/query.js (5)
24-38: Constructor still readsoutFormatfrom rawoptionsparameter.This issue was flagged in a previous review but remains unresolved. Line 37 reads from the raw
optionsparameter which can beundefined, causing aTypeError. The mergedthis.options(line 26) already handlesoptions || {}, so you should use it consistently.Apply this fix:
- this.outFormat = options.outFormat || oracledb.OBJECT; + this.outFormat = this.options.outFormat || oracledb.OBJECT;
146-167: Transaction control flags don't take effect due to property name mismatch.This critical issue was flagged in a previous review but remains unresolved. Lines 148, 155, and 162 set
this.autocommit(lowercase), but all other code readsthis.autoCommit(camelCase) at lines 45, 170, 180, 194, 202, 204, 253, 257. This preventsBEGIN TRANSACTION,SET AUTOCOMMIT ON, andSET AUTOCOMMIT OFFfrom affecting subsequent query execution.Apply these fixes:
if (this.sql.startsWith('BEGIN TRANSACTION')) { - this.autocommit = false; + this.autoCommit = false; // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.resolve(); } if (this.sql.startsWith('SET AUTOCOMMIT ON')) { - this.autocommit = true; + this.autoCommit = true; // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.resolve(); } if (this.sql.startsWith('SET AUTOCOMMIT OFF')) { - this.autocommit = false; + this.autoCommit = false; // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.resolve(); }
339-435: Potential double-parse or type error for JSON attributes.This issue was flagged in a previous review but remains unresolved. Lines 412-414 unconditionally call
JSON.parse(value)for JSON types, then lines 426-429 still invoke the dialect parser for the same value. This risks:
- Double-parsing if the dialect parser also decodes JSON
TypeErrorifvalueis aBufferor already an object (Oracle stores JSON asBLOBper data-types-overrides.ts)Prefer one of these solutions:
Option 1 (recommended): Let the dialect parser handle JSON entirely:
if (modelDefinition.rawAttributes[key] && modelDefinition.rawAttributes[key].type) { let typeid = modelDefinition.rawAttributes[key].type.toLocaleString(); - if (modelDefinition.rawAttributes[key].type.getDataTypeId() === 'JSON') { - value = JSON.parse(value); - } // For some types, the "name" of the type is returned with the length, we remove itOption 2: Only parse strings and skip dialect parser for JSON:
+ let isJsonType = false; if (modelDefinition.rawAttributes[key].type.getDataTypeId() === 'JSON') { + isJsonType = true; - value = JSON.parse(value); + if (typeof value === 'string') { + value = JSON.parse(value); + } } // For some types, the "name" of the type is returned with the length, we remove it // For Boolean we skip this because BOOLEAN is mapped to CHAR(1) and we dont' want to // remove the (1) for BOOLEAN if ( typeid.includes('(') && modelDefinition.rawAttributes[key].type.getDataTypeId() !== 'BOOLEAN' ) { typeid = typeid.slice(0, typeid.indexOf('(')); } const parser = this.sequelize.dialect.getParserForDatabaseDataType(typeid); - if (value !== null && parser) { + if (value !== null && parser && !isJsonType) { value = parser(value); }Based on learnings.
545-559:isNewRecordflag remains inverted in upsert result.This issue was flagged in a previous review but remains unresolved. Line 558 sets
isNewRecord: data.isUpdate, which is1for updates and0for inserts—the opposite of the intended semantics.isNewRecordshould betruefor new records andfalsefor existing ones.Apply this fix:
- result = [{ isNewRecord: data.isUpdate, value: data }, data.isUpdate == 0]; + result = [{ isNewRecord: data.isUpdate == 0, value: data }, data.isUpdate == 0];
656-660: ORA-02443 error handling still has regex and constructor issues.While the ORA-02291/02292 handling was fixed, the ORA-02443 case remains unresolved from the previous review. Line 657's regex has no capture group, so
match[1]isundefined. Additionally,UnknownConstraintErrorexpects an options object, not a string parameter.Apply this fix:
// ORA-02443: Cannot drop constraint - nonexistent constraint - match = err.message.match(/ORA-02443/); - if (match && match.length > 0) { - return new UnknownConstraintError(match[1]); + match = err.message.match(/ORA-02443:[^-]*-\s*(.+?)(?:\s|$)/); + if (match && match.length > 1) { + return new UnknownConstraintError({ + constraint: match[1].trim(), + cause: err, + }); }
🧹 Nitpick comments (4)
packages/core/test/integration/error.test.ts (4)
553-563: Oracle ValidationError.errors parity with other dialectsTreating Oracle like db2 (i.e.
ValidationError.errorsbeing empty for bulk unique violations) is acceptable for initial support, but it does mean Oracle exposes less structured info than most other dialects here. Consider adding a TODO to parse the ORA-00001 details intoerror.errorslater for parity, once the dialect stabilizes.Also applies to: 633-647
606-608: Harden Oracle unique-constraint regex for index-name matchingThe generic ORA‑00001 check is fine, but the index‑specific one:
/ORA-00001: unique constraint \(.*.users_username_unique\) violated/relies on exact casing and an unescaped
.beforeusers_username_unique. To make this more resilient to schema prefixes & case differences, you could tighten it to something like:- /ORA-00001: unique constraint \(.*.users_username_unique\) violated/ + /ORA-00001: unique constraint \((?:.+\.)?users_username_unique\) violated/iThis still asserts the right constraint name while tolerating driver/DDL variations.
Also applies to: 682-686
763-769: Oracle FK errors expose less metadata than other dialectsFor Oracle FK violations you currently assert
error.tableisundefinedanderror.fieldsisnull, whereas other dialects generally surface at leasttableorfields. Oracle’s ORA‑02291/02292 messages contain the constraint name, so in the future it should be possible to extract table/column info for better parity; if you plan to improve the Oracle error mapping, these expectations will need to be relaxed or updated accordingly.Also applies to: 846-852
896-899: Consider aligning Oracle duplicate-constraint mapping with UnknownConstraintErrorFor duplicate constraint names you assert a bare
DatabaseErroron Oracle, while MariaDB/MySQL/MSSQL/sqlite3 surface anAggregateErrorthat includes anUnknownConstraintErrorwithconstraintandtable. That’s a divergence in the cross‑dialect error contract: user code catchingUnknownConstraintErrorwon’t work on Oracle here. If feasible, consider mapping ORA‑02264 into the sameUnknownConstraintErrorshape so behavior is consistent across dialects.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/core/test/integration/error.test.ts(8 hunks)packages/oracle/src/query.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
packages/**/test/**/*.test.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Name unit tests with the .test.ts suffix
Files:
packages/core/test/integration/error.test.ts
packages/**/test/**/*.test.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/test/**/*.test.{js,ts}: Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Use beforeEach/afterEach to sync with { force: true } and close Sequelize instances in tests
In tests, skip unsupported behavior with dialect.supports.featureName checks
Files:
packages/core/test/integration/error.test.ts
packages/**/src/**/*.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write all new implementations in TypeScript; avoid creating new .js files in src
Files:
packages/oracle/src/query.js
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : In tests, skip unsupported behavior with dialect.supports.featureName checks
Applied to files:
packages/core/test/integration/error.test.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/query-generator.{js,ts} : When modifying query generation, update both the base query generator and all dialect-specific implementations
Applied to files:
packages/core/test/integration/error.test.tspackages/oracle/src/query.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Applied to files:
packages/core/test/integration/error.test.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
Applied to files:
packages/core/test/integration/error.test.tspackages/oracle/src/query.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Applied to files:
packages/core/test/integration/error.test.tspackages/oracle/src/query.js
🧬 Code graph analysis (2)
packages/core/test/integration/error.test.ts (1)
packages/core/src/errors/database-error.ts (1)
DatabaseError(22-38)
packages/oracle/src/query.js (6)
packages/oracle/src/query.d.ts (1)
OracleQuery(5-5)packages/oracle/src/index.mjs (2)
OracleQuery(7-7)OracleQuery(7-7)packages/oracle/src/_internal/data-types-overrides.ts (1)
JSON(331-358)packages/core/src/model-definition.ts (1)
index(706-757)packages/core/src/model-typescript.ts (1)
uniqueKeys(352-384)packages/core/src/utils/string.ts (1)
nameIndex(62-70)
🪛 Biome (2.1.2)
packages/oracle/src/query.js
[error] 2-10: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 10-11: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 11-12: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 12-13: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 13-14: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 14-15: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 15-16: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 16-17: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 17-18: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 18-19: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 22-753: Illegal use of an export declaration outside of a module
not allowed inside scripts
(parse)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 18)
- GitHub Check: Upload install and build artifact (Node 20)
🔇 Additional comments (1)
packages/core/test/integration/error.test.ts (1)
494-503: Oracle branch correctly reuses quoted-identifier INSERTIncluding
oraclein the['db2', 'ibmi', 'oracle']branch so it uses the double‑quotedINSERT INTO "users" ("name") ...SQL matches how those dialects quote identifiers and keeps the test intent clear. No issues here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (9)
packages/oracle/src/query-generator.js (4)
3-1214: This new dialect implementation should ideally live in TypeScript, not a.jsfile.Per the repo guidelines, new implementations under
packages/**/src/**should be written in TypeScript, and dialect SQL should go intoquery-generator-typescript.internal.ts(with a thin JS wrapper only if absolutely needed). This file contains substantial new logic (DDL, DML, JSON helpers, bind handling) that would benefit from typings, and it also triggers lint/parser issues in tools expecting ESM TS.Consider migrating the concrete methods from this file into
OracleQueryGeneratorTypeScriptand keeping this JS file as a minimal public wrapper (or removing it entirely if consumers can import the TS‑built artifact directly).
254-323: Fix unique‑index → unique‑constraint handling: splice logic anduniquetype assumptions.Two issues in the
createTableQueryindex‑to‑constraint conversion block:
Forward
spliceoveridxToDeletecan remove wrong indexes.
Splicingoptions.indexesin ascending index order shifts subsequent indices; later deletions may target the wrong element or no element at all. This leaves some indexes inoptions.indexeseven though they were meant to be converted to constraints.
index.unique.lengthassumesuniqueis notfalse.
For{ unique: false }, the conditionindex.unique === true || (index.unique.length > 0 && index.unique !== false)still evaluates thelengthaccess on a boolean, which will throw at runtime.A safe fix is to normalize
uniqueto a boolean and remove indexes in reverse order:- if (options && options.indexes && options.indexes.length > 0) { - const idxToDelete = []; + if (options && options.indexes && options.indexes.length > 0) { + const idxToDelete: number[] = []; options.indexes.forEach((index, idx) => { - if ( - 'unique' in index && - (index.unique === true || (index.unique.length > 0 && index.unique !== false)) - ) { + const unique = + typeof index.unique === 'boolean' + ? index.unique + : Boolean(index.unique); + + if ('unique' in index && unique) { // If unique index, transform to unique constraint on column const fields = index.fields.map(field => { if (typeof field === 'string') { return field; } return field.attribute; }); @@ - idxToDelete.forEach(idx => { - options.indexes.splice(idx, 1); - }); + // delete from the end to avoid index shifting + for (let i = idxToDelete.length - 1; i >= 0; i--) { + options.indexes.splice(idxToDelete[i], 1); + }This preserves the intended behavior and avoids index‑shift bugs.
682-727: Auto‑increment detection inbulkInsertQueryis incorrect when last row is non‑null.The
allColumnsmap is recomputed for every row:for (const fieldValueHash of fieldValueHashes) { forOwn(fieldValueHash, (value, key) => { allColumns[key] = fieldMappedAttributes[key] && fieldMappedAttributes[key].autoIncrement === true && value === null; }); }This means
allColumns[key]only reflects the last row’s value for that column. Later, when building tuples, mixednull/ non‑nullvalues are only rejected if the last row isnull; if the last row is non‑null, a mix ofnulland non‑nullsilently passes and the column is treated as a regular in‑bind.To enforce the intended invariant (“either all rows are null or all are non‑null for auto‑increment columns”), track both “saw null” and “saw non‑null” per column:
- const allColumns = {}; + const allColumns: Record<string, boolean> = {}; @@ - for (const fieldValueHash of fieldValueHashes) { - forOwn(fieldValueHash, (value, key) => { - allColumns[key] = - fieldMappedAttributes[key] && - fieldMappedAttributes[key].autoIncrement === true && - value === null; - }); - } + const sawNull: Record<string, boolean> = {}; + const sawNonNull: Record<string, boolean> = {}; + + for (const fieldValueHash of fieldValueHashes) { + forOwn(fieldValueHash, (value, key) => { + if (!fieldMappedAttributes[key]?.autoIncrement) { + allColumns[key] = false; + return; + } + + const isNull = value === null; + sawNull[key] ||= isNull; + sawNonNull[key] ||= !isNull; + + if (sawNull[key] && sawNonNull[key]) { + throw new Error( + 'For an auto-increment column either all rows must be null or non-null; a mix is not allowed.', + ); + } + + // true means "use DEFAULT / outbind" + allColumns[key] = sawNull[key]; + }); + }This ensures you either generate
DEFAULTfor that column in every row or treat it as a regular bound column, and you consistently reject mixed sets.
848-955: Unreachable / incorrectDOUBLEhandling and type checks inattributeToSQL.The branch:
} else if (attribute.type && attribute.type === 'DOUBLE') { template = attribute.type.toSql(); }is problematic:
- In normal usage,
attribute.typeis a DataTypes instance, not the string'DOUBLE', so this condition never matches.- If
attribute.typewere the string'DOUBLE', callingtoSql()would throw.Oracle
DOUBLEcolumns will currently go through the genericelse if (attribute.type)path, so this is effectively dead or buggy code.A safer approach is either to:
- Remove this branch entirely and let the generic
attribute.type.toString()path handle DOUBLE, or- Check for the actual type instance, e.g.:
- } else if (attribute.type && attribute.type === 'DOUBLE') { - template = attribute.type.toSql(); - } else if (attribute.type) { + } else if (attribute.type instanceof DataTypes.DOUBLE) { + template = attribute.type.toSql(); + } else if (attribute.type) {which aligns with the earlier ENUM / JSON / BOOLEAN checks.
packages/oracle/src/query-generator-typescript.internal.ts (2)
140-157:removeConstraintQuerygenerates invalid Oracle syntax forifExists.For constraints starting with
sys, this override emits:ALTER TABLE <table> DROP CONSTRAINT IF EXISTS <name> [CASCADE]Oracle’s
ALTER TABLE ... DROP CONSTRAINTdoes not supportIF EXISTS, so any call withoptions.ifExists === truewill fail at runtime.To fix this:
- Either reject
ifExistsfor Oracle by validating options before building SQL, e.g.:+ if (options) { + // Oracle does not support IF EXISTS for DROP CONSTRAINT + rejectInvalidOptions( + 'removeConstraintQuery', + this.dialect, + /* REMOVE_CONSTRAINT_QUERY_SUPPORTABLE_OPTIONS */ new Set(['ifExists', 'cascade']), + /* supportedOptions */ new Set(['cascade']), + options, + ); + } + if (constraintName.startsWith('sys')) { return joinSQLFragments([ 'ALTER TABLE', this.quoteTable(tableName), 'DROP CONSTRAINT', - options?.ifExists ? 'IF EXISTS' : '', constraintName, options?.cascade ? 'CASCADE' : '', ]); }
- Or, if you truly need an “if exists” behavior, wrap the DROP in a PL/SQL block that checks the data dictionary before executing.
Right now, any use of
ifExistshere will be broken.Does Oracle SQL support `ALTER TABLE ... DROP CONSTRAINT IF EXISTS` syntax, and what is the recommended pattern to conditionally drop a constraint if it exists?
379-408: Use Oracle’sCOMMIT/ROLLBACKsyntax instead of T‑SQL forms.
commitTransactionQueryandrollbackTransactionQuerycurrently return:return 'COMMIT TRANSACTION'; ... return 'ROLLBACK TRANSACTION';These are SQL Server / T‑SQL forms and are not valid Oracle SQL; Oracle expects
COMMIT(optionallyCOMMIT WORK) andROLLBACK. Because Oracle does not enablesupports.connectionTransactionMethodsby default, these methods will be called and produce invalid SQL.You should either:
- Return plain Oracle statements:
commitTransactionQuery() { - return 'COMMIT TRANSACTION'; + return 'COMMIT'; } rollbackTransactionQuery(): string { if (this.dialect.supports.connectionTransactionMethods) { throw new Error( `rollbackTransactionQuery is not supported by the ${this.dialect.name} dialect.`, ); } - return 'ROLLBACK TRANSACTION'; + return 'ROLLBACK'; }
- Or, if Oracle is always meant to use connection‑level transaction control, set
supports.connectionTransactionMethods = truefor this dialect and make these methods throw unconditionally.As written, they are very likely to generate invalid SQL.
What are the valid SQL statements for committing and rolling back a transaction in Oracle Database, and does Oracle accept `COMMIT TRANSACTION` / `ROLLBACK TRANSACTION`?packages/oracle/src/dialect.ts (3)
88-90: Documentation URL doesn't match minimum database version.Line 88 links to Oracle 23 documentation, but line 90 sets
minimumDatabaseVersionto '18.0.0'. Oracle 23 introduced features unavailable in 18.0.0 (native JSON SQL type, SQL Domains, spatial enhancements).Either update the URL to Oracle 18 documentation or increase the minimum version to 23.0.0 if Oracle 23-specific features are required.
109-111: Runtime error when replication config is absent.
this.sequelize.options.replication.write.username?.toUpperCase()will throw ifreplicationorwriteis undefined (common in non-replication setups), because property access occurs before optional chaining onusername.Apply this diff to handle both replication and direct username safely:
getDefaultSchema(): string { - return this.sequelize.options.replication.write.username?.toUpperCase() ?? ''; + const replicationUser = this.sequelize.options.replication?.write?.username; + const directUser = this.sequelize.options.username; + const username = replicationUser ?? directUser; + return username?.toUpperCase() ?? ''; }
135-182: Fix typos in validation comments.The date validation logic is thorough and security-conscious, but there are two typos:
- Line 141: "indicated y" should be "indicated by"
- Line 146: "TIMESTAM_TZ" should be "TIMESTAMP_TZ"
Apply this diff:
// Validate that the split result has exactly three parts (function name, parameters, and an empty string) - // and that there are no additional SQL commands after the function call (indicated y the last empty string). + // and that there are no additional SQL commands after the function call (indicated by the last empty string). if (splitVal.length !== 3 || splitVal[2] !== '') { throw new Error('Invalid SQL function call.'); // Error if function call has unexpected format } - // Extract the function name (either 'TO_TIMESTAM_TZ' or 'TO_DATE') and the contents inside the parentheses + // Extract the function name (either 'TO_TIMESTAMP_TZ' or 'TO_DATE') and the contents inside the parentheses const functionName = splitVal[0].trim(); // Function name should be 'TO_TIMESTAMP_TZ' or 'TO_DATE'
🧹 Nitpick comments (3)
packages/oracle/src/query-interface-typescript.internal.ts (1)
13-26: Avoid overridingfetchDatabaseVersionby aligning Oracle’sversionQueryoutput.This override exists only because Oracle returns
VERSION_FULL. If you instead alias it toversioninOracleQueryGeneratorTypeScript.versionQuery(e.g.SELECT VERSION_FULL AS version ...), you can drop this method and rely on the baseAbstractQueryInterfaceTypeScript.fetchDatabaseVersion(including its runtime assertion on theversionfield). That keeps Oracle in line with other dialects and removes an extra Oracle‑specific code path here.packages/core/src/abstract-dialect/query-interface-typescript.ts (1)
261-279: Good use of a dialect flag to control concurrent FK drops.The new
concurrentDropConstraintsguard makes FK removal concurrent only for dialects that explicitly support it, while keeping the previous sequential behavior as the default. This limits deadlock/timeout risk and keeps behavior configurable per dialect.Ensure each dialect sets
supports.dropTable.concurrentDropConstraintsappropriately (e.g. conservativefalsefor engines known to deadlock under concurrent DDL).packages/oracle/src/dialect.ts (1)
16-16: Consider using a type alias for the empty interface.An empty interface is equivalent to
{}. If this is a placeholder for future options, consider using a type alias for better semantics.Apply this diff:
-export interface OracleDialectOptions {} +export type OracleDialectOptions = Record<string, never>;Alternatively, if options will be added soon, the empty interface is acceptable as a placeholder.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
packages/core/src/abstract-dialect/dialect.ts(5 hunks)packages/core/src/abstract-dialect/query-interface-typescript.ts(1 hunks)packages/core/test/integration/support.ts(1 hunks)packages/oracle/src/dialect.ts(1 hunks)packages/oracle/src/query-generator-typescript.internal.ts(1 hunks)packages/oracle/src/query-generator.js(1 hunks)packages/oracle/src/query-interface-typescript.internal.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
packages/*/src/query-generator.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Files:
packages/oracle/src/query-generator.js
packages/**/src/**/*.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write all new implementations in TypeScript; avoid creating new .js files in src
Files:
packages/oracle/src/query-generator.js
packages/**/src/**/query-generator.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
When modifying query generation, update both the base query generator and all dialect-specific implementations
Files:
packages/oracle/src/query-generator.js
packages/*/src/dialect.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
When adding a dialect feature, update packages/{dialect}/src/dialect.ts to declare feature support flags
Files:
packages/oracle/src/dialect.ts
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
Applied to files:
packages/oracle/src/query-interface-typescript.internal.tspackages/oracle/src/query-generator.jspackages/core/test/integration/support.tspackages/core/src/abstract-dialect/query-interface-typescript.tspackages/core/src/abstract-dialect/dialect.tspackages/oracle/src/query-generator-typescript.internal.tspackages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Applied to files:
packages/oracle/src/query-interface-typescript.internal.tspackages/oracle/src/query-generator.jspackages/core/src/abstract-dialect/query-interface-typescript.tspackages/core/src/abstract-dialect/dialect.tspackages/oracle/src/query-generator-typescript.internal.tspackages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/query-generator.{js,ts} : When modifying query generation, update both the base query generator and all dialect-specific implementations
Applied to files:
packages/oracle/src/query-interface-typescript.internal.tspackages/oracle/src/query-generator.jspackages/core/src/abstract-dialect/query-interface-typescript.tspackages/core/src/abstract-dialect/dialect.tspackages/oracle/src/query-generator-typescript.internal.tspackages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/dialect.ts : When adding a dialect feature, update packages/{dialect}/src/dialect.ts to declare feature support flags
Applied to files:
packages/oracle/src/query-interface-typescript.internal.tspackages/oracle/src/query-generator.jspackages/core/src/abstract-dialect/query-interface-typescript.tspackages/core/src/abstract-dialect/dialect.tspackages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Co-locate TypeScript type definitions with their implementation files
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/*.js : Write all new implementations in TypeScript; avoid creating new .js files in src
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-11-08T03:05:56.951Z
Learnt from: SippieCup
Repo: sequelize/sequelize PR: 18051
File: packages/core/src/utils/undot.ts:177-177
Timestamp: 2025-11-08T03:05:56.951Z
Learning: In packages/core/src/utils/undot.ts, the defensive check "if (!Array.isArray(obj))" before numeric leaf assignment in setByPathArray is intentional to handle edge cases where table aliases or oddly-named columns produce single-segment numeric keys (e.g., "0").
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Prefer TypeScript for all new code; only modify existing .js files when necessary
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : In tests, skip unsupported behavior with dialect.supports.featureName checks
Applied to files:
packages/core/test/integration/support.tspackages/core/src/abstract-dialect/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Applied to files:
packages/core/src/abstract-dialect/dialect.tspackages/oracle/src/dialect.ts
🧬 Code graph analysis (5)
packages/oracle/src/query-interface-typescript.internal.ts (2)
packages/core/src/abstract-dialect/query-interface-internal.ts (1)
AbstractQueryInterfaceInternal(11-50)packages/core/src/abstract-dialect/query-interface.types.ts (1)
FetchDatabaseVersionOptions(128-128)
packages/oracle/src/query-generator.js (5)
packages/oracle/src/query-generator-typescript.internal.ts (1)
OracleQueryGeneratorTypeScript(34-409)packages/core/src/utils/check.ts (1)
rejectInvalidOptions(33-54)packages/core/src/abstract-dialect/query-generator.js (5)
CREATE_TABLE_QUERY_SUPPORTABLE_OPTIONS(43-51)CREATE_TABLE_QUERY_SUPPORTABLE_OPTIONS(43-51)ADD_COLUMN_QUERY_SUPPORTABLE_OPTIONS(52-52)ADD_COLUMN_QUERY_SUPPORTABLE_OPTIONS(52-52)DataTypes(38-38)packages/core/src/utils/object.ts (2)
EMPTY_SET(16-16)getObjectFromMap(227-237)packages/core/src/utils/query-builder-utils.ts (1)
defaultValueSchemable(15-35)
packages/core/test/integration/support.ts (1)
packages/core/test/support.ts (1)
sequelize(504-504)
packages/oracle/src/query-generator-typescript.internal.ts (8)
packages/oracle/src/query-generator.internal.ts (1)
OracleQueryGeneratorInternal(11-54)packages/oracle/src/dialect.ts (1)
OracleDialect(23-191)packages/core/src/abstract-dialect/query-generator.types.ts (8)
TableOrModel(13-13)RemoveIndexQueryOptions(194-198)RenameTableQueryOptions(66-68)RemoveColumnQueryOptions(77-80)CreateSchemaQueryOptions(35-42)TruncateTableQueryOptions(71-74)ShowConstraintsQueryOptions(171-175)BulkDeleteQueryOptions(189-191)packages/core/src/utils/check.ts (1)
rejectInvalidOptions(33-54)packages/core/src/utils/object.ts (1)
EMPTY_SET(16-16)packages/core/src/utils/string.ts (1)
generateIndexName(72-107)packages/core/src/abstract-dialect/query-interface.d.ts (1)
TableNameWithSchema(71-75)packages/core/src/utils/model-utils.ts (1)
extractModelDefinition(35-45)
packages/oracle/src/dialect.ts (4)
packages/core/src/abstract-dialect/dialect.ts (1)
SupportableNumericOptions(15-19)packages/oracle/src/connection-manager.ts (1)
OracleConnectionOptions(26-33)packages/core/src/utils/sql.ts (1)
createSpecifiedOrderedBindCollector(401-419)packages/oracle/src/_internal/connection-options.ts (1)
CONNECTION_OPTION_NAMES(75-84)
🪛 Biome (2.1.2)
packages/oracle/src/query-generator.js
[error] 4-5: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 5-6: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 6-7: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 7-8: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 8-9: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 9-10: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 11-12: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 12-13: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 13-17: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 17-18: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 18-19: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 19-20: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 20-25: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 25-26: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 26-27: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 154-1209: Illegal use of an export declaration outside of a module
not allowed inside scripts
(parse)
packages/oracle/src/dialect.ts
[error] 16-16: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 20)
- GitHub Check: Upload install and build artifact (Node 18)
🔇 Additional comments (9)
packages/core/src/abstract-dialect/dialect.ts (3)
116-118: LGTM! Type change enables explicit opt-out.The change from
stringtofalse | stringproperly allows dialects that don't support INSERT IGNORE/DO NOTHING to explicitly declare this limitation while maintaining backward compatibility.
246-246: LGTM! New property supports dialect-specific constraint drop behavior.The
concurrentDropConstraintsproperty enables dialects like Oracle to indicate they cannot drop multiple constraints on the same table concurrently (to avoid resource contention errors).
336-337: LGTM! Safe defaults for new properties.The default values are conservative:
returnIntoValues: falseandtopLevelOrderByRequired: falsedefault to unsupportedconcurrentDropConstraints: trueassumes concurrent operations are safe by defaultDialects can override these as needed.
Also applies to: 473-473
packages/oracle/src/dialect.ts (6)
18-21: LGTM! Numeric options correctly configured for Oracle.Oracle supports unsigned integers but not zerofill, which is correctly reflected in this configuration.
24-79: LGTM! Comprehensive dialect capabilities declaration.The
supportsconfiguration correctly declares Oracle's capabilities, including proper usage of the new core dialect properties (returnIntoValues,topLevelOrderByRequired,concurrentDropConstraints).
113-115: LGTM! Bind collector correctly configured for Oracle.Using
createSpecifiedOrderedBindCollector(':')is appropriate for Oracle's named bind parameter syntax (:1,:2, etc.).
117-127: LGTM! String escaping with security validation for date functions.The special handling for
TO_TIMESTAMP_TZandTO_DATEwith validation viaassertDateprevents SQL injection while allowing Oracle date literals.
184-190: LGTM! Supported options correctly declared.The static methods properly declare that Oracle has no dialect-specific options beyond connection settings.
129-133: Based on my verification of Oracle's hex literal syntax, the current implementation is correct:In Oracle, you can use a string literal containing a hex value to insert data into a RAW column, exactly as the code does with
'${hex}'. Oracle performs an implicit cast from VARCHAR2 to RAW when needed, allowing plain quoted hex strings to work seamlessly without theXprefix.The implementation matches the actual Oracle syntax, similar to how PostgreSQL handles it. While different SQL dialects have different conventions (MSSQL uses
0x${hex}, the abstract default usesX'${hex}'), Oracle's approach with plain quoted strings is both valid and commonly used in the ecosystem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (4)
packages/oracle/src/query-generator.js (4)
1-1237: This file should be implemented in TypeScript.The coding guidelines require all new implementations to be written in TypeScript. This was already flagged in previous reviews with a comprehensive migration plan, but the file remains as JavaScript.
Based on coding guidelines.
320-322: Fix array splice bug when removing processed indexes.Splicing in forward order within the loop causes index misalignment. After the first
splice, all subsequent indices shift down, making the remaining indices inidxToDeletepoint to the wrong elements.Apply this diff to fix by iterating in reverse order:
- idxToDelete.forEach(idx => { - options.indexes.splice(idx, 1); - }); + // Splice in reverse order to avoid index shifting issues + for (let i = idxToDelete.length - 1; i >= 0; i--) { + options.indexes.splice(idxToDelete[i], 1); + }
713-720: Fix auto-increment detection to validate across all rows.
allColumns[key]is overwritten for each row, so it only reflects the last row's value. A mix ofnulland non-nullvalues for an auto-increment column is only detected when the last row isnull. If the last row is non-null, the mix passes silently.Apply this diff to track both states and enforce the invariant:
+ const sawNull = {}; + const sawNonNull = {}; + for (const fieldValueHash of fieldValueHashes) { forOwn(fieldValueHash, (value, key) => { - allColumns[key] = - fieldMappedAttributes[key] && - fieldMappedAttributes[key].autoIncrement === true && - value === null; + if (!fieldMappedAttributes[key]?.autoIncrement) { + allColumns[key] = false; + return; + } + + const isNull = value === null; + sawNull[key] ||= isNull; + sawNonNull[key] ||= !isNull; + + if (sawNull[key] && sawNonNull[key]) { + throw new Error( + 'For an auto-increment column either all rows must be null or non-null; a mix is not allowed.', + ); + } + + allColumns[key] = sawNull[key]; }); }
921-922: Fix unreachable DOUBLE condition.Line 921 compares
attribute.type === 'DOUBLE'against a string, butattribute.typeis a DataType class instance. This condition is unreachable dead code.Apply this diff to use instanceof check (consistent with ENUM at line 893, JSON at line 905, and BOOLEAN at line 912):
- } else if (attribute.autoIncrement) { + if (attribute.autoIncrement) { template = ' NUMBER(*,0) GENERATED BY DEFAULT ON NULL AS IDENTITY'; - } else if (attribute.type && attribute.type === 'DOUBLE') { - template = attribute.type.toSql(); - } else if (attribute.type) { + } else if (attribute.type instanceof DataTypes.DOUBLE) { + template = attribute.type.toSql(); + } else if (attribute.type) {
🧹 Nitpick comments (5)
packages/oracle/src/query-generator.js (2)
436-443: Remove commented-out code.Commented-out code should be removed and tracked in version control history instead. If this implementation is needed later, add a TODO comment with context.
Apply this diff:
- // addConstraintQuery(tableName, options) { - // options = options || {}; - - // const constraintSnippet = this.getConstraintSnippet(tableName, options); - - // tableName = this.quoteTable(tableName); - // return `ALTER TABLE ${tableName} ADD ${constraintSnippet};`; - // } - addColumnQuery(table, key, dataType, options) {
1060-1102: Remove large commented-out code block.This 42-line commented-out implementation should be removed. If the functionality is needed, create a TODO comment with an issue reference.
Apply this diff:
- // handleSequelizeMethod(smth, tableName, factory, options, prepend) { - // let str; - // if (smth instanceof Utils.Json) { - // // Parse nested object - // if (smth.conditions) { - // const conditions = this.parseConditionObject(smth.conditions).map(condition => - // `${this.jsonPathExtractionQuery(condition.path[0], _.tail(condition.path))} = '${condition.value}'` - // ); - // - // return conditions.join(' AND '); - // } - // if (smth.path) { - // - // // Allow specifying conditions using the sqlite json functions - // if (this._checkValidJsonStatement(smth.path)) { - // str = smth.path; - // } else { - // // Also support json property accessors - // const paths = _.toPath(smth.path); - // const column = paths.shift(); - // str = this.jsonPathExtractionQuery(column, paths); - // } - // if (smth.value) { - // str += util.format(' = %s', this.escape(smth.value)); - // } - // - // return str; - // } - // } - // if (smth instanceof Utils.Cast) { - // if (smth.val instanceof Utils.SequelizeMethod) { - // str = this.handleSequelizeMethod(smth.val, tableName, factory, options, prepend); - // if (smth.type === 'boolean') { - // str = `(CASE WHEN ${str}='true' THEN 1 ELSE 0 END)`; - // return `CAST(${str} AS NUMBER)`; - // } if (smth.type === 'timestamptz' && /json_value\(/.test(str)) { - // str = str.slice(0, -1); - // return `${str} RETURNING TIMESTAMP WITH TIME ZONE)`; - // } - // } - // } - // return super.handleSequelizeMethod(smth, tableName, factory, options, prepend); - // } - _checkValidJsonStatement(stmt) {packages/oracle/src/query-interface.d.ts (1)
1-8: Consider adding explicitupsertmethod typing to the type declaration file.The type file inherits the
upsertmethod fromAbstractQueryInterfacethrough the empty class body, which is technically correct. However, since the implementation file contains custom Oracle-specificupsertlogic (handlingupsertKeys, constraints, and unique indexes), explicitly declaring the method signature in the.d.tsfile would improve type clarity and IDE support for library consumers:async upsert( tableName: string | { tableName: string }, insertValues: object, updateValues: object, where: object, options: object ): Promise<boolean | number | undefined>;This makes the contract explicit and improves discoverability of the Oracle dialect's
upsertbehavior.packages/core/test/integration/model.test.js (1)
475-667: Oracle index expectations look consistent, but test is position‑sensitiveThe new Oracle branch that assigns
idx1 = args[1],idx2 = args[2],idx3 = args[3]and asserts only onfields(nottype) matches how Oracle is expected to surface these indexes (1 composite + 2 single‑column). This is consistent with the rest of the suite.The only downside is the usual brittleness around relying on
args[N]ordering. If Oracle ever changes index ordering (e.g., by name), this test could break even though behavior is correct. Long‑term, consider locating indexes byname(e.g., viaargs.find(idx => idx.name === 'a_b_uniq')) instead of array position, similar to what you already do in some other tests.packages/core/test/unit/sql/update.test.js (1)
90-90: Remove redundant Oracle expectation.The Oracle expectation is identical to the default expectation after quote character substitution. Per the comment at line 10, the expectsql helper automatically replaces
[]with dialect-specific quote characters (double quotes for Oracle). Adding an explicit Oracle expectation here is redundant and increases maintenance overhead without providing value.Apply this diff to remove the redundant line:
db2: 'SELECT * FROM FINAL TABLE (UPDATE "users" SET "user_name"=$sequelize_1 WHERE "id" = $sequelize_2);', snowflake: 'UPDATE "users" SET "user_name"=$sequelize_1 WHERE "id" = $sequelize_2', - oracle: `UPDATE "users" SET "user_name"=$sequelize_1 WHERE "id" = $sequelize_2`, default: 'UPDATE `users` SET `user_name`=$sequelize_1 WHERE `id` = $sequelize_2',Note: This addresses the past review comment asking "What's the difference with the default?"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (6)
packages/core/test/integration/model.test.js(9 hunks)packages/core/test/unit/query-generator/version-query.test.ts(1 hunks)packages/core/test/unit/sql/update.test.js(2 hunks)packages/oracle/src/query-generator.js(1 hunks)packages/oracle/src/query-interface.d.ts(1 hunks)packages/oracle/src/query-interface.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
packages/**/test/**/*.test.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Name integration tests with the .test.js suffix
Files:
packages/core/test/unit/sql/update.test.jspackages/core/test/integration/model.test.js
packages/**/test/**/*.test.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/test/**/*.test.{js,ts}: Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Use beforeEach/afterEach to sync with { force: true } and close Sequelize instances in tests
In tests, skip unsupported behavior with dialect.supports.featureName checks
Files:
packages/core/test/unit/sql/update.test.jspackages/core/test/integration/model.test.jspackages/core/test/unit/query-generator/version-query.test.ts
packages/*/src/query-generator.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Files:
packages/oracle/src/query-generator.js
packages/**/src/**/*.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write all new implementations in TypeScript; avoid creating new .js files in src
Files:
packages/oracle/src/query-generator.jspackages/oracle/src/query-interface.js
packages/**/src/**/query-generator.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
When modifying query generation, update both the base query generator and all dialect-specific implementations
Files:
packages/oracle/src/query-generator.js
packages/*/src/query-interface.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
Files:
packages/oracle/src/query-interface.js
packages/**/test/**/*.test.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Name unit tests with the .test.ts suffix
Files:
packages/core/test/unit/query-generator/version-query.test.ts
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
Applied to files:
packages/oracle/src/query-interface.d.tspackages/core/test/unit/sql/update.test.jspackages/oracle/src/query-generator.jspackages/oracle/src/query-interface.jspackages/core/test/unit/query-generator/version-query.test.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Applied to files:
packages/oracle/src/query-interface.d.tspackages/core/test/unit/sql/update.test.jspackages/core/test/integration/model.test.jspackages/oracle/src/query-generator.jspackages/oracle/src/query-interface.jspackages/core/test/unit/query-generator/version-query.test.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/query-generator.{js,ts} : When modifying query generation, update both the base query generator and all dialect-specific implementations
Applied to files:
packages/oracle/src/query-interface.d.tspackages/core/test/unit/sql/update.test.jspackages/core/test/integration/model.test.jspackages/oracle/src/query-generator.jspackages/oracle/src/query-interface.jspackages/core/test/unit/query-generator/version-query.test.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/dialect.ts : When adding a dialect feature, update packages/{dialect}/src/dialect.ts to declare feature support flags
Applied to files:
packages/oracle/src/query-interface.d.tspackages/core/test/integration/model.test.jspackages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Applied to files:
packages/core/test/integration/model.test.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : In tests, skip unsupported behavior with dialect.supports.featureName checks
Applied to files:
packages/core/test/integration/model.test.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Co-locate TypeScript type definitions with their implementation files
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/*.js : Write all new implementations in TypeScript; avoid creating new .js files in src
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-11-08T03:05:56.951Z
Learnt from: SippieCup
Repo: sequelize/sequelize PR: 18051
File: packages/core/src/utils/undot.ts:177-177
Timestamp: 2025-11-08T03:05:56.951Z
Learning: In packages/core/src/utils/undot.ts, the defensive check "if (!Array.isArray(obj))" before numeric leaf assignment in setByPathArray is intentional to handle edge cases where table aliases or oddly-named columns produce single-segment numeric keys (e.g., "0").
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Prefer TypeScript for all new code; only modify existing .js files when necessary
Applied to files:
packages/oracle/src/query-generator.js
🧬 Code graph analysis (3)
packages/oracle/src/query-interface.d.ts (2)
packages/oracle/src/query-interface.js (1)
OracleQueryInterface(9-92)packages/oracle/src/dialect.ts (1)
OracleDialect(23-191)
packages/oracle/src/query-generator.js (6)
packages/oracle/src/query-generator-typescript.internal.ts (1)
OracleQueryGeneratorTypeScript(34-409)packages/core/src/abstract-dialect/query-generator-typescript.ts (2)
options(192-194)quoteIdentifier(703-705)packages/core/src/utils/check.ts (1)
rejectInvalidOptions(33-54)packages/core/src/abstract-dialect/query-generator.js (5)
CREATE_TABLE_QUERY_SUPPORTABLE_OPTIONS(43-51)CREATE_TABLE_QUERY_SUPPORTABLE_OPTIONS(43-51)ADD_COLUMN_QUERY_SUPPORTABLE_OPTIONS(52-52)ADD_COLUMN_QUERY_SUPPORTABLE_OPTIONS(52-52)DataTypes(38-38)packages/core/src/utils/object.ts (2)
EMPTY_SET(16-16)getObjectFromMap(227-237)packages/core/src/utils/query-builder-utils.ts (1)
defaultValueSchemable(15-35)
packages/oracle/src/query-interface.js (3)
packages/oracle/src/query-interface.d.ts (1)
OracleQueryInterface(6-8)packages/core/src/model-typescript.ts (2)
primaryKeys(140-150)uniqueKeys(352-384)packages/core/src/utils/sql.ts (1)
assertNoReservedBind(437-449)
🪛 Biome (2.1.2)
packages/oracle/src/query-generator.js
[error] 4-5: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 5-6: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 6-7: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 7-8: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 8-9: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 9-10: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 11-12: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 12-13: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 13-17: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 17-18: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 18-19: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 19-20: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 20-25: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 25-26: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 26-27: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 154-1232: Illegal use of an export declaration outside of a module
not allowed inside scripts
(parse)
packages/oracle/src/query-interface.js
[error] 2-3: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 3-4: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 8-92: Illegal use of an export declaration outside of a module
not allowed inside scripts
(parse)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 20)
- GitHub Check: Upload install and build artifact (Node 18)
🔇 Additional comments (8)
packages/oracle/src/query-interface.js (2)
46-52: Verify the logic for falling back to primary keys.The condition at lines 47-49 falls back to using primary keys as upsertKeys when:
- No unique constraint is available, OR
- The update data contains any primary key field
The second condition (
intersection(options.updateOnDuplicate, primaryKeys).length) seems counterintuitive. Why should updating a primary key field force the use of primary keys as the upsert constraint?Please verify this is the intended Oracle upsert behavior. If this logic is specific to Oracle's MERGE statement requirements, consider adding a comment explaining why.
76-91: LGTM: SQL generation and execution logic is sound.The handling of bind parameters (lines 86-88) correctly prevents conflicts by clearing
options.bindwhensql.bindis present. The shallow copy of options at line 15 ensures this doesn't affect the caller's original options object.packages/core/test/integration/model.test.js (5)
269-297: Oracle index field shape aligned with db2/mssqlAdding
case 'oracle'to share the sameshowIndexfield shape asdb2/mssql(attribute + collate + length +order: 'ASC') is consistent with the expectations you set elsewhere for Oracle indexes. No issues from this test-side change.
1022-1070: Schema describeTable logging condition correctly keeps postgres specialThe
else if (dialectName !== 'postgres')guard keeps postgres out of the SQL string assertions while letting all other dialects (including oracle & snowflake) use the default behavior, with sqlite still handled specially via theTABLE_INFOcheck. This matches the maintainer guidance about only needing a postgres special case here.
1089-1134: Oracle quoting for FK references matches ANSI‑style dialectsAdding
oraclealongsidepostgres,db2, andibmifor the foreign‑keyREFERENCES "prefix"."UserPubs" ("id")expectation is correct: Oracle uses double‑quoted schema and table identifiers in this pattern. The test change aligns with the intended quoting style.
1136-1251: Oracle schema-qualified INSERT/UPDATE SQL expectations look correctIncluding
oraclewithpostgres/db2/ibmifor:
INSERT INTO "UserPublics"(default schema),INSERT INTO "special"."UserSpecials",UPDATE "special"."UserSpecials"matches Oracle’s double‑quoted, schema‑qualified SQL style. These assertions are consistent with how other ANSI‑style dialects are handled.
1418-1436: Good: Oracle foreign‑key error case explicitly matches ORA‑00942The new
case 'oracle'branch asserting/^ORA-00942:/for an invalid referenced table cleanly documents the Oracle‑specific behavior and is in line with how other dialects are handled here.packages/core/test/unit/sql/update.test.js (1)
137-137: Oracle's UPDATE with LIMIT rownum approach is correct and intentional.The abstract query generator (packages/core/src/abstract-dialect/query-generator.js:507-516) explicitly handles Oracle UPDATE statements with LIMIT by appending
rownum <= Ndirectly to the WHERE clause. This matches the test expectation and is a valid, widely-supported Oracle pattern for limiting UPDATE operations.The design difference from DELETE (which uses a subquery pattern) is intentional: UPDATE statements evaluate the WHERE clause and apply rownum filtering directly, while DELETE requires a subquery to first identify which specific rows match before deleting them. Both approaches are correct for their respective operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (5)
packages/oracle/src/query-generator-typescript.internal.ts (2)
145-154: RemoveIF EXISTSfrom Oracle constraint drop—still not supported.Line 150 still emits
IF EXISTSwhenoptions?.ifExistsis true, but Oracle does not supportIF EXISTSinDROP CONSTRAINTclauses. This will cause a runtime SQL error (ORA-11557).Either reject
ifExistsas unsupported (validate viarejectInvalidOptionsbefore emitting SQL), or implement conditional dropping via PL/SQL (query catalog and conditionally execute DROP).
396-408: Fix transaction SQL to use Oracle syntax.Lines 397 and 407 return
'COMMIT TRANSACTION'and'ROLLBACK TRANSACTION', which are SQL Server/T-SQL forms. Oracle uses'COMMIT'and'ROLLBACK'.Since the Oracle dialect does not set
connectionTransactionMethods: true, these methods will be called and produce invalid SQL at runtime.Apply this diff:
commitTransactionQuery() { - return 'COMMIT TRANSACTION'; + return 'COMMIT'; } rollbackTransactionQuery(): string { if (this.dialect.supports.connectionTransactionMethods) { throw new Error( `rollbackTransactionQuery is not supported by the ${this.dialect.name} dialect.`, ); } - return 'ROLLBACK TRANSACTION'; + return 'ROLLBACK'; }packages/oracle/src/query-generator.js (3)
320-322: Fix array splice to avoid index shifting.Splicing
options.indexesby iteratingidxToDeletein forward order causes index misalignment. After the firstsplice, all subsequent indices shift down, making remaining indices inidxToDeletepoint to wrong elements.Apply this diff to splice in reverse order:
- idxToDelete.forEach(idx => { - options.indexes.splice(idx, 1); - }); + // Splice in reverse order to avoid index shifting + for (let i = idxToDelete.length - 1; i >= 0; i--) { + options.indexes.splice(idxToDelete[i], 1); + }
690-696: Fix auto-increment detection across multiple rows.
allColumns[key]is overwritten for each row (line 692-695), so only the last row's value is checked. A mix ofnulland non-nullvalues for an auto-increment column is only detected when the last row isnull. If the last row is non-null, the mix passes silently.Track both "sawNull" and "sawNonNull" per column and throw if both are observed.
Apply this diff:
+ const sawNull = {}; + const sawNonNull = {}; + for (const fieldValueHash of fieldValueHashes) { forOwn(fieldValueHash, (value, key) => { - allColumns[key] = - fieldMappedAttributes[key] && - fieldMappedAttributes[key].autoIncrement === true && - value === null; + if (!fieldMappedAttributes[key]?.autoIncrement) { + allColumns[key] = false; + return; + } + + const isNull = value === null; + sawNull[key] ||= isNull; + sawNonNull[key] ||= !isNull; + + if (sawNull[key] && sawNonNull[key]) { + throw new Error( + 'For an auto-increment column either all rows must be null or non-null; a mix is not allowed.', + ); + } + + allColumns[key] = sawNull[key]; }); }
898-899: Fix unreachable DOUBLE condition.Line 898 compares
attribute.type === 'DOUBLE'against a string, butattribute.typeis a DataType instance. This condition is unreachable and will never execute.Change to use
instanceof:- } else if (attribute.autoIncrement) { + if (attribute.autoIncrement) { template = ' NUMBER(*,0) GENERATED BY DEFAULT ON NULL AS IDENTITY'; - } else if (attribute.type && attribute.type === 'DOUBLE') { - template = attribute.type.toSql(); - } else if (attribute.type) { + } else if (attribute.type instanceof DataTypes.DOUBLE) { + template = attribute.type.toSql(); + } else if (attribute.type) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/oracle/src/query-generator-typescript.internal.ts(1 hunks)packages/oracle/src/query-generator.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
packages/*/src/query-generator.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Files:
packages/oracle/src/query-generator.js
packages/**/src/**/*.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write all new implementations in TypeScript; avoid creating new .js files in src
Files:
packages/oracle/src/query-generator.js
packages/**/src/**/query-generator.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
When modifying query generation, update both the base query generator and all dialect-specific implementations
Files:
packages/oracle/src/query-generator.js
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/query-generator.{js,ts} : When modifying query generation, update both the base query generator and all dialect-specific implementations
Applied to files:
packages/oracle/src/query-generator-typescript.internal.tspackages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Applied to files:
packages/oracle/src/query-generator-typescript.internal.tspackages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
Applied to files:
packages/oracle/src/query-generator-typescript.internal.tspackages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/dialect.ts : When adding a dialect feature, update packages/{dialect}/src/dialect.ts to declare feature support flags
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Co-locate TypeScript type definitions with their implementation files
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/*.js : Write all new implementations in TypeScript; avoid creating new .js files in src
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-11-08T03:05:56.951Z
Learnt from: SippieCup
Repo: sequelize/sequelize PR: 18051
File: packages/core/src/utils/undot.ts:177-177
Timestamp: 2025-11-08T03:05:56.951Z
Learning: In packages/core/src/utils/undot.ts, the defensive check "if (!Array.isArray(obj))" before numeric leaf assignment in setByPathArray is intentional to handle edge cases where table aliases or oddly-named columns produce single-segment numeric keys (e.g., "0").
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Prefer TypeScript for all new code; only modify existing .js files when necessary
Applied to files:
packages/oracle/src/query-generator.js
🧬 Code graph analysis (2)
packages/oracle/src/query-generator-typescript.internal.ts (5)
packages/oracle/src/query-generator.internal.ts (1)
OracleQueryGeneratorInternal(11-54)packages/core/src/utils/check.ts (1)
rejectInvalidOptions(33-54)packages/core/src/utils/object.ts (1)
EMPTY_SET(16-16)packages/core/src/utils/string.ts (1)
generateIndexName(72-107)packages/core/src/utils/model-utils.ts (1)
extractModelDefinition(35-45)
packages/oracle/src/query-generator.js (6)
packages/oracle/src/query-generator.d.ts (1)
OracleQueryGenerator(5-5)packages/oracle/src/query-generator-typescript.internal.ts (1)
OracleQueryGeneratorTypeScript(34-409)packages/core/src/utils/check.ts (1)
rejectInvalidOptions(33-54)packages/core/src/abstract-dialect/query-generator.js (5)
CREATE_TABLE_QUERY_SUPPORTABLE_OPTIONS(43-51)CREATE_TABLE_QUERY_SUPPORTABLE_OPTIONS(43-51)ADD_COLUMN_QUERY_SUPPORTABLE_OPTIONS(52-52)ADD_COLUMN_QUERY_SUPPORTABLE_OPTIONS(52-52)DataTypes(38-38)packages/core/src/utils/object.ts (2)
EMPTY_SET(16-16)getObjectFromMap(227-237)packages/core/src/utils/query-builder-utils.ts (1)
defaultValueSchemable(15-35)
🪛 Biome (2.1.2)
packages/oracle/src/query-generator.js
[error] 4-5: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 5-6: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 6-7: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 7-8: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 8-9: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 9-10: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 11-12: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 12-13: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 13-17: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 17-18: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 18-19: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 19-20: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 20-25: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 25-26: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 26-27: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 154-1209: Illegal use of an export declaration outside of a module
not allowed inside scripts
(parse)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 18)
- GitHub Check: Upload install and build artifact (Node 20)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (3)
packages/oracle/src/dialect.ts (3)
86-101: Address the documentation URL and minimum version mismatch.The
dataTypesDocumentationUrlpoints to Oracle Database 23 documentation, whileminimumDatabaseVersionis set to '18.0.0'. Oracle 23 introduced features not available in Oracle 18 (native JSON SQL type, SQL Domains, spatial enhancements). This mismatch may confuse users running Oracle 18 who reference the Oracle 23 documentation.Consider either:
- Updating
dataTypesDocumentationUrlto reference Oracle 18 documentation to align with the minimum version, or- Increasing
minimumDatabaseVersionto '23.0.0' if Oracle 23 features are required
109-111: CRITICAL: Fix runtime error in getDefaultSchema for non-replication setups.
getDefaultSchemawill throw a runtime error whenreplicationorwriteis undefined, which is the default for non-replication configurations. The optional chaining onusernameis evaluated only after the property access toreplication.writesucceeds, so it doesn't prevent the error.Apply this diff to safely handle both replication and non-replication configs:
getDefaultSchema(): string { - return this.sequelize.options.replication.write.username?.toUpperCase() ?? ''; + const replicationUser = this.sequelize.options.replication?.write?.username; + const directUser = this.sequelize.options.username; + + const username = replicationUser ?? directUser; + + return username?.toUpperCase() ?? ''; }
135-182: Fix typos in comments.Two minor typos remain in the validation comments:
- Line 141: "indicated y the last empty string" → "indicated by the last empty string"
- Line 146: Comment references "TIMESTAM_TZ" → should be "TIMESTAMP_TZ"
Apply this diff:
// Validate that the split result has exactly three parts (function name, parameters, and an empty string) - // and that there are no additional SQL commands after the function call (indicated y the last empty string). + // and that there are no additional SQL commands after the function call (indicated by the last empty string). if (splitVal.length !== 3 || splitVal[2] !== '') { throw new Error('Invalid SQL function call.'); // Error if function call has unexpected format } - // Extract the function name (either 'TO_TIMESTAMP_TZ' or 'TO_DATE') and the contents inside the parentheses + // Extract the function name (either 'TO_TIMESTAMP_TZ' or 'TO_DATE') and the contents inside the parentheses const functionName = splitVal[0].trim(); // Function name should be 'TO_TIMESTAMP_TZ' or 'TO_DATE'
🧹 Nitpick comments (1)
packages/oracle/src/dialect.ts (1)
16-16: Convert empty interface to type alias or add properties.The empty interface is flagged by static analysis and is equivalent to
{}. Consider using a type alias instead for clarity, or add Oracle-specific dialect options if needed.Apply this diff to convert to a type alias:
-export interface OracleDialectOptions {} +export type OracleDialectOptions = Record<string, never>;Or, if Oracle-specific options are planned, add a comment:
-export interface OracleDialectOptions {} +// TODO: Add Oracle-specific dialect options as needed +export interface OracleDialectOptions {}Based on static analysis hints.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/oracle/src/dialect.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
packages/*/src/dialect.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
When adding a dialect feature, update packages/{dialect}/src/dialect.ts to declare feature support flags
Files:
packages/oracle/src/dialect.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/query-generator.{js,ts} : When modifying query generation, update both the base query generator and all dialect-specific implementations
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Applied to files:
packages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/dialect.ts : When adding a dialect feature, update packages/{dialect}/src/dialect.ts to declare feature support flags
Applied to files:
packages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/query-generator.{js,ts} : When modifying query generation, update both the base query generator and all dialect-specific implementations
Applied to files:
packages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
Applied to files:
packages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Applied to files:
packages/oracle/src/dialect.ts
🧬 Code graph analysis (1)
packages/oracle/src/dialect.ts (4)
packages/core/src/abstract-dialect/dialect.ts (1)
SupportableNumericOptions(15-19)packages/oracle/src/connection-manager.ts (1)
OracleConnectionOptions(26-33)packages/core/src/utils/sql.ts (1)
createSpecifiedOrderedBindCollector(401-419)packages/oracle/src/_internal/connection-options.ts (1)
CONNECTION_OPTION_NAMES(75-84)
🪛 Biome (2.1.2)
packages/oracle/src/dialect.ts
[error] 16-16: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 18)
- GitHub Check: Upload install and build artifact (Node 20)
|
I'm eagerly awaiting the |
Doing another review is first on my list for this Wednesday, a release somewhere in January is possible |
WikiRik
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these should be the final comments
| constructor(sequelize: Sequelize, options: OracleDialectOptions) { | ||
| super({ | ||
| dataTypesDocumentationUrl: | ||
| 'https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Data-Types.html', | ||
| minimumDatabaseVersion: '18.4.0', | ||
| identifierDelimiter: '"', | ||
| name: 'oracle', | ||
| options, | ||
| sequelize, | ||
| dataTypeOverrides: DataTypes, | ||
| }); | ||
|
|
||
| this.connectionManager = new OracleConnectionManager(this); | ||
| this.queryGenerator = new OracleQueryGenerator(this); | ||
| this.queryInterface = new OracleQueryInterface(this); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a valid comment
| // handleSequelizeMethod(smth, tableName, factory, options, prepend) { | ||
| // let str; | ||
| // if (smth instanceof Utils.Json) { | ||
| // // Parse nested object | ||
| // if (smth.conditions) { | ||
| // const conditions = this.parseConditionObject(smth.conditions).map(condition => | ||
| // `${this.jsonPathExtractionQuery(condition.path[0], _.tail(condition.path))} = '${condition.value}'` | ||
| // ); | ||
|
|
||
| // return conditions.join(' AND '); | ||
| // } | ||
| // if (smth.path) { | ||
|
|
||
| // // Allow specifying conditions using the sqlite json functions | ||
| // if (this._checkValidJsonStatement(smth.path)) { | ||
| // str = smth.path; | ||
| // } else { | ||
| // // Also support json property accessors | ||
| // const paths = _.toPath(smth.path); | ||
| // const column = paths.shift(); | ||
| // str = this.jsonPathExtractionQuery(column, paths); | ||
| // } | ||
| // if (smth.value) { | ||
| // str += util.format(' = %s', this.escape(smth.value)); | ||
| // } | ||
|
|
||
| // return str; | ||
| // } | ||
| // } | ||
| // if (smth instanceof Utils.Cast) { | ||
| // if (smth.val instanceof Utils.SequelizeMethod) { | ||
| // str = this.handleSequelizeMethod(smth.val, tableName, factory, options, prepend); | ||
| // if (smth.type === 'boolean') { | ||
| // str = `(CASE WHEN ${str}='true' THEN 1 ELSE 0 END)`; | ||
| // return `CAST(${str} AS NUMBER)`; | ||
| // } if (smth.type === 'timestamptz' && /json_value\(/.test(str)) { | ||
| // str = str.slice(0, -1); | ||
| // return `${str} RETURNING TIMESTAMP WITH TIME ZONE)`; | ||
| // } | ||
| // } | ||
| // } | ||
| // return super.handleSequelizeMethod(smth, tableName, factory, options, prepend); | ||
| // } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be removed if it's not used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes removed it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (10)
packages/core/test/unit/query-generator/create-schema-query.test.ts (2)
16-16: Role quoting and idempotency issues remain in Oracle CREATE SCHEMA expectation.The password security concern from the previous review has been resolved (now using
IDENTIFIED EXTERNALLY). However, two issues remain:
Incorrect role quoting: Oracle predefined role names like
CONNECTshould be granted without quotes. The expectation should useGRANT CONNECT TO "mySchema"instead ofGRANT "CONNECT" TO "mySchema"(and similarly for other system privileges).Partial idempotency: The grants only execute when
NOT USER_FOUND(i.e., user newly created). If the user already exists but lacks required permissions, no grants are re-applied, potentially leaving the user in an incomplete state.These issues should be addressed in the implementation (
packages/oracle/src/query-generator-typescript.internal.ts) and the test expectation updated accordingly.
128-132: Incomplete list of invalid options for Oracle in combined options test.The Oracle expectation only lists 3 invalid options but should list 6. Based on the individual option tests:
- Line 65:
commentis only supported by Snowflake, so Oracle should reject it- Line 74:
ifNotExistsis explicitly rejected by Oracle- Line 84:
replaceis only supported by MariaDB and Snowflake, so Oracle should reject it🔎 Apply this diff to add the missing invalid options:
oracle: buildInvalidOptionReceivedError('createSchemaQuery', dialectName, [ 'authorization', 'charset', 'collate', + 'comment', + 'ifNotExists', + 'replace', ]),packages/oracle/src/query-generator-typescript.internal.ts (2)
396-408: Fix transaction SQL to use Oracle syntax.Lines 397 and 407 return T-SQL syntax (
COMMIT TRANSACTION/ROLLBACK TRANSACTION), which Oracle does not support. Oracle requiresCOMMITandROLLBACKwithout theTRANSACTIONkeyword. Since the Oracle dialect does not setconnectionTransactionMethods: true, these methods will be invoked and produce runtime SQL errors.🔎 Apply this diff to fix the SQL syntax:
commitTransactionQuery() { - return 'COMMIT TRANSACTION'; + return 'COMMIT'; } rollbackTransactionQuery(): string { if (this.dialect.supports.connectionTransactionMethods) { throw new Error( `rollbackTransactionQuery is not supported by the ${this.dialect.name} dialect.`, ); } - return 'ROLLBACK TRANSACTION'; + return 'ROLLBACK'; }
140-157:IF EXISTSinremoveConstraintQueryis still present despite being marked resolved.The past review comment flagged that Oracle does not support
IF EXISTSinDROP CONSTRAINTclauses (line 150), marked as "✅ Addressed in commit 8454ae2." However, the code still emitsIF EXISTSwhenoptions?.ifExistsis true for sys-prefixed constraints, which will cause ORA-11557 runtime errors.Either validate and reject the
ifExistsoption before building SQL, or implement PL/SQL conditional logic querying the data dictionary to check constraint existence.packages/oracle/src/query-generator.js (3)
320-322: Fix index shifting bug when splicingoptions.indexes.Splicing array elements while iterating
idxToDeletein forward order causes index misalignment. After the firstsplice, remaining indices point to wrong elements. This results in incorrect indexes being removed.🔎 Apply this diff to fix (reverse iteration):
- idxToDelete.forEach(idx => { - options.indexes.splice(idx, 1); - }); + // Splice in reverse order to avoid index shifting + for (let i = idxToDelete.length - 1; i >= 0; i--) { + options.indexes.splice(idxToDelete[i], 1); + }Or use
filterto rebuild the array:- idxToDelete.forEach(idx => { - options.indexes.splice(idx, 1); - }); + const idxSet = new Set(idxToDelete); + options.indexes = options.indexes.filter((_, idx) => !idxSet.has(idx));
898-899: Fix unreachable DOUBLE condition inattributeToSQL.Line 898 compares
attribute.type === 'DOUBLE'(strict equality with a string), butattribute.typeis a DataType class instance. This condition is unreachable dead code and inconsistent with other branches that useinstanceof(lines 870, 882, 889).🔎 Apply this diff to fix:
- } else if (attribute.type && attribute.type === 'DOUBLE') { - template = attribute.type.toSql(); + } else if (attribute.type instanceof DataTypes.DOUBLE) { + template = attribute.type.toSql();
690-696: Fix auto-increment detection to check all rows, not just the last one.The loop overwrites
allColumns[key]for each row (lines 692-695), so only the last row's value determines the final state. A mix ofnulland non-nullvalues for an auto-increment column is only detected when the last row isnull. If the last row is non-null, the mix passes silently.🔎 Apply this diff to enforce the invariant across all rows:
+ const sawNull = {}; + const sawNonNull = {}; + for (const fieldValueHash of fieldValueHashes) { forOwn(fieldValueHash, (value, key) => { - allColumns[key] = - fieldMappedAttributes[key] && - fieldMappedAttributes[key].autoIncrement === true && - value === null; + if (!fieldMappedAttributes[key]?.autoIncrement) { + allColumns[key] = false; + return; + } + + const isNull = value === null; + sawNull[key] ||= isNull; + sawNonNull[key] ||= !isNull; + + if (sawNull[key] && sawNonNull[key]) { + throw new Error( + 'For an auto-increment column either all rows must be null or non-null; a mix is not allowed.', + ); + } + + allColumns[key] = sawNull[key]; }); }packages/oracle/src/dialect.ts (3)
109-111:getDefaultSchemawill throw in non-replication setups.Line 110 accesses
this.sequelize.options.replication.write.usernamewithout safe optional chaining onreplicationorwrite. In default (non-replication) configurations,replicationorwritewill be undefined, causing a runtime error before the optional chaining onusernameis evaluated.🔎 Apply this diff to fix:
getDefaultSchema(): string { - return this.sequelize.options.replication.write.username?.toUpperCase() ?? ''; + const replicationUser = this.sequelize.options.replication?.write?.username; + const directUser = this.sequelize.options.username; + const username = replicationUser ?? directUser; + return username?.toUpperCase() ?? ''; }
88-90: Update documentation URL to match minimum database version.Line 88 links to Oracle Database 23 documentation, but line 89 declares
minimumDatabaseVersion: '18.0.0'. Oracle 23 introduced features unavailable in 18 (native JSON SQL type, SQL Domains, spatial enhancements). The documentation should align with the declared minimum version.🔎 Apply this diff:
- dataTypesDocumentationUrl: - 'https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Data-Types.html', + dataTypesDocumentationUrl: + 'https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Data-Types.html',
141-146: Fix typos in comments.Line 141: "indicated y the last empty string" should be "indicated by the last empty string"
Line 146: Comment mentions "TIMESTAM_TZ" but should be "TIMESTAMP_TZ"
🔎 Apply this diff:
// Validate that the split result has exactly three parts (function name, parameters, and an empty string) - // and that there are no additional SQL commands after the function call (indicated y the last empty string). + // and that there are no additional SQL commands after the function call (indicated by the last empty string). if (splitVal.length !== 3 || splitVal[2] !== '') { throw new Error('Invalid SQL function call.'); // Error if function call has unexpected format } - // Extract the function name (either 'TO_TIMESTAM_TZ' or 'TO_DATE') and the contents inside the parentheses + // Extract the function name (either 'TO_TIMESTAMP_TZ' or 'TO_DATE') and the contents inside the parentheses
🧹 Nitpick comments (2)
packages/core/src/abstract-dialect/dialect.ts (1)
244-247: Consider using consistent comment style.The comment uses
//inline style, while other properties inDialectSupportsuse/* */block comment style. This is a minor consistency nit.🔎 Apply this diff for consistent comment style:
dropTable: { cascade: boolean; - concurrentDropConstraints: boolean; // If Constraints on same table can be dropped concurrently. + /** Whether constraints on the same table can be dropped concurrently */ + concurrentDropConstraints: boolean; };packages/oracle/src/dialect.ts (1)
16-16: Consider using a type alias for the empty OracleDialectOptions.The empty
OracleDialectOptionsinterface is functionally equivalent to{}. While valid as a placeholder for future options, a type alias is slightly cleaner for empty definitions.🔎 Apply this diff if preferred:
-export interface OracleDialectOptions {} +export type OracleDialectOptions = Record<string, never>;Or simply:
-export interface OracleDialectOptions {} +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface OracleDialectOptions {}Based on static analysis hint from Biome.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
packages/core/src/abstract-dialect/dialect.ts(5 hunks)packages/core/test/unit/query-generator/create-schema-query.test.ts(4 hunks)packages/oracle/src/dialect.ts(1 hunks)packages/oracle/src/query-generator-typescript.internal.ts(1 hunks)packages/oracle/src/query-generator.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
packages/**/test/**/*.test.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Name unit tests with the .test.ts suffix
Files:
packages/core/test/unit/query-generator/create-schema-query.test.ts
packages/**/test/**/*.test.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/test/**/*.test.{js,ts}: Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Use beforeEach/afterEach to sync with { force: true } and close Sequelize instances in tests
In tests, skip unsupported behavior with dialect.supports.featureName checks
Files:
packages/core/test/unit/query-generator/create-schema-query.test.ts
packages/*/src/query-generator.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Files:
packages/oracle/src/query-generator.js
packages/**/src/**/*.js
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write all new implementations in TypeScript; avoid creating new .js files in src
Files:
packages/oracle/src/query-generator.js
packages/**/src/**/query-generator.{js,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
When modifying query generation, update both the base query generator and all dialect-specific implementations
Files:
packages/oracle/src/query-generator.js
packages/*/src/dialect.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
When adding a dialect feature, update packages/{dialect}/src/dialect.ts to declare feature support flags
Files:
packages/oracle/src/dialect.ts
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-interface.{js,ts} : Add schema operations for new features in query-interface.ts (preferred) or legacy query-interface.js
Applied to files:
packages/core/test/unit/query-generator/create-schema-query.test.tspackages/oracle/src/query-generator-typescript.internal.tspackages/oracle/src/query-generator.jspackages/core/src/abstract-dialect/dialect.tspackages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/query-generator.{js,ts} : When modifying query generation, update both the base query generator and all dialect-specific implementations
Applied to files:
packages/core/test/unit/query-generator/create-schema-query.test.tspackages/oracle/src/query-generator-typescript.internal.tspackages/oracle/src/query-generator.jspackages/core/src/abstract-dialect/dialect.tspackages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/query-generator.{js,ts} : Implement dialect feature SQL in query-generator.ts (preferred) or legacy query-generator.js
Applied to files:
packages/core/test/unit/query-generator/create-schema-query.test.tspackages/oracle/src/query-generator-typescript.internal.tspackages/oracle/src/query-generator.jspackages/core/src/abstract-dialect/dialect.tspackages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : In tests, skip unsupported behavior with dialect.supports.featureName checks
Applied to files:
packages/core/test/unit/query-generator/create-schema-query.test.tspackages/core/src/abstract-dialect/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/*/src/dialect.ts : When adding a dialect feature, update packages/{dialect}/src/dialect.ts to declare feature support flags
Applied to files:
packages/oracle/src/query-generator.jspackages/core/src/abstract-dialect/dialect.tspackages/oracle/src/dialect.ts
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Co-locate TypeScript type definitions with their implementation files
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/src/**/*.js : Write all new implementations in TypeScript; avoid creating new .js files in src
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-11-08T03:05:56.951Z
Learnt from: SippieCup
Repo: sequelize/sequelize PR: 18051
File: packages/core/src/utils/undot.ts:177-177
Timestamp: 2025-11-08T03:05:56.951Z
Learning: In packages/core/src/utils/undot.ts, the defensive check "if (!Array.isArray(obj))" before numeric leaf assignment in setByPathArray is intentional to handle edge cases where table aliases or oddly-named columns produce single-segment numeric keys (e.g., "0").
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Prefer TypeScript for all new code; only modify existing .js files when necessary
Applied to files:
packages/oracle/src/query-generator.js
📚 Learning: 2025-09-29T19:49:24.715Z
Learnt from: CR
Repo: sequelize/sequelize PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-29T19:49:24.715Z
Learning: Applies to packages/**/test/**/*.test.{js,ts} : Use Support.getTestDialectTeaser() for dialect-specific test descriptions
Applied to files:
packages/core/src/abstract-dialect/dialect.tspackages/oracle/src/dialect.ts
🧬 Code graph analysis (2)
packages/core/test/unit/query-generator/create-schema-query.test.ts (1)
packages/core/src/utils/check.ts (1)
buildInvalidOptionReceivedError(88-96)
packages/oracle/src/query-generator.js (3)
packages/oracle/src/query-generator-typescript.internal.ts (1)
OracleQueryGeneratorTypeScript(34-409)packages/core/src/utils/check.ts (1)
rejectInvalidOptions(33-54)packages/core/src/abstract-dialect/query-generator.js (4)
CREATE_TABLE_QUERY_SUPPORTABLE_OPTIONS(43-51)CREATE_TABLE_QUERY_SUPPORTABLE_OPTIONS(43-51)ADD_COLUMN_QUERY_SUPPORTABLE_OPTIONS(52-52)ADD_COLUMN_QUERY_SUPPORTABLE_OPTIONS(52-52)
🪛 Biome (2.1.2)
packages/oracle/src/query-generator.js
[error] 4-5: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 5-6: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 6-7: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 7-8: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 8-9: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 9-10: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 11-12: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 12-13: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 13-17: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 17-18: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 18-19: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 19-20: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 20-25: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 25-26: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 26-27: Illegal use of an import declaration outside of a module
not allowed inside scripts
(parse)
[error] 154-1165: Illegal use of an export declaration outside of a module
not allowed inside scripts
(parse)
packages/oracle/src/dialect.ts
[error] 16-16: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Upload install and build artifact (Node 18)
- GitHub Check: Upload install and build artifact (Node 20)
🔇 Additional comments (4)
packages/core/src/abstract-dialect/dialect.ts (4)
71-75: LGTM!The new
returnIntoValuesandtopLevelOrderByRequiredcapability flags are well-documented and properly typed. These additions support Oracle-specific behaviors for RETURNING INTO binds and ORDER BY requirements.
116-118: LGTM!The type expansion to
false | stringproperly models dialects that don't support ignore-duplicates semantics (Oracle, DB2, IBMi) versus those that use dialect-specific keywords.
336-337: LGTM!Default values of
falsefor both properties are appropriate, requiring Oracle (and any other dialect needing these features) to explicitly opt-in.
471-474: LGTM!Defaulting
concurrentDropConstraints: truemaintains backward compatibility for existing dialects while allowing Oracle to override this tofalsein its dialect implementation.
Thanks. I have addressed all the comments. |
Pull Request Checklist
Description of Changes
This change fixes CI issues on top of PR #17403.
Major updates:
Oracle upsert:
The Oracle dialect generates both
updateQueryandinsertQuery, combining them into a single PL/SQL block with binds.To ensure bind numbering continues correctly between the two queries,
createBindParamGeneratorwas updated to accept the dialect parameter and continue numbering based onObject.keys(bind).length.Oracle bulkInsert:
Skips mapBindParameters and bind generation since Oracle uses an array of arrays for multi-row bind batches.
ignoreDuplicates dialect supports option is enhanced to include
falseas valid value for dialects not supporting it.ignoreDuplicates:
| false /* Not supported /
| string / dialect specific words for INSERT IGNORE or DO NOTHING */;
Ex:
MariaDb: ' IGNORE' → string .
Postgres: '' → string
Oracle, db2, ibmi: false → Not supported.
updateOnDuplicate:
updateOnDuplicate: '', is set for ibmi so that dialect.supports.inserts.updateOnDuplicate can be used
Unit tests:
Updated to use $sequelize_1, $sequelize_2, ... placeholders to match the positional bind style used in SQL generation.
Miscellaneous:
Updated copyright year.
List of Breaking Changes
Summary by CodeRabbit
New Features
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.