Skip to content
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

feat(ibmi): add database version compatibility check for native boolean + initial unit tests #16909

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

rcronin
Copy link
Contributor

@rcronin rcronin commented Dec 29, 2023

Pull Request Checklist

  • Have you added new tests to prevent regressions?
  • If a documentation update is necessary, have you opened a PR to the documentation repository?
  • Did you update the typescript typings accordingly (if applicable)?
  • Does the description below contain a link to an existing issue (Closes #[issue]) or a description of the issue you are solving?
  • Does the name of your PR follow our conventions?

Description Of Change

Added a check within data-types.js for the IBM i dialect to check the database version. If it's the latest known version, it implements the base boolean support, which handles booleans properly within javascript and back to the database. Also copied the DB2 unit tests as a start for IBM i unit testing.

Todos

@WikiRik
Copy link
Member

WikiRik commented Dec 29, 2023

Don't worry about the failing artifact download actions, that's a known flaky thing in the new version of the action. I can just rerun the checks if needed but you should be good if unit tests pass.

@rcronin
Copy link
Contributor Author

rcronin commented Dec 29, 2023

@WikiRik sounds good. This is ready to review

@rcronin
Copy link
Contributor Author

rcronin commented Jan 16, 2024

@WikiRik - any update on when this may get reviewed/merged?

Copy link
Member

@WikiRik WikiRik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add some unit tests that simulate ibmi 7.5.0 (or higher)? You can just do something similar as here;

it('supports sql.uuidV4 default values', async () => {
const localSequelize = dialect.name === 'postgres'
? createSequelizeInstance({
databaseVersion: '13.0.0',
})
: sequelize;
const stub = sinon.stub(localSequelize, 'queryRaw');
await localSequelize.queryInterface.createTable('table', {
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: sql.uuidV4,
},
});
expect(stub.callCount).to.eq(1);
const firstCall = stub.getCall(0);
expectsql(firstCall.args[0], {
postgres: 'CREATE TABLE IF NOT EXISTS "table" ("id" UUID DEFAULT gen_random_uuid(), PRIMARY KEY ("id"));',
'mariadb mysql': 'CREATE TABLE IF NOT EXISTS `table` (`id` CHAR(36) BINARY, PRIMARY KEY (`id`)) ENGINE=InnoDB;',
mssql: `IF OBJECT_ID(N'[table]', 'U') IS NULL CREATE TABLE [table] ([id] UNIQUEIDENTIFIER DEFAULT NEWID(), PRIMARY KEY ([id]));`,
sqlite: 'CREATE TABLE IF NOT EXISTS `table` (`id` TEXT PRIMARY KEY);',
snowflake: 'CREATE TABLE IF NOT EXISTS "table" ("id" VARCHAR(36), PRIMARY KEY ("id"));',
db2: 'CREATE TABLE IF NOT EXISTS "table" ("id" CHAR(36) FOR BIT DATA NOT NULL, PRIMARY KEY ("id"));',
ibmi: `BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE VALUE '42710' BEGIN END; CREATE TABLE "table" ("id" CHAR(36), PRIMARY KEY ("id")); END`,
});
});
if (dialect.name === 'postgres') {
// gen_random_uuid was added in postgres 13
it('supports sql.uuidV4 default values (postgres < 13)', async () => {
const localSequelize = createSequelizeInstance({
databaseVersion: '12.0.0',
});
const stub = sinon.stub(localSequelize, 'queryRaw');
await localSequelize.queryInterface.createTable('table', {
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: sql.uuidV4,
},
});
expect(stub.callCount).to.eq(1);
const firstCall = stub.getCall(0);
expectsql(firstCall.args[0], {
postgres: 'CREATE TABLE IF NOT EXISTS "table" ("id" UUID DEFAULT uuid_generate_v4(), PRIMARY KEY ("id"));',
});
});
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason that this file was not added originally is that we're reducing the amount of dialect specific tests and are moving this per function to separate files. But seeing as we're still in the process of doing that I can see some benefit in having this file so I can go either way. @ephys do you have a strong opinion on this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functions being tested in this new file already have common test files, so I don't want to approve this file. The new tests should be added to the new files instead, if they're relevant

