kysely-org / kysely

A type-safe typescript SQL query builder
https://kysely.dev
MIT License
10.82k stars 275 forks source link

Potential typing bug with INSERT ON CONFLICT DO UPDATE WHERE #1189

Open ethanresnick opened 1 month ago

ethanresnick commented 1 month ago

Hi, I have a query like:

kysely
  .insertInto('person')
  .values({ id, employeeNumber })
  .onConflict(oc =>
    oc.column('id').doUpdateSet(eb => ({
      employeeNumber: eb.ref('excluded.employeeNumber'),
    }))
    .where('person.employerId', '=', employerId)
  )
  .executeTakeFirst();

The intention is something like: upsert a person with their employee number, but only if the person to update is in the same company as the person performing the update. (This is not a real example from my domain, but you get the idea.)

The issue is that, in the types for the person table, the employer_id column's update type is never (as its intended to be immutable). However, kysely only lets me refer to the column in the where clause based on its update type, so the query gives an error when it seems like it should be allowed.

Self-contained example:

import { Kysely, ColumnType } from "kysely";

declare const db: Kysely<{
  person: {
    id: ColumnType<number, number, never>;
    employeeNumber: number;
    employerId:  ColumnType<number, number, never>;
  };
}>;

const result = db
  .insertInto('person')
  .values({ id: 32, employeeNumber: 4343, employerId: 1 })
  .onConflict(oc =>
    oc.column('id').doUpdateSet(eb => ({
      employeeNumber: eb.ref('excluded.employeeNumber'),
    }))
    .where('person.employerId', '=', 1)
  )
  .executeTakeFirst();

Error is:

Argument of type '"person.employerId"' is not assignable to parameter of type 'ReferenceExpression<OnConflictDatabase<{ person: { id: ColumnType<number, number, never>; employeeNumber: number; employerId: ColumnType<number, number, never>; }; }, "person">, OnConflictTables<...>>'