2021-08-17 11:24:00 -05:00
|
|
|
import { Falsy, notFalsy } from '@logto/essentials';
|
|
|
|
import { SchemaValuePrimitive, SchemaValue } from '@logto/schemas';
|
|
|
|
import { sql, SqlSqlTokenType } from 'slonik';
|
|
|
|
import { FieldIdentifiers, Table } from './types';
|
2021-06-23 12:09:42 -05:00
|
|
|
|
2021-08-17 11:24:00 -05:00
|
|
|
export const conditionalSql = <T>(
|
|
|
|
value: T,
|
|
|
|
buildSql: (value: Exclude<T, Falsy>) => SqlSqlTokenType
|
|
|
|
) => (notFalsy(value) ? buildSql(value) : sql``);
|
|
|
|
|
|
|
|
export const autoSetFields = Object.freeze(['createdAt', 'updatedAt'] as const);
|
|
|
|
// `Except` type will require omit fields to be the key of given type
|
|
|
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
|
|
export type OmitAutoSetFields<T> = Omit<T, typeof autoSetFields[number]>;
|
|
|
|
export type ExcludeAutoSetFields<T> = Exclude<T, typeof autoSetFields[number]>;
|
|
|
|
export const excludeAutoSetFields = <T extends string>(fields: readonly T[]) =>
|
|
|
|
Object.freeze(
|
|
|
|
fields.filter(
|
|
|
|
(field): field is ExcludeAutoSetFields<T> =>
|
|
|
|
!(autoSetFields as readonly string[]).includes(field)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2021-08-17 11:45:46 -05:00
|
|
|
/**
|
|
|
|
* Note `undefined` is removed from the acceptable list,
|
|
|
|
* since you should NOT call this function if ignoring the field is the desired behavior.
|
|
|
|
* Calling this function with `null` means an explicit `null` setting in database is expected.
|
|
|
|
* @param value The value to convert.
|
|
|
|
* @returns A primitive that can be saved into database.
|
|
|
|
*/
|
|
|
|
export const convertToPrimitive = (
|
|
|
|
value: NonNullable<SchemaValue> | null
|
|
|
|
): NonNullable<SchemaValuePrimitive> | null => {
|
2021-08-17 11:24:00 -05:00
|
|
|
if (value === null) {
|
2021-08-17 11:45:46 -05:00
|
|
|
return null;
|
2021-08-17 11:24:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof value === 'object') {
|
|
|
|
return JSON.stringify(value);
|
|
|
|
}
|
2021-06-23 12:09:42 -05:00
|
|
|
|
2021-08-17 11:24:00 -05:00
|
|
|
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new Error(`Cannot convert to primitive from ${typeof value}`);
|
|
|
|
};
|
2021-07-04 08:52:20 -05:00
|
|
|
|
2021-06-25 12:39:02 -05:00
|
|
|
export const convertToIdentifiers = <T extends Table>(
|
|
|
|
{ table, fields }: T,
|
|
|
|
withPrefix = false
|
|
|
|
) => ({
|
2021-06-23 12:09:42 -05:00
|
|
|
table: sql.identifier([table]),
|
|
|
|
fields: Object.entries<string>(fields).reduce(
|
2021-06-25 12:39:02 -05:00
|
|
|
(previous, [key, value]) => ({
|
|
|
|
...previous,
|
|
|
|
[key]: sql.identifier(withPrefix ? [table, value] : [value]),
|
|
|
|
}),
|
2021-06-23 12:09:42 -05:00
|
|
|
// eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter
|
|
|
|
{} as FieldIdentifiers<keyof T['fields']>
|
|
|
|
),
|
|
|
|
});
|