@@ -20,8 +20,7 @@ describe('QueryGenerator#bulkInsertQuery', () => {
expectsql(sql, {
default: `INSERT INTO [Users] ([firstName]) VALUES ('a string');`,
mssql: `INSERT INTO [Users] ([firstName]) VALUES (N'a string');`,
// TODO: ibmi should be the same as `default`, since the 'returning' option is not specified
ibmi: `SELECT * FROM FINAL TABLE (INSERT INTO "Users" ("firstName") VALUES ('a string'))`,
ibmi: `INSERT INTO "Users" ("firstName") VALUES ('a string')`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work now

Suggested change
ibmi: `INSERT INTO "Users" ("firstName") VALUES ('a string')`,

@@ -24,7 +24,7 @@ describe('QueryInterface#bulkInsert', () => {

expectPerDialect(() => firstCall, {
default: toMatchRegex(/^INSERT INTO (?:`|")Users(?:`|") \((?:`|")firstName(?:`|")\) VALUES (?:\('\w+'\),){999}\('\w+'\);$/),
ibmi: toMatchRegex(/^SELECT \* FROM FINAL TABLE \(INSERT INTO "Users" \("firstName"\) VALUES (?:\('\w+'\),){999}\('\w+'\)\)$/),
ibmi: toMatchRegex(/^INSERT INTO "Users" \("firstName"\) VALUES (?:\('\w+'\),){999}\('\w+'\)$/),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ibmi: toMatchRegex(/^INSERT INTO "Users" \("firstName"\) VALUES (?:\('\w+'\),){999}\('\w+'\)$/),

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that the custom expectations in the other changed tests can be removed

Comment on lines +12 to +15
const databaseVersion
= Number.parseFloat(this._getDialect().sequelize.options.databaseVersion || this._getDialect().defaultVersion);

return databaseVersion >= 7.5;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use the gt function from semver to compare this to getDatabaseVersion()

@@ -96,5 +96,6 @@ export const Config: Record<Dialect, Options> = {
dialectOptions: {
odbcConnectionString: env.SEQ_IBMI_CONN_STR,
},
databaseVersion: '7.3.0',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
databaseVersion: '7.3.0',

ibmi has a defaultVersion of 7.3.0 already

@@ -8,16 +8,27 @@ export class UUID extends BaseTypes.UUID {
}

export class BOOLEAN extends BaseTypes.BOOLEAN {
protected supportsNativeBooleans() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be hard private

@@ -8,16 +8,27 @@ export class UUID extends BaseTypes.UUID {
}

export class BOOLEAN extends BaseTypes.BOOLEAN {
protected supportsNativeBooleans() {
const databaseVersion
= Number.parseFloat(this._getDialect().sequelize.options.databaseVersion || this._getDialect().defaultVersion);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't get the database version like this, but via sequelize.getDatabaseVersion()

@@ -356,7 +355,6 @@ export class IBMiQueryGenerator extends IBMiQueryGeneratorTypeScript {
let query = super.bulkInsertQuery(tableName, fieldValueHashes, options, fieldMappedAttributes);
if (query.at(-1) === ';') {
query = query.slice(0, -1);
query = `SELECT * FROM FINAL TABLE (${query})`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove the "select from final table"? :o

@rcronin rcronin requested a review from a team as a code owner March 18, 2024 23:04
@rcronin rcronin requested review from ephys and WikiRik and removed request for a team March 18, 2024 23:04
@sequelize-bot sequelize-bot bot added the conflicted This PR has merge conflicts and will not be present in the list of PRs to review label Apr 10, 2024
@rcronin
Copy link
Contributor Author

rcronin commented Apr 17, 2024

Finally circling back to this. To implement with the dialect being split out, how should I approach this pull request? Throw out and redo it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
conflicted This PR has merge conflicts and will not be present in the list of PRs to review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants