Skip to content

Releases: RobinBlomberg/kysely-codegen

0.20.0

Choose a tag to compare

@RobinBlomberg RobinBlomberg released this 16 Feb 08:46

Many great contributions, bug fixes and new features.

Resolves #284, #287, #307, #308, #72, #301, #275, #283.

defineConfig() and postprocess()

kysely-codegen@0.20.0 adds a defineConfig function that makes it easy to configure kysely-codegen in a type-safe way. It also adds a new Config#postprocess function that makes it possible to process the introspected metadata before generating code. This function allows you to reuse the active kysely-codegen connection to further introspect the database and modify the metadata as needed.

Example of generating enum types from PostGraphile enum tables:

import { sql } from "kysely";
import { defineConfig } from "kysely-codegen";
import pluralize from "pluralize";

export default defineConfig({
  camelCase: false,
  dateParser: "timestamp",
  dialect: "postgres",
  excludePattern: "(graphile_migrate.*|graphile_worker._private_*)",
  outFile: "./types/database-types.ts",
  postprocess: async ({ db, metadata }) => {
    const rows = await db
      .selectFrom("pg_catalog.pg_constraint as foreign_key_constraint")
      .innerJoin(
        "pg_catalog.pg_class as from_table",
        "from_table.oid",
        "foreign_key_constraint.conrelid",
      )
      .innerJoin(
        "pg_catalog.pg_namespace as from_table_namespace",
        "from_table_namespace.oid",
        "from_table.relnamespace",
      )
      .innerJoin("pg_catalog.pg_attribute as from_column", (join) =>
        join
          .onRef("from_column.attrelid", "=", "from_table.oid")
          .on(sql`from_column.attnum = any(foreign_key_constraint.conkey)`),
      )
      .innerJoin(
        "pg_catalog.pg_class as to_table",
        "to_table.oid",
        "foreign_key_constraint.confrelid",
      )
      .innerJoin(
        "pg_catalog.pg_namespace as to_table_namespace",
        "to_table_namespace.oid",
        "to_table.relnamespace",
      )
      .innerJoin("pg_catalog.pg_attribute as to_column", (join) =>
        join
          .onRef("to_column.attrelid", "=", "to_table.oid")
          .on(sql`to_column.attnum = any(foreign_key_constraint.confkey)`),
      )
      .select([
        "from_table_namespace.nspname as fromSchema",
        "from_table.relname as fromTable",
        "from_column.attname as fromColumn",
        "to_table_namespace.nspname as enumSchema",
        "to_table.relname as enumTable",
        "to_column.attname as enumColumn",
      ])
      .where("foreign_key_constraint.contype", "=", "f")
      .where(sql<any>`obj_description(to_table.oid, 'pg_class') like '%@enum%'`)
      .execute();

    await Promise.all(
      rows.map(
        async ({
          fromColumn,
          fromSchema,
          fromTable,
          enumColumn,
          enumSchema,
          enumTable,
        }) => {
          const fromTableMetadata = metadata.tables.find(
            (table) => table.schema === fromSchema && table.name === fromTable,
          );
          const fromColumnMetadata = fromTableMetadata?.columns.find(
            (column) => column.name === fromColumn,
          );
          const enumTableMetadata = metadata.tables.find(
            (table) => table.schema === enumSchema && table.name === enumTable,
          );
          const enumColumnMetadata = enumTableMetadata?.columns.find(
            (column) => column.name === enumColumn,
          );

          if (fromColumnMetadata || enumColumnMetadata) {
            const dataType = `${pluralize.singular(enumTable)}.${enumColumn}`;
            const enumValues = await db
              .selectFrom(`${enumSchema}.${enumTable}`)
              .select(enumColumn)
              .execute()
              .then((rows) =>
                rows.map((row) => (row as Record<string, string>)[enumColumn]),
              );

            metadata.enums.set(`${enumSchema}.${dataType}`, enumValues);

            if (fromColumnMetadata) {
              fromColumnMetadata.dataTypeSchema = enumSchema;
              fromColumnMetadata.dataType = dataType;
            }

            if (enumColumnMetadata) {
              enumColumnMetadata.dataTypeSchema = enumSchema;
              enumColumnMetadata.dataType = dataType;
            }
          }
        },
      ),
    );

    return metadata;
  },
  singularize: true,
  url: process.env.DATABASE_URL,
});

Example output:

+type EventTypeName = "TICKET_CREATED" | "TICKET_DELETED" | "TICKET_UPDATED";
+
 type Event = {
   createdAt: Generated<Timestamp>;
   data: JsonValue;
-  type: string;
+  type: EventTypeName;
 };

 type EventType = {
   description: string;
-  name: string;
+  name: EventTypeName;
 };

What's Changed

  • feat: update @tediousjs/connection-string to 1.0.0 by @bakasmarius in #312
  • replace git-diff with diff by @paolostyle in #306
  • feat(generator): Add support for generate symbol with CJK character by @lightrabbit in #313
  • allow 'sqlite://' prefix in database url by @R4stafa in #302
  • fix: resolve flaky CLI tests and add GitHub Actions CI by @elitan in #297
  • feat: add PostgreSQL materialized view support by @elitan in #298
  • feat: add uuid as string in mariadb by @AwaludinAR in #308
  • Add support for 'timetz' type in PostgresAdapter by @bombillazo in #291
  • Support subpath imports for named imports by @alex-kinokon in #290
  • fix(GH-287): Fix for generic type imports by @kevinmichaelchen in #288
  • support nullable override types by @itamar82 in #286
  • feat: Add defineConfig() function for type-safe TypeScript configs
  • feat: Add Config#postprocess() function
  • feat: Silence dotenv tips

New Contributors

Full Changelog: 0.19.0...0.20.0

0.19.0

Choose a tag to compare

@RobinBlomberg RobinBlomberg released this 03 Sep 07:00

New features

Thanks to amazing contributions from @kevinmichaelchen in #274, you can now override types on a global level:

.kysely-codegenrc.json

{
  "customImports": {
    "InstantRange": "./custom-types",
    "CustomDuration": "@my-org/custom-types#Duration",
    "Temporal": "@js-temporal/polyfill",
  },
  "typeMapping": {
    "timestamptz": "Temporal.Instant",
    "tstzrange": "InstantRange",
    "date": "Temporal.PlainDate",
    "interval": "CustomDuration"
  }
}

Example of generated output:

import type { InstantRange } from './custom-types';
import type { Duration as CustomDuration } from '@my-org/custom-types';
import type { Temporal } from '@js-temporal/polyfill';

export interface EventModel {
  createdAt: Temporal.Instant;
  dateRange: ColumnType<InstantRange, InstantRange, never>;
  eventDate: Temporal.PlainDate;
  interval: CustomDuration;
}

export interface DB {
  events: EventModel;
}

What's Changed

New Contributors

Full Changelog: 0.18.0...0.19.0

0.18.0

Choose a tag to compare

@RobinBlomberg RobinBlomberg released this 02 Mar 13:47

Migration to 0.18.0

The follow CLI options have been changed:

  • --schema has been renamed to --default-schema.
  • --singular has been renamed to --singularize.
  • --runtime-enums and --runtime-enums-style have been merged into a single CLI option --runtime-enums.

Configuration file

All codegen options can also be configured in a .kysely-codegenrc.json (or .js, .ts, .yaml etc.) file or the kysely-codegen property in package.json. See Cosmiconfig for all available configuration file formats.

The default configuration:

{
  "camelCase": false,
  "dateParser": "timestamp",
  "defaultSchemas": [], // ["public"] for PostgreSQL.
  "dialect": null,
  "domains": true,
  "envFile": null,
  "excludePattern": null,
  "includePattern": null,
  "logLevel": "warn",
  "numericParser": "string",
  "outFile": "./node_modules/kysely-codegen/dist/db.d.ts",
  "overrides": {},
  "partitions": false,
  "print": false,
  "runtimeEnums": false,
  "singularize": false,
  "typeOnlyImports": true,
  "url": "env(DATABASE_URL)",
  "verify": false
}

The configuration object adds support for more advanced options:

{
  "camelCase": true,
  "overrides": {
    "columns": {
      "users.settings": "{ theme: 'dark' }"
    }
  },
  "singularize": {
    "/^(.*?)s?$/": "$1_model",
    "/(bacch)(?:us|i)$/i": "$1us"
  }
}

The generated output:

export interface UserModel {
  settings: { theme: 'dark' };
}

// ...

export interface DB {
  bacchi: Bacchus;
  users: UserModel;
}

Custom serializers and dialects

The new configuration support also adds support for supplying custom serializers.

Here is a stub example of a basic Zod serializer (.kysely-codegenrc.ts):

import { toKyselyCamelCase } from '../../generator';
import type { Config } from '../config';

const config: Config = {
  logLevel: 'debug',
  outFile: null,
  serializer: {
    serializeFile: (metadata) => {
      let output = 'import { z } from "zod";\n\n';

      for (const table of metadata.tables) {
        output += 'export const ';
        output += toKyselyCamelCase(table.name);
        output += 'Schema = z.object({\n';

        for (const column of table.columns) {
          output += '  ';
          output += column.name;
          output += ': ';

          switch (column.dataType) {
            case 'int4':
              output += 'z.number().int()';
              break;
            default:
              output += 'z.unknown()';
          }

          output += ',\n';
        }

        output += '});\n\n';
      }

      return output;
    },
  },
  url: 'postgres://user:password@localhost:5433/database',
};

export default config;

Example output:

import { z } from "zod";

export const usersSchema = z.object({
  baz_qux: z.number().int(),
});

Similarly, it's also possible to supply a custom dialect value, allowing you to create a completely new kysely-codegen dialects or extending an existing one with extra logic.

What's Changed

  • feat!: Merge "runtime-enums" and "runtime-enums-style" options
  • feat!: Deprecate "schemas" option and rename it to "defaultSchemas"
  • feat!: Rename "singular" option to "singularize"
  • feat: Support kysely-codegen configuration files (using cosmiconfig)
  • feat: Add support for custom singularization rules
  • feat: Merge all ...IdentifierNode classes into a single IdentifierNode class
  • feat: Add skipAutogenerationFileComment serializer option
  • fix: Fix overrides not always applying to the correct column
  • fix: Fix test flakiness by running all tests in sequence
  • fix: Make bun sqlite codegen work again (re-introduce KyselyBunSqliteIntrospectorDialect using the sqlite database from bun:sqlite and the Kysely dialect from 'kysely-bun-sqlite') by @meck93 in #238
  • fix: Fix update function example @ README. by @igalklebanov in #227
  • chore: Upgrade all dependencies
  • chore: Allow @libsql/kysely-libsql@^0.4.1 as a peer dependency @alsiola in #233

New Contributors

Full Changelog: 0.17.0...0.18.0

0.17.0

Choose a tag to compare

@RobinBlomberg RobinBlomberg released this 18 Oct 06:44

What's Changed

  • fix: fix incorrect timestamp types (fixes #203, #209)
  • feat: support named instances for Microsoft Sql Server by @gittgott in #204
  • feat: add --date-parser flag to control Postgres DATE type by @brianmcd in #210 (fixes #177, #194)
  • docs: list current cli args by @shane-js in #167
  • docs: update README.md run instructions by @shane-js in #166
  • docs: improve documentation (fixes #178)
  • feat(cli): adjust flag descriptions (fixes #193)
  • feat: improve error when .env file is missing

New Contributors

Full Changelog: 0.16.7...0.17.0

0.16.7

Choose a tag to compare

@RobinBlomberg RobinBlomberg released this 16 Sep 12:22

What's Changed

  • Allow PG Timestamp to accept string as selectType. by @hevar in #199 (fixes #194, #123, #177)
  • Correctly pass the partition option to the Postgres inspector by @fxmouthuy in #197 (fixes #196)
  • Fix postgres default schema behavior by @RobinClowers in #200
  • Deduplicate repeated ColumnType arguments

New Contributors

Full Changelog: 0.16.4...0.16.7

0.16.4

Choose a tag to compare

@RobinBlomberg RobinBlomberg released this 02 Sep 07:13

What's Changed

  • feat: accept multiple --schema flags @RobinClowers in #192
  • fix: export all internal modules
  • fix(generator): fix syntax error in old PostgreSQL versions
  • fix(cli): rename misnamed CLI option
  • refactor: install knip and remove all unused files/variables

Full Changelog: 0.16.0...0.16.4

0.16.0

Choose a tag to compare

@RobinBlomberg RobinBlomberg released this 30 Aug 06:33

Good morning! This is a big one.

What's Changed

  • Properly utilize SSL parameter for MSSQL dialect connection by @mjbergman92 in #158
  • Make it possible to insert strings into Interval columns by @qchar in #159
  • Add --singular CLI option by @acro5piano in #162 (fixes #32)
  • Add new Bun SQLite Dialect by @tlonny in #174 (fixes #153)
  • Bump Tedious to v18 by @bakasmarius in #172
  • Column overrides by @gittgott in #148 (fixes #30)
  • Change type definition for JsonObject to make ESLint happy (fixes #181)
  • Add --numeric-parser option for specifying PostgreSQL Numeric return type (fixes #161 and #109)
  • Make table names starting with numbers generate valid JavaScript identifiers (fixes #151)
  • Make runtime enums generate correct enum keys and add --runtime-enums-style CLI option (fixes #150)
  • Add top-of-file marker comment when generating code (fixes #114)
  • Exclude table partitions (fixes #76)
  • Support overriding JSON column types (fixes #75)

Refactors and chores

  • Bump all dependencies
  • Refactor code to make CLI, generator and introspector into separate modules
  • Use Vitest test runner

New Contributors

Full Changelog: 0.15.0...0.16.0

0.15.0

Choose a tag to compare

@RobinBlomberg RobinBlomberg released this 18 Apr 11:17

What's Changed

New Contributors

Full Changelog: 0.14.0...0.15.0

0.14.0

Choose a tag to compare

@RobinBlomberg RobinBlomberg released this 17 Mar 20:35

What's Changed

  • Add a skip-domains flag for postgres by @RobinClowers in #136
  • Update compatible tedious versions by @timclark97 in #137
  • Set kysely-bun-worker as an optional peer dep by @arempe93 in #138
  • typescript comments based on columns comments by @elitan in #139
  • feat: runtime enum support by @lsnow99 in #131

New Contributors

Full Changelog: 0.13.0...0.14.0

0.13.0

Choose a tag to compare

@RobinBlomberg RobinBlomberg released this 07 Mar 07:25

What's Changed

  • fix: add 'bun-sqlite' in VALID_DIALECTS by @mtt-artis in #129
  • Add MSSQL Support by @timclark97 in #128
  • Add include/exclude pattern instructions to README.md by @divmgl in #133
  • Expand environment variables from .env by @iffa in #130

New Contributors

  • @mtt-artis made their first contribution in #129
  • @timclark97 made their first contribution in #128
  • @divmgl made their first contribution in #133
  • @iffa made their first contribution in #130

Full Changelog: 0.12.0...0.13.0