2021-08-18 00:24:00 +08:00
|
|
|
import { SchemaLike, GeneratedSchema } from '@logto/schemas';
|
2022-01-25 13:34:20 +08:00
|
|
|
import { has } from '@silverhand/essentials';
|
2022-04-24 10:34:18 +00:00
|
|
|
import { IdentifierSqlToken, sql } from 'slonik';
|
2021-08-30 11:30:54 +08:00
|
|
|
|
2022-04-19 21:49:20 +08:00
|
|
|
import envSet from '@/env-set';
|
2022-03-02 15:44:57 +08:00
|
|
|
import { InsertionError } from '@/errors/SlonikError';
|
2021-09-16 23:48:06 +08:00
|
|
|
import assertThat from '@/utils/assert-that';
|
2021-08-30 11:30:54 +08:00
|
|
|
|
2021-08-18 00:24:00 +08:00
|
|
|
import {
|
|
|
|
conditionalSql,
|
|
|
|
convertToIdentifiers,
|
2021-08-26 13:05:23 +08:00
|
|
|
convertToPrimitiveOrSql,
|
2021-08-18 00:24:00 +08:00
|
|
|
excludeAutoSetFields,
|
|
|
|
OmitAutoSetFields,
|
|
|
|
} from './utils';
|
|
|
|
|
2022-04-24 10:34:18 +00:00
|
|
|
const setExcluded = (...fields: IdentifierSqlToken[]) =>
|
2021-08-18 00:24:00 +08:00
|
|
|
sql.join(
|
|
|
|
fields.map((field) => sql`${field}=excluded.${field}`),
|
|
|
|
sql`, `
|
|
|
|
);
|
|
|
|
|
|
|
|
type OnConflict = {
|
2022-04-24 10:34:18 +00:00
|
|
|
fields: IdentifierSqlToken[];
|
|
|
|
setExcludedFields: IdentifierSqlToken[];
|
2021-08-18 00:24:00 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
type InsertIntoConfigReturning = {
|
|
|
|
returning: true;
|
|
|
|
onConflict?: OnConflict;
|
|
|
|
};
|
|
|
|
|
|
|
|
type InsertIntoConfig = {
|
|
|
|
returning?: false;
|
|
|
|
onConflict?: OnConflict;
|
|
|
|
};
|
|
|
|
|
|
|
|
interface BuildInsertInto {
|
2021-12-08 11:11:27 +08:00
|
|
|
<Schema extends SchemaLike, ReturnType extends SchemaLike>(
|
2021-08-18 00:24:00 +08:00
|
|
|
{ fieldKeys, ...rest }: GeneratedSchema<Schema>,
|
|
|
|
config: InsertIntoConfigReturning
|
2021-12-08 11:11:27 +08:00
|
|
|
): (data: OmitAutoSetFields<Schema>) => Promise<ReturnType>;
|
2021-08-27 00:33:13 +08:00
|
|
|
<Schema extends SchemaLike>(
|
2021-08-18 00:24:00 +08:00
|
|
|
{ fieldKeys, ...rest }: GeneratedSchema<Schema>,
|
|
|
|
config?: InsertIntoConfig
|
|
|
|
): (data: OmitAutoSetFields<Schema>) => Promise<void>;
|
|
|
|
}
|
|
|
|
|
2021-12-08 11:11:27 +08:00
|
|
|
export const buildInsertInto: BuildInsertInto = <
|
|
|
|
Schema extends SchemaLike,
|
|
|
|
ReturnType extends SchemaLike
|
|
|
|
>(
|
2022-03-02 15:44:57 +08:00
|
|
|
schema: GeneratedSchema<Schema>,
|
2021-08-18 00:24:00 +08:00
|
|
|
config?: InsertIntoConfig | InsertIntoConfigReturning
|
|
|
|
) => {
|
2022-03-02 15:44:57 +08:00
|
|
|
const { fieldKeys, ...rest } = schema;
|
2021-08-18 00:24:00 +08:00
|
|
|
const { table, fields } = convertToIdentifiers(rest);
|
|
|
|
const keys = excludeAutoSetFields(fieldKeys);
|
|
|
|
const returning = Boolean(config?.returning);
|
|
|
|
const onConflict = config?.onConflict;
|
|
|
|
|
2021-12-08 11:11:27 +08:00
|
|
|
return async (data: OmitAutoSetFields<Schema>): Promise<ReturnType | void> => {
|
2022-01-25 13:34:20 +08:00
|
|
|
const insertingKeys = keys.filter((key) => has(data, key));
|
2021-08-27 00:33:13 +08:00
|
|
|
const {
|
|
|
|
rows: [entry],
|
2022-04-19 21:49:20 +08:00
|
|
|
} = await envSet.pool.query<ReturnType>(sql`
|
2021-12-20 14:20:23 +08:00
|
|
|
insert into ${table} (${sql.join(
|
2022-01-25 13:34:20 +08:00
|
|
|
insertingKeys.map((key) => fields[key]),
|
2021-08-18 00:24:00 +08:00
|
|
|
sql`, `
|
|
|
|
)})
|
2021-12-20 14:20:23 +08:00
|
|
|
values (${sql.join(
|
2022-01-25 13:34:20 +08:00
|
|
|
insertingKeys.map((key) => convertToPrimitiveOrSql(key, data[key] ?? null)),
|
2021-12-20 14:20:23 +08:00
|
|
|
sql`, `
|
|
|
|
)})
|
|
|
|
${conditionalSql(returning, () => sql`returning *`)}
|
|
|
|
${conditionalSql(
|
|
|
|
onConflict,
|
|
|
|
({ fields, setExcludedFields }) => sql`
|
|
|
|
on conflict (${sql.join(fields, sql`, `)}) do update
|
|
|
|
set ${setExcluded(...setExcludedFields)}
|
|
|
|
`
|
|
|
|
)}
|
2021-08-18 00:24:00 +08:00
|
|
|
`);
|
|
|
|
|
2022-03-02 15:44:57 +08:00
|
|
|
assertThat(!returning || entry, new InsertionError(schema, data));
|
2022-01-27 19:26:34 +08:00
|
|
|
|
2021-08-18 00:24:00 +08:00
|
|
|
return entry;
|
|
|
|
};
|
|
|
|
};
|