Skip to content

feat: slonik major upgrade#7897

Draft
n1ru4l wants to merge 7 commits intocopilot/update-slonik-connection-usagefrom
feat-upgrade-slonik
Draft

feat: slonik major upgrade#7897
n1ru4l wants to merge 7 commits intocopilot/update-slonik-connection-usagefrom
feat-upgrade-slonik

Conversation

@n1ru4l
Copy link
Contributor

@n1ru4l n1ru4l commented Mar 23, 2026

Background

Major slonik upgrade on top of #7887

Description

Checklist

  • Input validation
  • Output encoding
  • Authentication management
  • Session management
  • Access control
  • Cryptographic practices
  • Error handling and logging
  • Data protection
  • Communication security
  • System configuration
  • Database security
  • File management
  • Memory management
  • Testing

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on a significant upgrade of the slonik PostgreSQL client library, bringing improved type safety and a more streamlined database interaction experience. It involves updating core database dependencies, adapting the PostgresDatabasePool to new slonik features, and refactoring the TaskScheduler to directly integrate with the updated database pool. Additionally, several Zod schemas have been adjusted to correctly parse large integer values from the database, enhancing overall data consistency.

Highlights

  • Slonik Dependency Upgrade: The slonik and slonik-interceptor-query-logging dependencies have been upgraded to their latest major versions (from 30.4.4 to 48.13.2 and 46.4.0 to 48.13.2 respectively), along with the introduction of @standard-schema/spec.
  • Enhanced Type Safety with StandardSchemaV1: The PostgresDatabasePool and psql utilities have been refactored to leverage QuerySqlToken and StandardSchemaV1 from slonik, significantly improving type inference and safety for database queries.
  • TaskScheduler Refactoring: The TaskScheduler in packages/services/workflows has been refactored to directly use the PostgresDatabasePool for job scheduling, removing its previous dependency on pg.Pool and graphile-worker's WorkerUtils.
  • BigInt Handling in Zod Schemas: Several Zod schemas across the codebase have been updated to correctly handle bigint values returned from PostgreSQL by transforming them to Number, ensuring data integrity for fields like expiresAt, createdAt, membersCount, total, limitRetentionDays, and limitOperationsMonthly.
  • Simplified psql.join Usage: The usage of psql.join has been updated to use psql.fragment for improved clarity and alignment with the new slonik API.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 23, 2026

🚀 Snapshot Release (alpha)

The latest changes of this PR are available as alpha on npm (based on the declared changesets):

Package Version Info
hive 11.0.1-alpha-20260325160931-6d64dd55a21cc9cc560650b8dfb6f33a6afc7f18 npm ↗︎ unpkg ↗︎


Object.assign(psqlFn, createSqlTag());

export const psql = psqlFn as any as SqlTag<any> & TaggedTemplateLiteralInvocation;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

By keeping the tag callable, we avoid introducing psql.unknown and transforming all existing use to use psql.unknown instead of psql.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 23, 2026

🐋 This PR was built and pushed to the following Docker images:

Targets: build

Platforms: linux/amd64

Image Tag: 6e7815a0ada8defac078cddc2c470191486894e0

SELECT id, user_id
FROM organizations
WHERE id IN (${psql.join(organizations, psql`, `)})`,
WHERE id IN (${psql.join(organizations, psql.fragment`, `)})`,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This changed and needed a few updates.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request updates Slonik dependencies and refactors database interaction logic. Key changes include removing the slonik@30.4.4 patch, upgrading slonik and slonik-interceptor-query-logging to 48.13.2, and introducing @standard-schema/spec. The PostgresDatabasePool class is updated to use QuerySqlToken for improved type safety and getRawPgPool is removed. The TaskScheduler is refactored to directly use PostgresDatabasePool methods instead of graphile-worker's WorkerUtils, which was removed. Several bigint to Number transformations in Zod schemas (e.g., limitRetentionDays, limitOperationsMonthly, membersCount, total) are identified as potential sources of precision loss, and the use of psql.fragment for SQL join separators is noted, requiring verification of generated SQL. Additionally, type assertions (as any) in psql.ts and postgres-database-pool.ts are highlighted as areas that might bypass type checking.

I am having trouble creating individual review comments. Click here to see my feedback.

packages/services/workflows/src/kit.ts (135-151)

critical

The code is using tools.withPgClient which is no longer available since tools has been removed. The code needs to be refactored to use the pgPool directly.

packages/services/workflows/src/kit.ts (166-169)

critical

The code is using tools.addJob which is no longer available since tools has been removed. The code needs to be refactored to use the pgPool directly.

