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

feat(core): allow jsonb partial update (#210)

* refactor(core): allow jsonb partial update

allow jsonb partial update

* fix(core): add comments

add comments

* fix(core): add non-nullable case

add non-nullable case assertation

* fix(core): use coalesce

use coalesce

* test(core): add ut

add ut
`
This commit is contained in:
simeng-li 2022-02-04 12:19:59 +08:00 committed by GitHub
parent d14f1a8841
commit 3d550b74dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 10 deletions

View file

@ -1,4 +1,4 @@
import { CreateUser, Users } from '@logto/schemas';
import { CreateUser, Users, Applications } from '@logto/schemas';
import RequestError from '@/errors/RequestError';
import { createTestPool } from '@/utils/test-utils';
@ -35,6 +35,24 @@ describe('buildUpdateWhere()', () => {
).resolves.toStrictEqual(user);
});
it('return query with jsonb partial update if input data type is jsonb', async () => {
const pool = createTestPool(
'update "applications"\nset\n"custom_client_metadata"=\ncoalesce("custom_client_metadata",\'{}\'::jsonb)|| $1\nwhere "id"=$2\nreturning *',
(_, [costumClientMetadata, id]) => ({
id: String(id),
costumClientMetadata: String(costumClientMetadata),
})
);
const updateWhere = buildUpdateWhere(pool, Applications, true);
await expect(
updateWhere({
set: { customClientMetadata: { idTokenTtl: 3600 } },
where: { id: 'foo' },
})
).resolves.toStrictEqual({ id: 'foo', costumClientMetadata: '{"idTokenTtl":3600}' });
});
it('throws an error when `undefined` found in values', async () => {
const pool = createTestPool(
'update "users"\nset "username"=$1\nwhere "id"=$2 and "username"=$3'

View file

@ -38,10 +38,25 @@ export const buildUpdateWhere: BuildUpdateWhere = <
const isKeyOfSchema = isKeyOf(schema);
const connectKeyValueWithEqualSign = (data: Partial<Schema>) =>
Object.entries(data)
.map(
([key, value]) =>
isKeyOfSchema(key) && sql`${fields[key]}=${convertToPrimitiveOrSql(key, value)}`
)
.map(([key, value]) => {
if (!isKeyOfSchema(key)) {
return;
}
if (value && typeof value === 'object' && !Array.isArray(value)) {
/**
* Jsonb || operator is used to shallow merge two jsonb types of data
* all jsonb data field must be non-nullable
* https://www.postgresql.org/docs/current/functions-json.html
*/
return sql`
${fields[key]}=
coalesce(${fields[key]},'{}'::jsonb)|| ${convertToPrimitiveOrSql(key, value)}
`;
}
return sql`${fields[key]}=${convertToPrimitiveOrSql(key, value)}`;
})
.filter((value): value is Truthy<typeof value> => notFalsy(value));
return async ({ set, where }: UpdateWhereData<Schema>) => {

View file

@ -84,14 +84,9 @@ export default function applicationRoutes<T extends AuthedRouter>(router: T) {
params: { id },
body,
} = ctx.guard;
const application = await findApplicationById(id);
ctx.body = await updateApplicationById(id, {
...body,
oidcClientMetadata: buildOidcClientMetadata({
...application.oidcClientMetadata,
...body.oidcClientMetadata,
}),
});
return next();