romeerez/orchid-orm

[typescript] timestamps() object spread error while running migrations

Closed this issue · 5 comments

Trying to add timestamps to my tables using ...t.timestamps() object spread as per documentation, but getting into the following error:

 Type '{ createdAt: ColumnWithDefault<ColumnTypeBase<unknown, BaseOperators, unknown, unknown, unknown, ColumnDataBase>, RawSQLBase<ColumnTypeBase<unknown, BaseOperators, unknown, unknown, unknown, ColumnDataBase>, unknown>>; ... 4 more ...; description: NullableColumn<...>; }' is not assignable to type 'ColumnsShape'.
  Property 'createdAt' is incompatible with index signature.
    Type 'ColumnWithDefault<ColumnTypeBase<unknown, BaseOperators, unknown, unknown, unknown, ColumnDataBase>, RawSQLBase<ColumnTypeBase<unknown, BaseOperators, unknown, unknown, unknown, ColumnDataBase>, unknown>>' is missing the following properties from type 'ColumnType<unknown, BaseOperators, unknown, unknown, unknown>': primaryKey, foreignKey, index, searchIndex, and 11 more.

  7     (t) => ({
               ~~
  8       id: t.uuid().primaryKey(),
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
 12       ...t.timestamps(),
    ~~~~~~~~~~~~~~~~~~~~~~~~
 13     }),
    ~~~~~~

  node_modules/.pnpm/rake-db@2.10.61/node_modules/rake-db/dist/index.d.ts:54:100
    54 type ColumnsShapeCallback<CT extends ColumnTypesBase, Shape extends ColumnsShape = ColumnsShape> = (t: MigrationColumnTypes<CT> & {
                                                                                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    55     raw: typeof raw;
       ~~~~~~~~~~~~~~~~~~~~
    56 }) => Shape;
       ~~~~~~~~~~~
    The expected type comes from the return type of this signature.

Here's the offending code:

import { change } from "../dbScript";

change(async (db) => {
  await db.createTable(
    "event_type",
    { createIfNotExists: true, dropIfExists: true },
    (t) => ({
      id: t.uuid().primaryKey(),
      name: t.varchar().unique(),
      title: t.varchar(),
      description: t.varchar().nullable(),
      ...t.timestamps(),
    }),
  );
});

If I remove timestamps declaration or use manual timestamp definitions, all migrations run perfectly.

My editor also highlights this same issue, so it's not isolated to build time.
CleanShot 2023-10-11 at 19 05 58@2x

Can't reproduce, could you share your dbScript and base table files?

Sure thing!

BaseTable.ts

export const BaseTable = createBaseTable({
  snakeCase: true,
  columnTypes: (t) => ({
    id: () => t.uuid().primaryKey(),
    ...t,
    ...t.timestamps(),
  }),
  exportAs: "BaseTable",
});

dbScript.ts

import { rakeDb } from "rake-db";
import { appCodeUpdater } from "orchid-orm/codegen";
import { config } from "./config";
import { BaseTable } from "./tables/BaseTable";

export const change = rakeDb(config.database, {
  snakeCase: true,
  baseTable: BaseTable,
  migrationsPath: "./migrations",
  appCodeUpdater: appCodeUpdater({
    tablePath: (tableName) => `./tables/${tableName}.ts`,
    ormPath: "./db.ts",
  }),
  useCodeUpdater: false, // set to false to disable code updater
  commands: {
    async seed() {
      const { seed } = await import("./seed");
      await seed();
    },
  },
  import: (path) => import(path),
});

What am I missing / doing incorrectly?

Here in the base table:

export const BaseTable = createBaseTable({
  snakeCase: true,
  columnTypes: (t) => ({
    id: () => t.uuid().primaryKey(),
    ...t,
    ...t.timestamps(), <-- here
  }),
  exportAs: "BaseTable",
});

That line is causing types to corrupt. I guess you want to createAt and updatedAt helpers to be available later when defining columns? It's not supported, but I can add support for it.

Ah, that makes sense. Thanks!

I'll make sure to add this separately to each table, but such a convenience method would be nice when you need all tables to have timestamps, but don't treat it as a priority.

Would this throw off migrations as well by any chance?

...t.timestamps() can be used in migrations and in table classes, but not in the base class. There is no way to make all tables have it implicitly, and I'm not sure if that would be a good idea.