packages/services/workflows/src/kit.ts (79-85)

critical

The tools property is removed and the pgPool is now of type PostgresDatabasePool. This changes the way tasks are scheduled. Ensure that the new implementation is correct and that all task scheduling logic is updated accordingly.

packages/services/storage/src/index.ts (5506-5507)

high

The limitRetentionDays and limitOperationsMonthly fields are transformed from bigint to Number. This could lead to precision loss if the bigint values are larger than the maximum safe integer in JavaScript. Consider using a library like bignumber.js to handle large integer values safely, or ensure that the values are within the safe integer range.

packages/internal/postgres/src/postgres-database-pool.ts (51-53)

high

The method getRawPgPool has been removed. Ensure that all usages of this method have been updated to use the getSlonikPool method or another appropriate alternative. If it's no longer needed, remove it from the codebase.

packages/services/storage/src/index.ts (5760)

high

The total field is transformed from bigint to Number. This could lead to precision loss if the bigint values are larger than the maximum safe integer in JavaScript. Consider using a library like bignumber.js to handle large integer values safely, or ensure that the values are within the safe integer range.

packages/services/storage/src/index.ts (1828)

high

The total field is transformed from bigint to Number. This could lead to precision loss if the bigint values are larger than the maximum safe integer in JavaScript. Consider using a library like bignumber.js to handle large integer values safely, or ensure that the values are within the safe integer range.

packages/services/commerce/src/index.ts (62)

high

The TaskScheduler is now initialized with storage.pool instead of storage.pool.getRawPgPool(). Ensure that the TaskScheduler is compatible with the PostgresDatabasePool interface and that all required methods are available.

packages/services/server/src/index.ts (172)

high

The TaskScheduler is now initialized with storage.pool instead of storage.pool.getRawPgPool(). Ensure that the TaskScheduler is compatible with the PostgresDatabasePool interface and that all required methods are available.

packages/services/storage/src/index.ts (1866)

high

The total field is transformed from bigint to Number. This could lead to precision loss if the bigint values are larger than the maximum safe integer in JavaScript. Consider using a library like bignumber.js to handle large integer values safely, or ensure that the values are within the safe integer range.

packages/services/storage/src/index.ts (673)

high

The total field is transformed from bigint to Number. This could lead to precision loss if the bigint values are larger than the maximum safe integer in JavaScript. Consider using a library like bignumber.js to handle large integer values safely, or ensure that the values are within the safe integer range.

packages/services/storage/src/index.ts (1856)

high

The total field is transformed from bigint to Number. This could lead to precision loss if the bigint values are larger than the maximum safe integer in JavaScript. Consider using a library like bignumber.js to handle large integer values safely, or ensure that the values are within the safe integer range.

packages/services/storage/src/index.ts (1840)

high

The total field is transformed from bigint to Number. This could lead to precision loss if the bigint values are larger than the maximum safe integer in JavaScript. Consider using a library like bignumber.js to handle large integer values safely, or ensure that the values are within the safe integer range.

packages/internal/postgres/src/psql.ts (21)

medium

The type assertion psqlFn as any as SqlTag<any> & TaggedTemplateLiteralInvocation is used to combine the properties of psqlFn and createSqlTag. While this may be necessary to satisfy the TypeScript compiler, it's important to ensure that this doesn't bypass any type checking or introduce runtime errors. Consider adding a comment explaining why this assertion is needed.

packages/services/storage/src/index.ts (1720)

medium

The separator in psql.join has been changed from , ( to fragment), (`. Ensure that this change does not affect the generated SQL query and that the values are correctly joined.

                targets.map(dest => psql.join([target, dest], psql.fragment`, `)),
                psql.fragment`), (`,
              )}

packages/services/storage/src/index.ts (1502)

medium

The separator in psql.join has been changed from , ( to fragment), (`. Ensure that this change does not affect the generated SQL query and that the values are correctly joined.

                    uniqueSelectors.map(s => psql`${s.targetId}, ${s.projectId}`),
                    psql.fragment`), (`,
                  )})

packages/services/storage/src/index.ts (839)

medium

The separator in psql.join has been changed from , ( to fragment), (`. Ensure that this change does not affect the generated SQL query and that the values are correctly joined.

            pairs.map(p => psql`${p.organizationId}, ${p.userId}`),
            psql.fragment`), (`,
          )}))

packages/services/storage/src/index.ts (697)

medium

The separator in psql.join has been changed from , ( to fragment), (`. Ensure that this change does not affect the generated SQL query and that the values are correctly joined.

            selectors.map(s => psql`${s.organizationId}, ${s.userId}`),
            psql.fragment`), (`,
          )}))

