immich/server/src/utils/database.ts

61 lines
2.2 KiB
TypeScript
Raw Normal View History

2025-01-09 11:15:41 -05:00
import { Expression, RawBuilder, sql, ValueExpression } from 'kysely';
import { InsertObject } from 'node_modules/kysely/dist/cjs';
import { DB } from 'src/db';
import { Between, LessThanOrEqual, MoreThanOrEqual } from 'typeorm';
2023-12-08 11:15:46 -05:00
/**
* Allows optional values unlike the regular Between and uses MoreThanOrEqual
* or LessThanOrEqual when only one parameter is specified.
*/
export function OptionalBetween<T>(from?: T, to?: T) {
if (from && to) {
return Between(from, to);
} else if (from) {
return MoreThanOrEqual(from);
} else if (to) {
return LessThanOrEqual(to);
}
}
2025-01-09 11:15:41 -05:00
// populated by the database repository at bootstrap
export const UPSERT_COLUMNS = {} as { [T in keyof DB]: { [K in keyof DB[T]]: RawBuilder<unknown> } };
/** Generates the columns for an upsert statement, excluding the conflict keys.
* Assumes that all entries have the same keys. */
export function mapUpsertColumns<T extends keyof DB>(
table: T,
entry: InsertObject<DB, T>,
conflictKeys: readonly (keyof DB[T])[],
) {
const columns = UPSERT_COLUMNS[table] as { [K in keyof DB[T]]: RawBuilder<unknown> };
const upsertColumns: Partial<Record<keyof typeof entry, RawBuilder<unknown>>> = {};
for (const entryColumn in entry) {
if (!conflictKeys.includes(entryColumn as keyof DB[T])) {
upsertColumns[entryColumn as keyof typeof entry] = columns[entryColumn as keyof DB[T]];
}
}
2025-01-09 11:15:41 -05:00
return upsertColumns as Expand<Record<keyof typeof entry, ValueExpression<DB, T, any>>>;
}
2025-01-09 11:15:41 -05:00
export const asUuid = (id: string | Expression<string>) => sql<string>`${id}::uuid`;
2025-01-09 11:15:41 -05:00
export const anyUuid = (ids: string[]) => sql<string>`any(${`{${ids}}`}::uuid[])`;
export const asVector = (embedding: number[]) => sql<string>`${`[${embedding}]`}::vector`;
export const unnest = (array: string[]) => sql<Record<string, string>>`unnest(array[${sql.join(array)}]::text[])`;
2025-01-09 11:15:41 -05:00
/**
* Mainly for type debugging to make VS Code display a more useful tooltip.
* Source: https://stackoverflow.com/a/69288824
*/
export type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
/** Recursive version of {@link Expand} from the same source. */
export type ExpandRecursively<T> = T extends object
? T extends infer O
? { [K in keyof O]: ExpandRecursively<O[K]> }
: never
: T;