0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-20 21:32:31 -05:00

fix(database): insertKeys filtering (#194)

* fix(database): insertKeys filtering

* fix: tests
This commit is contained in:
Wang Sijie 2022-01-25 13:34:20 +08:00 committed by GitHub
parent f85b922836
commit 67843f45db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 19 additions and 13 deletions

View file

@ -6,22 +6,25 @@ import RequestError from '@/errors/RequestError';
import { createTestPool } from '@/utils/test-utils'; import { createTestPool } from '@/utils/test-utils';
import { buildInsertInto } from './insert-into'; import { buildInsertInto } from './insert-into';
import { convertToIdentifiers, excludeAutoSetFields } from './utils'; import { convertToIdentifiers } from './utils';
describe('buildInsertInto()', () => { const buildExpectedInsertIntoSql = (keys: string[]) => [
const keys = excludeAutoSetFields(Users.fieldKeys);
const expectInsertIntoSql = [
`insert into "users" (${keys.map((key) => `"${decamelize(key)}"`).join(', ')})`, `insert into "users" (${keys.map((key) => `"${decamelize(key)}"`).join(', ')})`,
`values (${keys.map((_, index) => `$${index + 1}`).join(', ')})`, `values (${keys.map((_, index) => `$${index + 1}`).join(', ')})`,
]; ];
describe('buildInsertInto()', () => {
it('resolves a promise with `undefined` when `returning` is false', async () => { it('resolves a promise with `undefined` when `returning` is false', async () => {
const user: CreateUser = { id: 'foo', username: '456' };
const expectInsertIntoSql = buildExpectedInsertIntoSql(Object.keys(user));
const pool = createTestPool(expectInsertIntoSql.join('\n')); const pool = createTestPool(expectInsertIntoSql.join('\n'));
const insertInto = buildInsertInto(pool, Users); const insertInto = buildInsertInto(pool, Users);
await expect(insertInto({ id: 'foo', username: '456' })).resolves.toBe(undefined); await expect(insertInto(user)).resolves.toBe(undefined);
}); });
it('resolves a promise with `undefined` when `returning` is false and `onConflict` is enabled', async () => { it('resolves a promise with `undefined` when `returning` is false and `onConflict` is enabled', async () => {
const user: CreateUser = { id: 'foo', username: '456', primaryEmail: 'foo@bar.com' };
const expectInsertIntoSql = buildExpectedInsertIntoSql(Object.keys(user));
const pool = createTestPool( const pool = createTestPool(
[ [
...expectInsertIntoSql, ...expectInsertIntoSql,
@ -36,13 +39,12 @@ describe('buildInsertInto()', () => {
setExcludedFields: [fields.primaryEmail], setExcludedFields: [fields.primaryEmail],
}, },
}); });
await expect( await expect(insertInto(user)).resolves.toBe(undefined);
insertInto({ id: 'foo', username: '456', primaryEmail: 'foo@bar.com' })
).resolves.toBe(undefined);
}); });
it('resolves a promise with single entity when `returning` is true', async () => { it('resolves a promise with single entity when `returning` is true', async () => {
const user: CreateUser = { id: 'foo', username: '123', primaryEmail: 'foo@bar.com' }; const user: CreateUser = { id: 'foo', username: '123', primaryEmail: 'foo@bar.com' };
const expectInsertIntoSql = buildExpectedInsertIntoSql(Object.keys(user));
const pool = createTestPool( const pool = createTestPool(
[...expectInsertIntoSql, 'returning *'].join('\n'), [...expectInsertIntoSql, 'returning *'].join('\n'),
(_, [id, username, primaryEmail]) => ({ (_, [id, username, primaryEmail]) => ({
@ -58,6 +60,8 @@ describe('buildInsertInto()', () => {
}); });
it('throws `entity.create_failed` error with `undefined` when `returning` is true', async () => { it('throws `entity.create_failed` error with `undefined` when `returning` is true', async () => {
const user: CreateUser = { id: 'foo', username: '123', primaryEmail: 'foo@bar.com' };
const expectInsertIntoSql = buildExpectedInsertIntoSql(Object.keys(user));
const pool = createTestPool([...expectInsertIntoSql, 'returning *'].join('\n')); const pool = createTestPool([...expectInsertIntoSql, 'returning *'].join('\n'));
const insertInto = buildInsertInto(pool, Users, { returning: true }); const insertInto = buildInsertInto(pool, Users, { returning: true });

View file

@ -1,4 +1,5 @@
import { SchemaLike, GeneratedSchema } from '@logto/schemas'; import { SchemaLike, GeneratedSchema } from '@logto/schemas';
import { has } from '@silverhand/essentials';
import { DatabasePoolType, IdentifierSqlTokenType, sql } from 'slonik'; import { DatabasePoolType, IdentifierSqlTokenType, sql } from 'slonik';
import assertThat from '@/utils/assert-that'; import assertThat from '@/utils/assert-that';
@ -59,15 +60,16 @@ export const buildInsertInto: BuildInsertInto = <
const onConflict = config?.onConflict; const onConflict = config?.onConflict;
return async (data: OmitAutoSetFields<Schema>): Promise<ReturnType | void> => { return async (data: OmitAutoSetFields<Schema>): Promise<ReturnType | void> => {
const insertingKeys = keys.filter((key) => has(data, key));
const { const {
rows: [entry], rows: [entry],
} = await pool.query<ReturnType>(sql` } = await pool.query<ReturnType>(sql`
insert into ${table} (${sql.join( insert into ${table} (${sql.join(
keys.map((key) => fields[key]), insertingKeys.map((key) => fields[key]),
sql`, ` sql`, `
)}) )})
values (${sql.join( values (${sql.join(
keys.map((key) => convertToPrimitiveOrSql(key, data[key] ?? null)), insertingKeys.map((key) => convertToPrimitiveOrSql(key, data[key] ?? null)),
sql`, ` sql`, `
)}) )})
${conditionalSql(returning, () => sql`returning *`)} ${conditionalSql(returning, () => sql`returning *`)}