packages/services/storage/src/index.ts (620)

medium

The separator in psql.join has been changed from , to fragment, `. Ensure that this change does not affect the generated SQL query and that the values are correctly joined.

        WHERE id IN (${psql.join(organizations, psql.fragment`, `)})

packages/services/storage/src/index.ts (2419)

medium

The separator in psql.join has been changed from , ( to fragment), (`. Ensure that this change does not affect the generated SQL query and that the values are correctly joined.

              selectors.map(s => psql`${s.commit}, ${s.targetId}`),
              psql.fragment`), (`,
            )}))

packages/internal/postgres/package.json (10-12)

medium

The versions of slonik and slonik-interceptor-query-logging should be kept in sync to avoid compatibility issues. Ensure that both packages are updated to the same major and minor version.

packages/internal/postgres/src/postgres-database-pool.ts (202)

medium

The type assertion interceptor as any is used to assign the interceptor function to the pool method. While this may be necessary to satisfy the TypeScript compiler, it's important to ensure that this doesn't bypass any type checking or introduce runtime errors. Consider adding a comment explaining why this assertion is needed.

packages/internal/postgres/src/postgres-database-pool.ts (189-193)

medium

The type definition for the interceptor function has been simplified. Verify that this change does not introduce any type-related issues or break existing functionality. Ensure that the sql parameter is correctly typed as QuerySqlToken<any>.

packages/internal/postgres/src/postgres-database-pool.ts (125-137)

medium

The transaction handler's methods are being redefined using the methods available on the methods argument. This is unnecessary as the methods can be directly assigned. This simplifies the code and reduces redundancy.

          return handler({
            exists: methods.exists,
            any: methods.any,
            maybeOne: methods.maybeOne,
            async query(
              sql: QuerySqlToken<any>,
              values?: PrimitiveValueExpression[],
            ): Promise<void> {
              await methods.query(sql, values);
            },
            oneFirst: methods.oneFirst,
            maybeOneFirst: methods.maybeOneFirst,
            anyFirst: methods.anyFirst,
            one: methods.one,
          });

packages/internal/postgres/src/postgres-database-pool.ts (17-45)

medium

The type definitions for the query methods have been updated to use generics with StandardSchemaV1. This is good for type safety, but ensure that StandardSchemaV1 is correctly used throughout the codebase and that the inferred types are as expected. Also, confirm that the return types are accurate for all possible query results.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is one of the most annoying changes. Slonik introduced their own connection pool abstraction, which does not make it easy and straightforward to re-use the pg connection pool with graphile-workers. I will investigate ways to bridge the gap if possible.

@n1ru4l n1ru4l force-pushed the feat-upgrade-slonik branch 2 times, most recently from 1b080b8 to db3e117 Compare March 23, 2026 14:56
@n1ru4l n1ru4l force-pushed the copilot/update-slonik-connection-usage branch 2 times, most recently from a24dba9 to 4a99486 Compare March 25, 2026 10:24
@n1ru4l n1ru4l force-pushed the feat-upgrade-slonik branch 3 times, most recently from 34b92eb to b798336 Compare March 25, 2026 11:07
@n1ru4l n1ru4l force-pushed the feat-upgrade-slonik branch from a570a2e to b90983f Compare March 25, 2026 15:56
Comment on lines +172 to +178
const typeParsers = [
...createTypeParserPreset().filter(parser => parser.name !== 'int8'),
{
name: 'int8',
parse: (value: string) => parseInt(value, 10),
},
];
Copy link
Contributor Author

@n1ru4l n1ru4l Mar 25, 2026

Choose a reason for hiding this comment

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

In slonik the default type parser for int was changed to retrieve bigint. Introducing the old behaviour reduces the need to change all queries or zod model parsings. I don't see a benefit or issues for using bigint

@n1ru4l n1ru4l force-pushed the feat-upgrade-slonik branch from b90983f to 6d64dd5 Compare March 25, 2026 16:07
@n1ru4l n1ru4l force-pushed the feat-upgrade-slonik branch from 6d64dd5 to f047644 Compare March 26, 2026 10:38
@n1ru4l n1ru4l force-pushed the feat-upgrade-slonik branch 4 times, most recently from 59c52d1 to a62d40f Compare March 26, 2026 13:43
@n1ru4l n1ru4l force-pushed the feat-upgrade-slonik branch from a62d40f to 73dcef5 Compare March 26, 2026 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant