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: Add Cockroachdb support without transactions #16394

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

Conversation

divye11
Copy link

@divye11 divye11 commented Aug 17, 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

Todos

  • Implement a util function to add ids to objects where we add ...(dialect === 'cockroachdb' && { id: 1 })

divye11 and others added 30 commits December 7, 2022 00:03
…t and overrid postgres helpers for cockroachDB
@divye11 divye11 marked this pull request as draft August 17, 2023 17:36
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.

I just have a few more files that I need to check out in the cockroachdb folder but it looks very good to me. In the end it's not too many tests that add an id, but adding a util function for it in the future might be nice. Not for this PR imo.

@@ -233,6 +236,7 @@ We use a simple conventional commits convention:
- `db2`
- `ibmi`
- `snowflake`
- `cockroachdb`
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 added to the scopes in .github/workflows/pr-title.yml as well

Comment on lines 30 to 32
it(util.inspect(options, { depth: 2 }), () => {

return expectsql(
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
it(util.inspect(options, { depth: 2 }), () => {
return expectsql(
it(util.inspect(options, { depth: 2 }), () => {
return expectsql(

const dialectName = Support.getTestDialect();
const current = Support.sequelize;
const sql = current.dialect.queryGenerator;
const dialectName = Support.getTestDialect();
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
const dialectName = Support.getTestDialect();

@@ -71,7 +71,7 @@ describe('json', () => {

Copy link
Member

Choose a reason for hiding this comment

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

The two tests above should produce the same result for cockroachdb as well right? You can add those already

Comment on lines 345 to 352
default: `SELECT [user].*, [POSTS].[id] AS [POSTS.id], [POSTS].[title] AS [POSTS.title] FROM (SELECT [user].[id_user] AS [id], [user].[email], [user].[first_name] AS [firstName], [user].[last_name] AS [lastName] FROM [users] AS [user] ORDER BY [user].${TICK_LEFT}${TICK_LEFT}${TICK_LEFT}last_name${TICK_RIGHT}${TICK_RIGHT}${TICK_RIGHT} ASC${sql.addLimitAndOffset({
limit: 30,
offset: 10,
order: [['`user`.`last_name`', 'ASC']],
})
}) AS [user] LEFT OUTER JOIN [post] AS [POSTS] ON [user].[id_user] = [POSTS].[user_id] ORDER BY [user].${TICK_LEFT}${TICK_LEFT}${TICK_LEFT}last_name${TICK_RIGHT}${TICK_RIGHT}${TICK_RIGHT} ASC;`,
ibmi: `${`SELECT "user".*, "POSTS"."id" AS "POSTS.id", "POSTS"."title" AS "POSTS.title" FROM (SELECT "user"."id_user" AS "id", "user"."email", "user"."first_name" AS "firstName", "user"."last_name" AS "lastName" FROM "users" AS "user" ORDER BY "user"."""last_name""" ASC`}${
sql.addLimitAndOffset({ limit: 30, offset: 10, order: [['`user`.`last_name`', 'ASC']] })
ibmi: `${`SELECT "user".*, "POSTS"."id" AS "POSTS.id", "POSTS"."title" AS "POSTS.title" FROM (SELECT "user"."id_user" AS "id", "user"."email", "user"."first_name" AS "firstName", "user"."last_name" AS "lastName" FROM "users" AS "user" ORDER BY "user"."""last_name""" ASC`}${sql.addLimitAndOffset({ limit: 30, offset: 10, order: [['`user`.`last_name`', 'ASC']] })
}) AS "user" LEFT OUTER JOIN "post" AS "POSTS" ON "user"."id_user" = "POSTS"."user_id" ORDER BY "user"."""last_name""" ASC`,
Copy link
Member

Choose a reason for hiding this comment

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

Could you undo the changes to these lines?

@@ -849,7 +855,11 @@ describe(Support.getTestDialectTeaser('Model'), () => {
await User.sync({ force: true });
const user = await User.create({}, { returning: true });
expect(user.get('id')).to.be.ok;
expect(user.get('id')).to.equal(1);

// This test expects the ID to be 1 but in CockroachDB uses UUIDv4 to generate IDs.
Copy link
Member

Choose a reason for hiding this comment

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

Is there a different expectation we can add instead?

Copy link
Author

Choose a reason for hiding this comment

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

We could manually add id = 1 for the record or fetch the record ID and compare if needed, but seemed redundant.
Let me know your thoughts @WikiRik


await userWithDefaults.sync({ force: true });
const user = await userWithDefaults.create({});
// uuid validation regex taken from http://stackoverflow.com/a/13653180/800016
Copy link
Member

Choose a reason for hiding this comment

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

You can use the isUUID validator for this

expect(user2).to.not.be.null;
await t.rollback();
});

// Disabled in sqlite because it only supports one connection at a time
// Disabled in sqlite and cockroachdb because it only supports one connection at a time
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
// Disabled in sqlite and cockroachdb because it only supports one connection at a time
// Disabled in sqlite and partially for cockroachdb because it only supports one connection at a time

Comment on lines 8 to 9

const dialectName = Support.getTestDialect();
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
const dialectName = Support.getTestDialect();

@@ -570,8 +576,8 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => {
this.User = this.sequelize.define('users', {
Copy link
Member

Choose a reason for hiding this comment

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

I'll review the tests below here after you've resolved the conflicts with the main branch

@rafiss
Copy link
Contributor

rafiss commented Nov 24, 2023

@WikiRik Hi! CockroachDB developer here - do you know if this PR is able to get reviewed?

@divye11 divye11 marked this pull request as ready for review January 30, 2024 11:11
@WikiRik WikiRik requested a review from ephys January 30, 2024 15:39
@divye11 divye11 requested a review from WikiRik February 2, 2024 07:45
@WikiRik
Copy link
Member

WikiRik commented Mar 15, 2024

@divye11 are you able to resolve the merge conflicts so we can take another look at this?

@divye11 divye11 requested a review from a team as a code owner March 18, 2024 23:04
Copy link
Member

@ephys ephys left a comment

Choose a reason for hiding this comment

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

Thank you for your work!

I have reviewed the source code part. I will be reviewing the tests next

Comment on lines +20 to +21
ALTER RANGE default CONFIGURE ZONE USING "gc.ttlseconds" = 600;
ALTER DATABASE system CONFIGURE ZONE USING "gc.ttlseconds" = 600;
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
ALTER RANGE default CONFIGURE ZONE USING "gc.ttlseconds" = 600;
ALTER DATABASE system CONFIGURE ZONE USING "gc.ttlseconds" = 600;
ALTER RANGE default CONFIGURE ZONE USING \"gc.ttlseconds\" = 600;
ALTER DATABASE system CONFIGURE ZONE USING \"gc.ttlseconds\" = 600;

for https://github.com/koalaman/shellcheck/wiki/SC2140

Comment on lines +20 to +21
ALTER RANGE default CONFIGURE ZONE USING "gc.ttlseconds" = 600;
ALTER DATABASE system CONFIGURE ZONE USING "gc.ttlseconds" = 600;
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
ALTER RANGE default CONFIGURE ZONE USING "gc.ttlseconds" = 600;
ALTER DATABASE system CONFIGURE ZONE USING "gc.ttlseconds" = 600;
ALTER RANGE default CONFIGURE ZONE USING \"gc.ttlseconds\" = 600;
ALTER DATABASE system CONFIGURE ZONE USING \"gc.ttlseconds\" = 600;


export class INTEGER extends PostgresInteger {
sanitize(value: number): unknown {
if (value > Number.MAX_SAFE_INTEGER) {
Copy link
Member

Choose a reason for hiding this comment

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

If the value is > MAX_SAFE_INTEGER, it is already not reliable and should not be converted. This should throw an error

As that is already what BaseIntegerDataType does, there are no changes needed here, you can just re-export PostgresInteger as INTEGER

import type { AbstractDataType, AcceptableTypeOf, ArrayOptions, BindParamOptions, DataType } from '../abstract/data-types';
import * as BaseTypes from '../abstract/data-types';
import { attributeTypeToSql } from '../abstract/data-types-utils';
import { ARRAY as PostgresArray, GEOGRAPHY as PostgresGeography, INTEGER as PostgresInteger } from '../postgres/data-types';
Copy link
Member

Choose a reason for hiding this comment

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

Now that postgres has been moved to its own package, you will need to add an exports config to postgres similar to what is done in core to access the internals (the _non-semver-use-at-your-own-risk_ export)

Comment on lines +36 to +42
} else if (this.options.type instanceof BaseTypes.HSTORE) {
ValidationErrorItem.throwDataTypeValidationError('cockroachdb does not support the HSTORE data type.\n See https://www.cockroachlabs.com/docs/stable/data-types/ for a list of supported data types.');
} else if (this.options.type instanceof BaseTypes.UUID) {
ValidationErrorItem.throwDataTypeValidationError('cockroachdb does not support the UUID data type.\n See https://www.cockroachlabs.com/docs/stable/data-types/ for a list of supported data types.');
} else if (this.options.type instanceof BaseTypes.CITEXT) {
ValidationErrorItem.throwDataTypeValidationError('cockroachdb does not support the CITEXT data type.\n See https://www.cockroachlabs.com/docs/stable/data-types/ for a list of supported data types.');
}
Copy link
Member

Choose a reason for hiding this comment

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

These error messages are redundant, as the types themselves will throw if they are not supported

The relevant support options to set to make them throw are:

  • supports.dataTypes.HSTORE
  • supports.dataTypes.CITEXT

Note that there is not one for UUID, as all dialects should support it (with a fallback to a binary field or text when not available). From the documentation you linked, it looks like cockroach does support UUID though

The error message about nested array is fine though, as it's an interaction between this type and its subtype

]);
}

getUuidV1FunctionCall(): string {
Copy link
Member

Choose a reason for hiding this comment

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

getUuidV4FunctionCall is fine as it has a different implementation, but getUuidV1FunctionCall is the same implementation so this method can be removed

try {
await super.removeConstraint(tableName, constraintName, options);
} catch (error: any) {
if (error.message.includes('use DROP INDEX CASCADE instead')) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think the code should try to correct for this. It should alert the user, and the user should then use the cascade option themselves, that option is already supported in RemoveConstraintQueryOptions

@@ -57,7 +58,7 @@ export class PostgresConnectionManager extends AbstractConnectionManager<PgConne
#oidMap = new Map<number, TypeOids>();
#oidParserCache = new Map<number, TypeParser<any, any>>();

constructor(dialect: PostgresDialect, sequelize: Sequelize) {
constructor(dialect: PostgresDialect | CockroachDbDialect, sequelize: Sequelize) {
Copy link
Member

Choose a reason for hiding this comment

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

the postgres connection manager cannot have a direct reference to cockroachdb, it will create an package loop between @sequelize/postgres and @sequelize/cockroachdb.

After the merge of main in this PR, we can look into how this can be solved. I think the solution would be to have CockroachDbDialect extend PostgresDialect, but that may require moving some init code somehow

@@ -857,7 +857,7 @@ ${associationOwner._getAssociationDebugList()}`);
const missingIndexes = this.getIndexes()
.filter(item1 => !existingIndexes.some(item2 => item1.name === item2.name))
.sort((index1, index2) => {
if (this.sequelize.options.dialect === 'postgres') {
if (this.sequelize.options.dialect === 'postgres' || this.sequelize.options.dialect === 'cockroachdb') {
Copy link
Member

Choose a reason for hiding this comment

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

Following merge of main in this PR, keep in mind that this.sequelize.options.dialect should not be used anymore. Use this.sequelize.dialect.name instead

import forOwn from 'lodash/forOwn';
import isEqual from 'lodash/isEqual';

const debug = logger.debugContext('sql:pg');
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
const debug = logger.debugContext('sql:pg');
const debug = logger.debugContext('sql:cockroachdb');

@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
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

4 participants