Skip to content

Instantly share code, notes, and snippets.

@oliveryasuna
Last active April 24, 2025 17:35
Show Gist options
  • Save oliveryasuna/2197a5a8951236adaf265ed001f2db93 to your computer and use it in GitHub Desktop.
Save oliveryasuna/2197a5a8951236adaf265ed001f2db93 to your computer and use it in GitHub Desktop.
Kysely Repository (incomplete)
import type {AnyTable} from './types';
import type {ReferenceExpression} from 'kysely';
const UNARY_COMPARISON_OPERATORS_COMMON = (['is null', 'is not null'] as const);
const UNARY_COMPARISON_OPERATORS_BOOLEAN_ONLY = (['is true', 'is not true', 'is false', 'is not false', 'is unknown', 'is not unknown'] as const);
const UNARY_COMPARISON_OPERATORS = [...UNARY_COMPARISON_OPERATORS_COMMON, ...UNARY_COMPARISON_OPERATORS_BOOLEAN_ONLY] as const;
type UnaryComparisonOperatorCommon = (typeof UNARY_COMPARISON_OPERATORS_COMMON[number]);
type UnaryComparisonOperatorBooleanOnly = (typeof UNARY_COMPARISON_OPERATORS_BOOLEAN_ONLY[number]);
type UnaryComparisonOperator<T> = (T extends boolean
? (UnaryComparisonOperatorCommon | UnaryComparisonOperatorBooleanOnly)
: UnaryComparisonOperatorCommon);
const BINARY_COMPARISON_OPERATORS = (['<', '>', '<=', '>=', '=', '<>', 'is distinct from', 'is not distinct from'] as const);
type BinaryComparisonOperator = (typeof BINARY_COMPARISON_OPERATORS[number]);
// type BinaryComparisonInOperator = ('in' | 'not in');
const TERTIARY_COMPARISON_OPERATORS = (['between', 'not between', 'between symmetric', 'not between symmetric'] as const);
type TertiaryComparisonOperator = (typeof TERTIARY_COMPARISON_OPERATORS[number]);
const PATTERN_MATCHING_OPERATORS = (['like', 'not like', 'ilike', 'not ilike', 'similar to', 'not similar to'] as const);
type PatternMatchingOperator = (typeof PATTERN_MATCHING_OPERATORS[number]);
// const ARRAY_OPERATORS = (['@>', '<@', '&&'] as const);
//
// type ArrayOperator = (typeof ARRAY_OPERATORS[number]);
type Condition<DB, TB extends AnyTable<DB>, CL extends (((keyof TB) & ReferenceExpression<DB, TB> & string))> = (
// Comparison operators
//--------------------------------------------------
// Unary
UnaryComparisonOperator<TB[CL]>
| {operator: UnaryComparisonOperator<TB[CL]>;}
// Binary
| {
operator: BinaryComparisonOperator;
value: TB[CL];
}
| [BinaryComparisonOperator, TB[CL]]
// TODO: Support `in`.
// // Binary In
// | (
// TB[CL] extends []
// ? never
// : (
// | {operator: BinaryComparisonInOperator; value: TB[CL][];}
// | [BinaryComparisonInOperator, TB[CL][]]
// )
// )
// Tertiary
| {
operator: TertiaryComparisonOperator;
value1: TB[CL];
value2: TB[CL];
}
| [TertiaryComparisonOperator, TB[CL], TB[CL]]
| [TertiaryComparisonOperator, [TB[CL], TB[CL]]]
// Pattern matching operators
//--------------------------------------------------
| (TB[CL] extends string
? (
| {
operator: PatternMatchingOperator;
value: TB[CL];
}
| [PatternMatchingOperator, TB[CL]]
)
: never)
// TODO: Support array operators.
// // Array operators
// //--------------------------------------------------
//
// | (
// TB[CL] extends []
// ? (
// | {operator: ArrayOperator; value: TB[CL];}
// | [ArrayOperator, TB[CL]]
// )
// : never
// )
);
// TODO: This does not work with aliases.
type Conditions<DB, TB extends AnyTable<DB>> = {
[CL in ((keyof TB) & ReferenceExpression<DB, TB> & string)]?: Condition<DB, TB, CL>;
};
export type {
UnaryComparisonOperatorCommon,
UnaryComparisonOperatorBooleanOnly,
UnaryComparisonOperator,
BinaryComparisonOperator,
TertiaryComparisonOperator,
PatternMatchingOperator,
Condition,
Conditions
};
export {
UNARY_COMPARISON_OPERATORS_COMMON,
UNARY_COMPARISON_OPERATORS_BOOLEAN_ONLY,
UNARY_COMPARISON_OPERATORS,
BINARY_COMPARISON_OPERATORS,
TERTIARY_COMPARISON_OPERATORS,
PATTERN_MATCHING_OPERATORS
};
import type {
AnyColumn,
DeleteResult,
ExpressionBuilder,
InsertObject,
OnConflictBuilder,
OnConflictDatabase,
OnConflictTables,
OnConflictUpdateBuilder,
OperandExpression,
ReferenceExpression,
SqlBool,
UpdateObject,
UpdateResult
} from 'kysely';
import {Kysely, sql} from 'kysely';
import type {ExtractKyselySelection, Returning} from './returning';
import type {SimplifyResult, SimplifySingleResult} from 'kysely/dist/cjs/util/type-utils';
import type {Upsert} from './upsert';
import type {OnConflictDoNothingBuilder} from 'kysely/dist/cjs/query-builder/on-conflict-builder';
import type {InsertResult} from 'kysely/dist/cjs/query-builder/insert-result';
import type {AllSelection} from 'kysely/dist/cjs/parser/select-parser';
import type {AnySimpleColumn, AnyTable, OperandExpressionFactory} from './types';
import type {Condition, Conditions} from './conditions';
import {BINARY_COMPARISON_OPERATORS, PATTERN_MATCHING_OPERATORS, TERTIARY_COMPARISON_OPERATORS, UNARY_COMPARISON_OPERATORS} from './conditions';
import type {ExtractTableAlias} from 'kysely/dist/cjs/parser/table-parser';
class Repository<DB, TB extends ((keyof DB) & string)> {
// Properties
//--------------------------------------------------
protected _tableName: TB;
// Constructor
//--------------------------------------------------
public constructor(tableName: TB) {
this._tableName = tableName;
}
// Methods
//--------------------------------------------------
// Create
//
public insertOne(db: Kysely<DB>, value: InsertObject<DB, TB>): Promise<SimplifySingleResult<InsertResult>>;
public insertOne<Ret extends Returning<DB, TB>>(
db: Kysely<DB>,
value: InsertObject<DB, TB>,
returning: Ret
): Promise<SimplifySingleResult<ExtractKyselySelection<DB, TB, Ret>>>;
public insertOne<Ret extends Returning<DB, TB>>(
db: Kysely<DB>,
value: InsertObject<DB, TB>,
returning?: Ret
): (Promise<SimplifySingleResult<InsertResult> | SimplifySingleResult<ExtractKyselySelection<DB, TB, Ret>>>) {
// TODO: Could use `$if`.
if(returning) {
return (db
.insertInto(this._tableName)
.values(value)
.returning(this._normalizeReturning(returning))
.executeTakeFirst() as (Promise<SimplifySingleResult<InsertResult> | SimplifySingleResult<ExtractKyselySelection<DB, TB, Ret>>>));
} else {
return db
.insertInto(this._tableName)
.values(value)
.executeTakeFirst();
}
}
public insertOneUpsert(db: Kysely<DB>, value: InsertObject<DB, TB>, upsert: Upsert<DB, TB>): Promise<SimplifySingleResult<InsertResult>>;
public insertOneUpsert<Ret extends Returning<DB, TB>>(
db: Kysely<DB>,
value: InsertObject<DB, TB>,
upsert: Upsert<DB, TB>,
returning: Ret
): Promise<SimplifySingleResult<ExtractKyselySelection<DB, TB, Ret>>>;
public insertOneUpsert<Ret extends Returning<DB, TB>>(
db: Kysely<DB>,
value: InsertObject<DB, TB>,
upsert: Upsert<DB, TB>,
returning?: Ret
): (Promise<SimplifySingleResult<InsertResult> | SimplifySingleResult<ExtractKyselySelection<DB, TB, Ret>>>) {
const onConflict = this._normalizeUpsert(upsert);
// TODO: Could use `$if`.
if(returning) {
return (db
.insertInto(this._tableName)
.values(value)
.onConflict(onConflict)
.returning(this._normalizeReturning(returning))
.executeTakeFirst() as (Promise<SimplifySingleResult<InsertResult> | SimplifySingleResult<ExtractKyselySelection<DB, TB, Ret>>>));
} else {
return db
.insertInto(this._tableName)
.values(value)
.onConflict(onConflict)
.executeTakeFirst();
}
}
public insertAll(db: Kysely<DB>, values: InsertObject<DB, TB>[]): Promise<SimplifyResult<InsertResult>[]>;
public insertAll<Ret extends Returning<DB, TB>>(
db: Kysely<DB>,
values: InsertObject<DB, TB>[],
returning: Ret
): Promise<SimplifyResult<ExtractKyselySelection<DB, TB, Ret>>[]>;
public insertAll<Ret extends Returning<DB, TB>>(
db: Kysely<DB>,
values: InsertObject<DB, TB>[],
returning?: Ret
): (Promise<SimplifyResult<InsertResult>[] | SimplifyResult<ExtractKyselySelection<DB, TB, Ret>>[]>) {
// TODO: Could use `$if`.
if(returning) {
return (db
.insertInto(this._tableName)
.values(values)
.returning(this._normalizeReturning(returning))
.execute() as (Promise<SimplifyResult<InsertResult>[] | SimplifyResult<ExtractKyselySelection<DB, TB, Ret>>[]>));
} else {
return db
.insertInto(this._tableName)
.values(values)
.execute();
}
}
public insertAllUpsert(db: Kysely<DB>, values: InsertObject<DB, TB>[], upsert: Upsert<DB, TB>): Promise<SimplifyResult<InsertResult>[]>;
public insertAllUpsert<Ret extends Returning<DB, TB>>(
db: Kysely<DB>,
values: InsertObject<DB, TB>[],
upsert: Upsert<DB, TB>,
returning: Ret
): Promise<SimplifyResult<ExtractKyselySelection<DB, TB, Ret>>[]>;
public insertAllUpsert<Ret extends Returning<DB, TB>>(
db: Kysely<DB>,
values: InsertObject<DB, TB>[],
upsert: Upsert<DB, TB>,
returning?: Ret
): (Promise<SimplifyResult<InsertResult>[] | SimplifyResult<ExtractKyselySelection<DB, TB, Ret>>[]>) {
const onConflict = this._normalizeUpsert(upsert);
// TODO: Could use `$if`.
if(returning) {
return (db
.insertInto(this._tableName)
.values(values)
.onConflict(onConflict)
.returning(this._normalizeReturning(returning))
.execute() as (Promise<SimplifyResult<InsertResult>[] | SimplifyResult<ExtractKyselySelection<DB, TB, Ret>>[]>));
} else {
return db
.insertInto(this._tableName)
.values(values)
.onConflict(onConflict)
.execute();
}
}
// Read
//
public selectOne(db: Kysely<DB>, conditions: Conditions<DB, ExtractTableAlias<DB, TB>>): Promise<SimplifySingleResult<AllSelection<DB, TB>>>;
public selectOne<Ret extends Returning<DB, ExtractTableAlias<DB, TB>>>(
db: Kysely<DB>,
conditions: Conditions<DB, ExtractTableAlias<DB, TB>>,
values: Ret
): Promise<SimplifySingleResult<ExtractKyselySelection<DB, ExtractTableAlias<DB, TB>, Ret>>>;
public selectOne<Ret extends Returning<DB, ExtractTableAlias<DB, TB>>>(
db: Kysely<DB>,
conditions: Conditions<DB, ExtractTableAlias<DB, TB>>,
values?: Ret
): Promise<SimplifySingleResult<AllSelection<DB, ExtractTableAlias<DB, TB>>> | SimplifySingleResult<ExtractKyselySelection<DB, ExtractTableAlias<DB, TB>, Ret>>> {
const where = this._normalizeConditions(conditions);
// TODO: Could use `$if`.
if(values) {
return (db
.selectFrom(this._tableName)
.select(this._normalizeReturning(values))
.where(where)
.executeTakeFirst() as Promise<SimplifySingleResult<AllSelection<DB, ExtractTableAlias<DB, TB>>> | SimplifySingleResult<ExtractKyselySelection<DB, ExtractTableAlias<DB, TB>, Ret>>>);
} else {
return (db
.selectFrom(this._tableName)
.selectAll()
.where(where)
.executeTakeFirst() as Promise<SimplifySingleResult<AllSelection<DB, ExtractTableAlias<DB, TB>>>>);
}
}
public selectAll(db: Kysely<DB>, conditions: Conditions<DB, ExtractTableAlias<DB, TB>>): Promise<SimplifyResult<AllSelection<DB, TB>[]>>;
public selectAll<Ret extends Returning<DB, ExtractTableAlias<DB, TB>>>(
db: Kysely<DB>,
conditions: Conditions<DB, ExtractTableAlias<DB, TB>>,
values: Ret
): Promise<SimplifyResult<ExtractKyselySelection<DB, ExtractTableAlias<DB, TB>, Ret>[]>>;
public selectAll<Ret extends Returning<DB, ExtractTableAlias<DB, TB>>>(
db: Kysely<DB>,
conditions: Conditions<DB, ExtractTableAlias<DB, TB>>,
values?: Ret
): Promise<SimplifyResult<AllSelection<DB, ExtractTableAlias<DB, TB>>[]> | SimplifyResult<ExtractKyselySelection<DB, ExtractTableAlias<DB, TB>, Ret>[]>> {
const where = this._normalizeConditions(conditions);
// TODO: Could use `$if`.
if(values) {
return (db
.selectFrom(this._tableName)
.select(this._normalizeReturning(values))
.where(where)
.execute() as Promise<SimplifyResult<AllSelection<DB, ExtractTableAlias<DB, TB>>[]> | SimplifyResult<ExtractKyselySelection<DB, ExtractTableAlias<DB, TB>, Ret>[]>>);
} else {
return (db
.selectFrom(this._tableName)
.selectAll()
.where(where)
.execute() as Promise<SimplifyResult<AllSelection<DB, ExtractTableAlias<DB, TB>>[]>>);
}
}
public count(db: Kysely<DB>): Promise<number>;
public count(db: Kysely<DB>, conditions: Conditions<DB, ExtractTableAlias<DB, TB>>): Promise<number>;
public count(db: Kysely<DB>, conditions?: Conditions<DB, ExtractTableAlias<DB, TB>>): Promise<number> {
// TODO: Could use `$if`.
if(conditions) {
return (db
.selectFrom(this._tableName)
.select(db.fn.countAll<number>().as('count'))
.where(this._normalizeConditions(conditions))
.executeTakeFirstOrThrow()
// TODO: Why `any`?
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
.then((result: any): number => result.count));
} else {
return (db
.selectFrom(this._tableName)
.select(db.fn.countAll<number>().as('count'))
.executeTakeFirstOrThrow()
// TODO: Why `any`?
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
.then((result: any): number => result.count));
}
}
public exists(db: Kysely<DB>): Promise<boolean>;
public exists(db: Kysely<DB>, conditions: Conditions<DB, ExtractTableAlias<DB, TB>>): Promise<boolean>;
public exists(db: Kysely<DB>, conditions?: Conditions<DB, ExtractTableAlias<DB, TB>>): Promise<boolean> {
// TODO: Could use `$if`.
if(conditions === undefined) {
return (db
.selectFrom(this._tableName)
.select(eb => eb.lit(true).as('exists'))
.limit(1)
.executeTakeFirst()
// TODO: Why `any`?
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.then((result: any): boolean => (result !== undefined)));
} else {
return (db
.selectFrom(this._tableName)
.select(eb => eb.lit(true).as('exists'))
.where(this._normalizeConditions(conditions))
.limit(1)
.executeTakeFirst()
// TODO: Why `any`?
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.then((result: any): boolean => (result !== undefined)));
}
}
// Update
//
public update(db: Kysely<DB>, conditions: Conditions<DB, ExtractTableAlias<DB, TB>>, value: UpdateObject<DB, ExtractTableAlias<DB, TB>>): Promise<UpdateResult[]>;
public update<Ret extends Returning<DB, ExtractTableAlias<DB, TB>>>(
db: Kysely<DB>,
conditions: Conditions<DB, ExtractTableAlias<DB, TB>>,
value: UpdateObject<DB, ExtractTableAlias<DB, TB>>,
returning: Ret
): Promise<SimplifySingleResult<ExtractKyselySelection<DB, ExtractTableAlias<DB, TB>, Ret>>>;
public update<Ret extends Returning<DB, ExtractTableAlias<DB, TB>>>(
db: Kysely<DB>,
conditions: Conditions<DB, ExtractTableAlias<DB, TB>>,
value: UpdateObject<DB, ExtractTableAlias<DB, TB>>,
returning?: Ret
): Promise<UpdateResult[] | SimplifySingleResult<ExtractKyselySelection<DB, ExtractTableAlias<DB, TB>, Ret>>> {
const where = this._normalizeConditions(conditions);
// TODO: Could use `$if`.
if(returning) {
return (db
.updateTable(this._tableName)
.set(value)
.where(where)
.returning(this._normalizeReturning(returning))
.execute() as Promise<UpdateResult[] | SimplifySingleResult<ExtractKyselySelection<DB, ExtractTableAlias<DB, TB>, Ret>>>);
} else {
return db
.updateTable(this._tableName)
.set(value)
.where(where)
.execute();
}
}
// Delete
//
public delete(db: Kysely<DB>): Promise<DeleteResult[]>;
public delete(db: Kysely<DB>, conditions: Conditions<DB, ExtractTableAlias<DB, TB>>): Promise<DeleteResult[]>;
public delete(db: Kysely<DB>, conditions?: Conditions<DB, ExtractTableAlias<DB, TB>>): Promise<DeleteResult[]> {
// TODO: Could use `$if`.
if(conditions) {
return db
.deleteFrom(this._tableName)
.where(this._normalizeConditions(conditions))
.execute();
} else {
return db
.deleteFrom(this._tableName)
.execute();
}
}
// Helpers
//
// eslint-disable-next-line @typescript-eslint/no-explicit-any
protected _resolveReturning<DB, TB extends AnyTable<DB>>(input: (Kysely<any> | Returning<DB, TB>)): Returning<DB, TB> {
if(input instanceof Kysely) {
return [];
}
return input;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
protected _resolveConditions<DB, TB extends AnyTable<DB>>(input: (Kysely<any> | Conditions<DB, TB>)): Conditions<DB, TB> {
if(input instanceof Kysely) {
return {};
}
return input;
}
protected _normalizeReturning<DB, TB extends AnyTable<DB>>(returning: Returning<DB, TB>): AnySimpleColumn<DB, TB>[] {
if(Array.isArray(returning)) {
return returning;
}
const result: AnySimpleColumn<DB, TB>[] = [];
for(const [columnName, value] of Object.entries(returning)) {
if((typeof value === 'boolean') && value) {
result.push(columnName as AnySimpleColumn<DB, TB>);
} else if(typeof value === 'string') {
result.push(`${columnName} as ${value}` as AnySimpleColumn<DB, TB>);
}
}
return result;
}
protected _normalizeUpsert(
upsert: Upsert<DB, TB>
): ((b: OnConflictBuilder<DB, TB>) => (OnConflictUpdateBuilder<OnConflictDatabase<DB, TB>, OnConflictTables<TB>> | OnConflictDoNothingBuilder<DB, TB>)) {
if(typeof upsert === 'function') {
// Callback function for `onConflict`.
return upsert;
}
return ((b: OnConflictBuilder<DB, TB>): (OnConflictUpdateBuilder<OnConflictDatabase<DB, TB>, OnConflictTables<TB>> | OnConflictDoNothingBuilder<DB, TB>) => {
const conflictColumns: AnyColumn<DB, TB>[] = (Array.isArray(upsert)
// `UpsertArray`.
// eslint-disable-next-line @typescript-eslint/no-misused-spread
? ([...upsert[0]] as AnyColumn<DB, TB>[])
// `UpsertObject`.
// eslint-disable-next-line @typescript-eslint/no-misused-spread
: ([...upsert.conflict] as AnyColumn<DB, TB>[]));
const updateColumns: AnyColumn<DB, TB>[] = (Array.isArray(upsert)
// `UpsertArray`.
// eslint-disable-next-line @typescript-eslint/no-misused-spread
? ([...upsert[1]] as AnyColumn<DB, TB>[])
// `UpsertObject`.
// eslint-disable-next-line @typescript-eslint/no-misused-spread
: ([...upsert.update] as AnyColumn<DB, TB>[]));
if(updateColumns.length === 0) {
return b.doNothing();
}
return b
.columns(conflictColumns)
// TODO: This is the suggested way.
// See https://kysely-org.github.io/kysely-apidoc/classes/InsertQueryBuilder.html#onConflict.
// .doUpdateSet(updateColumns.reduce(
// ((
// updateObj: UpdateObject<OnConflictDatabase<Database, Table>, OnConflictTables<Table>, OnConflictTables<Table>>,
// columnName
// ): UpdateObject<OnConflictDatabase<Database, Table>, OnConflictTables<Table>, OnConflictTables<Table>> => {
// (updateObj as any)[columnName] = ((
// eb: ExpressionBuilder<OnConflictDatabase<Database, Table>, OnConflictTables<Table>>
// ): OperandExpression<UpdateType<OnConflictDatabase<Database, Table>[OnConflictTables<Table>][any]>> => eb.ref(`excluded.${columnName}` as any));
//
// return updateObj;
// }),
// {}
// ));
.doUpdateSet((
b2: ExpressionBuilder<OnConflictDatabase<DB, TB>, OnConflictTables<TB>>
): UpdateObject<OnConflictDatabase<DB, TB>, OnConflictTables<TB>, OnConflictTables<TB>> =>
updateColumns.reduce(
((
result: UpdateObject<OnConflictDatabase<DB, TB>, OnConflictTables<TB>, OnConflictTables<TB>>,
key: AnyColumn<DB, TB>
): UpdateObject<OnConflictDatabase<DB, TB>, OnConflictTables<TB>, OnConflictTables<TB>> => {
// TODO: Why `as any`?
// TODO: Why `as any`?
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
(result as any)[key] = b2.ref(`excluded.${key}` as any);
return result;
}),
{}
));
});
}
protected _normalizeConditions<DB, TB extends AnyTable<DB>>(condition: Conditions<DB, TB>): OperandExpressionFactory<DB, TB, SqlBool> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const entries: [(keyof Conditions<DB, TB>), Condition<DB, TB, any>][] = (Object.entries(condition) as any);
if(entries.length === 0) {
// TODO: Test this.
return ((eb: ExpressionBuilder<DB, TB>): OperandExpression<SqlBool> => eb.val(true));
}
return ((eb: ExpressionBuilder<DB, TB>): OperandExpression<SqlBool> =>
eb.and(entries.reduce(
((result: OperandExpression<SqlBool>[], [columnName, condition]): OperandExpression<SqlBool>[] => {
result.push(this._normalizeCondition(columnName, condition));
return result;
}),
[]
)));
}
// TODO: Are all of these usages of `sql` vulnerable to SQL injection?
protected _normalizeCondition<CL extends ((keyof TB) & ReferenceExpression<DB, TB> & string)>(columnName: CL, condition: Condition<DB, TB, CL>): OperandExpression<SqlBool> {
if(typeof condition === 'string') {
// Unary comparison operator.
return sql<SqlBool>`(${sql.ref(columnName)} ${sql.raw(condition)})`;
// TODO: Why `as any`?
} else if(typeof condition === 'object') {
if(Array.isArray(condition)) {
const operator = condition[0];
if(BINARY_COMPARISON_OPERATORS.includes(operator) || PATTERN_MATCHING_OPERATORS.includes(operator)) {
// Binary comparison operator or pattern matching operator.
return sql<SqlBool>`(${sql.ref(columnName)} ${sql.raw(operator)} ${sql.val(condition[1])})`;
} else if(TERTIARY_COMPARISON_OPERATORS.includes(operator)) {
// Tertiary comparison operator.
const [value1, value2] = (Array.isArray(condition[1]) ? condition[1] : [condition[1], condition[2]]);
return sql<SqlBool>`(${sql.ref(columnName)} ${sql.raw(operator)} ${sql.val(value1)} and ${sql.val(value2)})`;
} else {
throw (new Error(`Unknown operator: ${operator}`));
}
} else {
const operator = condition.operator;
if(UNARY_COMPARISON_OPERATORS.includes(operator)) {
// Unary comparison operator.
return sql<SqlBool>`(${sql.ref(columnName)} ${sql.raw(operator)})`;
} else if(BINARY_COMPARISON_OPERATORS.includes(operator) || PATTERN_MATCHING_OPERATORS.includes(operator)) {
// Binary comparison operator or pattern matching operator.
return sql<SqlBool>`(${sql.ref(columnName)} ${sql.raw(operator)} ${sql.val((condition as {value: TB[CL];}).value)})`;
} else if(TERTIARY_COMPARISON_OPERATORS.includes(operator)) {
// Tertiary comparison operator.
const {value1, value2} = (condition as {
value1: TB[CL];
value2: TB[CL];
});
return sql<SqlBool>`(${sql.ref(columnName)} ${sql.raw(operator)} ${sql.val(value1)} and ${sql.val(value2)})`;
} else {
throw (new Error(`Unknown operator: ${operator}`));
}
}
}
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
throw (new Error(`Unknown condition: ${condition}`));
}
}
export {
Repository
};
import type {Selection} from 'kysely';
import type {AnySimpleColumn, AnyTable} from './types';
type ReturningObject<DB, TB extends AnyTable<DB>> = {
[Col in AnySimpleColumn<DB, TB>]?: (boolean | string);
};
type Returning<DB, TB extends AnyTable<DB>> = (AnySimpleColumn<DB, TB>[] | ReturningObject<DB, TB>);
type ReturningObjectToArray<DB, TB extends AnyTable<DB>, RetObj extends ReturningObject<DB, TB>> = {
[CL in (keyof RetObj)]: (RetObj[CL] extends true
? (CL & string) & AnySimpleColumn<DB, TB>
: (RetObj[CL] extends string
? `${CL & string} as ${RetObj[CL]}` & AnySimpleColumn<DB, TB>
: never));
}[keyof RetObj][];
type ExtractKyselySelection<DB, TB extends AnyTable<DB>, Ret extends Returning<DB, TB>> =
(Ret extends AnySimpleColumn<DB, TB>[]
? Selection<DB, TB, Ret>
: (Ret extends ReturningObject<DB, TB>
? ExtractKyselySelection<DB, TB, ReturningObjectToArray<DB, TB, Ret>>
: never));
export type {
ReturningObject,
Returning,
ReturningObjectToArray,
ExtractKyselySelection
};
import type {AnyAliasedColumn, AnyAliasedColumnWithTable, AnyColumnWithTable} from 'kysely/dist/cjs/util/type-utils';
import type {AnyColumn, ExpressionBuilder, OperandExpression} from 'kysely';
type AnyTable<DB> = ({
[TB in (keyof DB)]: TB;
}[keyof DB] & string);
type AnySimpleColumnUnaliased<DB, TB extends AnyTable<DB>> = (AnyColumn<DB, TB> | AnyColumnWithTable<DB, TB>);
type AnySimpleColumnAliased<DB, TB extends AnyTable<DB>> = (AnyAliasedColumn<DB, TB> | AnyAliasedColumnWithTable<DB, TB>);
type AnySimpleColumn<DB, TB extends AnyTable<DB>> = (AnySimpleColumnUnaliased<DB, TB> | AnySimpleColumnAliased<DB, TB>);
// Not exported from Kysely.
type OperandExpressionFactory<DB, TB extends (keyof DB), V> = ((eb: ExpressionBuilder<DB, TB>) => OperandExpression<V>);
export type {
AnyTable,
AnySimpleColumnUnaliased,
AnySimpleColumnAliased,
AnySimpleColumn,
OperandExpressionFactory
};
import type {AnyColumn, OnConflictBuilder, OnConflictDatabase, OnConflictTables, OnConflictUpdateBuilder} from 'kysely';
import type {OnConflictDoNothingBuilder} from 'kysely/dist/cjs/query-builder/on-conflict-builder';
import type {AnyTable} from './types';
interface UpsertObject<DB, TB extends AnyTable<DB>> {
conflict: (AnyColumn<DB, TB> | AnyColumn<DB, TB>[]);
update: (AnyColumn<DB, TB> | AnyColumn<DB, TB>[]);
}
type UpsertArray<DB, TB extends AnyTable<DB>> = [
(AnyColumn<DB, TB> | AnyColumn<DB, TB>[]),
(AnyColumn<DB, TB> | AnyColumn<DB, TB>[])
];
type Upsert<DB, TB extends AnyTable<DB>> = (
((builder: OnConflictBuilder<DB, TB>) => (OnConflictUpdateBuilder<OnConflictDatabase<DB, TB>, OnConflictTables<TB>> | OnConflictDoNothingBuilder<DB, TB>))
| UpsertObject<DB, TB>
| UpsertArray<DB, TB>
);
export type {
UpsertObject,
UpsertArray,
Upsert
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment