mirror of
https://github.com/logto-io/logto.git
synced 2025-03-31 22:51:25 -05:00
fix(core): align jsonb replace mode (#1138)
This commit is contained in:
parent
ae0caa8f8b
commit
3cf34b5911
8 changed files with 15 additions and 85 deletions
|
@ -43,9 +43,8 @@ const updateApplication = buildUpdateWhere<CreateApplication, Application>(Appli
|
|||
|
||||
export const updateApplicationById = async (
|
||||
id: string,
|
||||
set: Partial<OmitAutoSetFields<CreateApplication>>,
|
||||
jsonbMode: 'replace' | 'merge' = 'merge'
|
||||
) => updateApplication({ set, where: { id }, jsonbMode });
|
||||
set: Partial<OmitAutoSetFields<CreateApplication>>
|
||||
) => updateApplication({ set, where: { id }, jsonbMode: 'replace' });
|
||||
|
||||
export const deleteApplicationById = async (id: string) => {
|
||||
const { rowCount } = await envSet.pool.query(sql`
|
||||
|
|
|
@ -16,12 +16,9 @@ export const getSetting = async () =>
|
|||
where ${fields.id}=${defaultSettingId}
|
||||
`);
|
||||
|
||||
export const updateSetting = async (
|
||||
setting: Partial<OmitAutoSetFields<CreateSetting>>,
|
||||
jsonbMode: 'replace' | 'merge' = 'merge'
|
||||
) => {
|
||||
export const updateSetting = async (setting: Partial<OmitAutoSetFields<CreateSetting>>) => {
|
||||
return buildUpdateWhere<CreateSetting, Setting>(
|
||||
Settings,
|
||||
true
|
||||
)({ set: setting, where: { id: defaultSettingId }, jsonbMode });
|
||||
)({ set: setting, where: { id: defaultSettingId }, jsonbMode: 'merge' });
|
||||
};
|
||||
|
|
|
@ -55,9 +55,7 @@ describe('sign-in-experience query', () => {
|
|||
/* eslint-disable sql/no-unsafe-query */
|
||||
const expectSql = `
|
||||
update "sign_in_experiences"
|
||||
set
|
||||
"terms_of_use"=
|
||||
coalesce("terms_of_use",'{}'::jsonb)|| $1
|
||||
set "terms_of_use"=$1
|
||||
where "id"=$2
|
||||
returning *
|
||||
`;
|
||||
|
|
|
@ -14,10 +14,8 @@ const updateSignInExperience = buildUpdateWhere<CreateSignInExperience, SignInEx
|
|||
|
||||
const id = 'default';
|
||||
|
||||
export const updateDefaultSignInExperience = async (
|
||||
set: Partial<CreateSignInExperience>,
|
||||
jsonbMode: 'replace' | 'merge' = 'merge'
|
||||
) => updateSignInExperience({ set, where: { id }, jsonbMode });
|
||||
export const updateDefaultSignInExperience = async (set: Partial<CreateSignInExperience>) =>
|
||||
updateSignInExperience({ set, where: { id }, jsonbMode: 'replace' });
|
||||
|
||||
export const findDefaultSignInExperience = async () =>
|
||||
envSet.pool.one<SignInExperience>(sql`
|
||||
|
|
|
@ -23,7 +23,6 @@ import {
|
|||
findUsers,
|
||||
updateUserById,
|
||||
deleteUserById,
|
||||
clearUserCustomDataById,
|
||||
deleteUserIdentity,
|
||||
} from './user';
|
||||
|
||||
|
@ -366,42 +365,6 @@ describe('user query', () => {
|
|||
await expect(deleteUserById(id)).rejects.toMatchError(new DeletionError(Users.table, id));
|
||||
});
|
||||
|
||||
it('clearUserCustomDataById', async () => {
|
||||
const id = 'foo';
|
||||
const expectSql = sql`
|
||||
update ${table}
|
||||
set ${fields.customData}='{}'::jsonb
|
||||
where ${fields.id}=$1
|
||||
`;
|
||||
|
||||
mockQuery.mockImplementationOnce(async (sql, values) => {
|
||||
expectSqlAssert(sql, expectSql.sql);
|
||||
expect(values).toEqual([id]);
|
||||
|
||||
return createMockQueryResult([dbvalue]);
|
||||
});
|
||||
|
||||
await clearUserCustomDataById(id);
|
||||
});
|
||||
|
||||
it('clearUserCustomDataById should throw when user can not be found by id', async () => {
|
||||
const id = 'foo';
|
||||
const expectSql = sql`
|
||||
update ${table}
|
||||
set ${fields.customData}='{}'::jsonb
|
||||
where ${fields.id}=$1
|
||||
`;
|
||||
|
||||
mockQuery.mockImplementationOnce(async (sql, values) => {
|
||||
expectSqlAssert(sql, expectSql.sql);
|
||||
expect(values).toEqual([id]);
|
||||
|
||||
return createMockQueryResult([]);
|
||||
});
|
||||
|
||||
await expect(clearUserCustomDataById(id)).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('deleteUserIdentity', async () => {
|
||||
const userId = 'foo';
|
||||
const target = 'connector1';
|
||||
|
|
|
@ -5,7 +5,7 @@ import { buildInsertInto } from '@/database/insert-into';
|
|||
import { buildUpdateWhere } from '@/database/update-where';
|
||||
import { conditionalSql, convertToIdentifiers, OmitAutoSetFields } from '@/database/utils';
|
||||
import envSet from '@/env-set';
|
||||
import { DeletionError, UpdateError } from '@/errors/SlonikError';
|
||||
import { DeletionError } from '@/errors/SlonikError';
|
||||
|
||||
const { table, fields } = convertToIdentifiers(Users);
|
||||
|
||||
|
@ -131,18 +131,6 @@ export const deleteUserById = async (id: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const clearUserCustomDataById = async (id: string) => {
|
||||
const { rowCount } = await envSet.pool.query<User>(sql`
|
||||
update ${table}
|
||||
set ${fields.customData}='{}'::jsonb
|
||||
where ${fields.id}=${id}
|
||||
`);
|
||||
|
||||
if (rowCount < 1) {
|
||||
throw new UpdateError(Users, { set: { customData: {} }, where: { id }, jsonbMode: 'replace' });
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteUserIdentity = async (userId: string, target: string) =>
|
||||
envSet.pool.one<User>(sql`
|
||||
update ${table}
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
updateUserById,
|
||||
deleteUserIdentity,
|
||||
deleteUserById,
|
||||
clearUserCustomDataById,
|
||||
} from '@/queries/user';
|
||||
import { createRequester } from '@/utils/test-utils';
|
||||
|
||||
|
@ -51,7 +50,6 @@ jest.mock('@/queries/user', () => ({
|
|||
...user,
|
||||
})
|
||||
),
|
||||
clearUserCustomDataById: jest.fn(),
|
||||
deleteUserIdentity: jest.fn(),
|
||||
}));
|
||||
|
||||
|
@ -169,15 +167,6 @@ describe('adminUserRoutes', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('PATCH /users/:userId should call clearUserCustomDataById if customData is present', async () => {
|
||||
const updateNameResponse = await userRequest.patch('/users/foo').send({ customData: {} });
|
||||
expect(updateNameResponse.status).toEqual(200);
|
||||
expect(updateNameResponse.body).toEqual({
|
||||
...mockUserResponse,
|
||||
});
|
||||
expect(clearUserCustomDataById).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('PATCH /users/:userId should updated with one field if the other is undefined', async () => {
|
||||
const name = 'Micheal';
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ import koaGuard from '@/middleware/koa-guard';
|
|||
import koaPagination from '@/middleware/koa-pagination';
|
||||
import { findRolesByRoleNames } from '@/queries/roles';
|
||||
import {
|
||||
clearUserCustomDataById,
|
||||
deleteUserById,
|
||||
deleteUserIdentity,
|
||||
findUsers,
|
||||
|
@ -124,11 +123,6 @@ export default function adminUserRoutes<T extends AuthedRouter>(router: T) {
|
|||
|
||||
await findUserById(userId);
|
||||
|
||||
// Clear customData to achieve full replacement
|
||||
if (body.customData) {
|
||||
await clearUserCustomDataById(userId);
|
||||
}
|
||||
|
||||
// Temp solution to validate the existence of input roleNames
|
||||
if (body.roleNames?.length) {
|
||||
const { roleNames } = body;
|
||||
|
@ -143,9 +137,13 @@ export default function adminUserRoutes<T extends AuthedRouter>(router: T) {
|
|||
}
|
||||
}
|
||||
|
||||
const user = await updateUserById(userId, {
|
||||
...body,
|
||||
});
|
||||
const user = await updateUserById(
|
||||
userId,
|
||||
{
|
||||
...body,
|
||||
},
|
||||
'replace'
|
||||
);
|
||||
|
||||
ctx.body = pick(user, ...userInfoSelectFields);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue