npm kysely-codegen 0.20.0

8 hours ago

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";

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

Don't miss a new kysely-codegen release

NewReleases is sending notifications on new releases.