mirror of
https://github.com/logto-io/logto.git
synced 2025-04-07 23:01:25 -05:00
test(core): add tests for database insert-into.ts
(#99)
This commit is contained in:
parent
bb040cbeee
commit
635fa92853
10 changed files with 135 additions and 20 deletions
|
@ -2,6 +2,7 @@
|
|||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
setupFilesAfterEnv: ['jest-matcher-specific-error'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: 'tsconfig.test.json',
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
"@types/oidc-provider": "^7.4.1",
|
||||
"eslint": "^7.30.0",
|
||||
"jest": "^27.0.6",
|
||||
"jest-matcher-specific-error": "^1.0.0",
|
||||
"lint-staged": "^11.1.1",
|
||||
"openapi-types": "^9.1.0",
|
||||
"prettier": "^2.3.2",
|
||||
|
|
68
packages/core/src/database/update-where.test.ts
Normal file
68
packages/core/src/database/update-where.test.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import { UserDBEntry, Users } from '@logto/schemas';
|
||||
|
||||
import RequestError from '@/errors/RequestError';
|
||||
import { createTestPool } from '@/utils/test-utils';
|
||||
|
||||
import { buildUpdateWhere } from './update-where';
|
||||
|
||||
describe('buildUpdateWhere()', () => {
|
||||
it('resolves a promise with `undefined` when `returning` is false', async () => {
|
||||
const pool = createTestPool(
|
||||
'update "users"\nset "username"=$1\nwhere "id"=$2 and "username"=$3'
|
||||
);
|
||||
const updateWhere = buildUpdateWhere(pool, Users);
|
||||
await expect(
|
||||
updateWhere({ set: { username: '123' }, where: { id: 'foo', username: '456' } })
|
||||
).resolves.toBe(undefined);
|
||||
});
|
||||
|
||||
it('resolves a promise with single entity when `returning` is true', async () => {
|
||||
const user: UserDBEntry = { id: 'foo', username: '123', primaryEmail: 'foo@bar.com' };
|
||||
const pool = createTestPool(
|
||||
'update "users"\nset "username"=$1, "primary_email"=$2\nwhere "id"=$3\nreturning *',
|
||||
(_, [username, primaryEmail, id]) => ({
|
||||
id: String(id),
|
||||
username: String(username),
|
||||
primaryEmail: String(primaryEmail),
|
||||
})
|
||||
);
|
||||
const updateWhere = buildUpdateWhere(pool, Users, true);
|
||||
await expect(
|
||||
updateWhere({ set: { username: '123', primaryEmail: 'foo@bar.com' }, where: { id: 'foo' } })
|
||||
).resolves.toStrictEqual(user);
|
||||
});
|
||||
|
||||
it('throws `entity.not_exists_with_id` error with `undefined` when `returning` is true', async () => {
|
||||
const pool = createTestPool('update "users"\nset "username"=$1\nwhere "id"=$2\nreturning *');
|
||||
const updateWhere = buildUpdateWhere(pool, Users, true);
|
||||
|
||||
await expect(
|
||||
updateWhere({ set: { username: '123' }, where: { id: 'foo' } })
|
||||
).rejects.toMatchError(
|
||||
new RequestError({
|
||||
code: 'entity.not_exists_with_id',
|
||||
name: Users.tableSingular,
|
||||
id: 'foo',
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('throws `entity.not_exists` error with `undefined` when `returning` is true and no id in where clause', async () => {
|
||||
const pool = createTestPool(
|
||||
'update "users"\nset "username"=$1\nwhere "username"=$2\nreturning *'
|
||||
);
|
||||
const updateWhere = buildUpdateWhere(pool, Users, true);
|
||||
|
||||
await expect(
|
||||
updateWhere({ set: { username: '123' }, where: { username: 'foo' } })
|
||||
).rejects.toMatchError(
|
||||
new RequestError({
|
||||
code: 'entity.not_exists',
|
||||
name: Users.tableSingular,
|
||||
id: undefined,
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,10 +1,9 @@
|
|||
import assert from 'assert';
|
||||
|
||||
import { notFalsy, Truthy } from '@logto/essentials';
|
||||
import { SchemaLike, GeneratedSchema } from '@logto/schemas';
|
||||
import { DatabasePoolType, sql } from 'slonik';
|
||||
|
||||
import RequestError from '@/errors/RequestError';
|
||||
import assert from '@/utils/assert';
|
||||
import { isKeyOf } from '@/utils/schema';
|
||||
|
||||
import { conditionalSql, convertToIdentifiers, convertToPrimitiveOrSql } from './utils';
|
||||
|
@ -48,18 +47,19 @@ export const buildUpdateWhere: BuildUpdateWhere = <Schema extends SchemaLike>(
|
|||
} = await pool.query<Schema>(sql`
|
||||
update ${table}
|
||||
set ${sql.join(connectKeyValueWithEqualSign(set), sql`, `)}
|
||||
where ${sql.join(connectKeyValueWithEqualSign(where), sql`, `)}
|
||||
where ${sql.join(connectKeyValueWithEqualSign(where), sql` and `)}
|
||||
${conditionalSql(returning, () => sql`returning *`)}
|
||||
`);
|
||||
|
||||
assert(
|
||||
!returning || entry,
|
||||
new RequestError({
|
||||
code: where.id ? 'entity.not_exists_with_id' : 'entity.not_exists',
|
||||
name: schema.tableSingular,
|
||||
id: where.id,
|
||||
status: 404,
|
||||
})
|
||||
() =>
|
||||
new RequestError({
|
||||
code: where.id ? 'entity.not_exists_with_id' : 'entity.not_exists',
|
||||
name: schema.tableSingular,
|
||||
id: where.id,
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
return entry;
|
||||
};
|
||||
|
|
16
packages/core/src/utils/assert.ts
Normal file
16
packages/core/src/utils/assert.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
// https://github.com/facebook/jest/issues/7547
|
||||
|
||||
export type AssertFunction = <E extends Error>(
|
||||
value: unknown,
|
||||
buildError: () => E
|
||||
) => asserts value;
|
||||
|
||||
const assert: AssertFunction = (value, buildError): asserts value => {
|
||||
if (!value) {
|
||||
// https://github.com/typescript-eslint/typescript-eslint/issues/3814
|
||||
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
||||
throw buildError();
|
||||
}
|
||||
};
|
||||
|
||||
export default assert;
|
|
@ -1,5 +1,3 @@
|
|||
import { AssertionError } from 'assert';
|
||||
|
||||
import { assertEnv, getEnv } from './env';
|
||||
|
||||
describe('getEnv()', () => {
|
||||
|
@ -26,8 +24,6 @@ describe('assertEnv()', () => {
|
|||
});
|
||||
|
||||
it("throws an error if env doesn't exist", () => {
|
||||
expect(() => assertEnv('BAR')).toThrow(
|
||||
new AssertionError({ message: 'env variable BAR not found' })
|
||||
);
|
||||
expect(() => assertEnv('BAR')).toThrow('env variable BAR not found');
|
||||
});
|
||||
});
|
||||
|
|
23
packages/core/src/utils/test-utils.ts
Normal file
23
packages/core/src/utils/test-utils.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { createMockPool, createMockQueryResult, QueryResultRowType } from 'slonik';
|
||||
import { PrimitiveValueExpressionType } from 'slonik/dist/src/types.d';
|
||||
|
||||
export const createTestPool = <T extends QueryResultRowType>(
|
||||
expectSql?: string,
|
||||
returning?: T | ((sql: string, values: readonly PrimitiveValueExpressionType[]) => T)
|
||||
) =>
|
||||
createMockPool({
|
||||
query: async (sql, values) => {
|
||||
if (expectSql) {
|
||||
expect(
|
||||
sql
|
||||
.split('\n')
|
||||
.map((row) => row.trim())
|
||||
.filter((row) => row)
|
||||
).toEqual(expectSql.split('\n'));
|
||||
}
|
||||
|
||||
return createMockQueryResult(
|
||||
returning ? [typeof returning === 'function' ? returning(sql, values) : returning] : []
|
||||
);
|
||||
},
|
||||
});
|
|
@ -1,5 +1,12 @@
|
|||
{
|
||||
"extends": "./tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"types": [
|
||||
"node",
|
||||
"jest",
|
||||
"jest-matcher-specific-error"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
{
|
||||
"extends": "./tsconfig.base",
|
||||
"extends": "./tsconfig",
|
||||
"compilerOptions": {
|
||||
"isolatedModules": false
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.test.ts"
|
||||
]
|
||||
"isolatedModules": false,
|
||||
}
|
||||
}
|
||||
|
|
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
|
@ -42,6 +42,7 @@ importers:
|
|||
got: ^11.8.2
|
||||
i18next: ^20.3.5
|
||||
jest: ^27.0.6
|
||||
jest-matcher-specific-error: ^1.0.0
|
||||
jose: ^3.14.3
|
||||
koa: ^2.13.1
|
||||
koa-body: ^4.2.0
|
||||
|
@ -102,6 +103,7 @@ importers:
|
|||
'@types/oidc-provider': 7.4.2
|
||||
eslint: 7.31.0
|
||||
jest: 27.0.6
|
||||
jest-matcher-specific-error: 1.0.0
|
||||
lint-staged: 11.1.1
|
||||
openapi-types: 9.1.0
|
||||
prettier: 2.3.2
|
||||
|
@ -9584,6 +9586,10 @@ packages:
|
|||
pretty-format: 27.0.6
|
||||
dev: true
|
||||
|
||||
/jest-matcher-specific-error/1.0.0:
|
||||
resolution: {integrity: sha512-thJdy9ibhDo8k+0arFalNCQBJ0u7eqTfpTzS2MzL3iCLmbRCkI+yhhKSiAxEi55e5ZUyf01ySa0fMqzF+sblAw==}
|
||||
dev: true
|
||||
|
||||
/jest-matcher-utils/26.6.2:
|
||||
resolution: {integrity: sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==}
|
||||
engines: {node: '>= 10.14.2'}
|
||||
|
|
Loading…
Add table
Reference in a new issue