mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
refactor!: add systems table for global configs
This commit is contained in:
parent
d0399eb8a4
commit
c2c3faa248
8 changed files with 86 additions and 72 deletions
|
@ -22,7 +22,7 @@ await mockEsmWithActual('./utils.js', () => ({
|
|||
}));
|
||||
|
||||
const { getCurrentDatabaseAlterationTimestamp } = await mockEsmWithActual(
|
||||
'../../../queries/logto-config.js',
|
||||
'../../../queries/system.js',
|
||||
() => ({
|
||||
getCurrentDatabaseAlterationTimestamp: jest.fn(),
|
||||
})
|
||||
|
|
|
@ -31,6 +31,7 @@ export const updateValueByKey = async <T extends LogtoConfigKey>(
|
|||
sql`
|
||||
insert into ${table} (${fields.key}, ${fields.value})
|
||||
values (${key}, ${sql.jsonb(value)})
|
||||
on conflict (${fields.key}) do update set ${fields.value}=excluded.${fields.value}
|
||||
on conflict (${fields.tenantId}, ${fields.key})
|
||||
do update set ${fields.value}=excluded.${fields.value}
|
||||
`
|
||||
);
|
||||
|
|
|
@ -17,10 +17,11 @@ const pool = createMockPool({
|
|||
});
|
||||
const { table, fields } = convertToIdentifiers(Systems);
|
||||
const timestamp = 1_663_923_776;
|
||||
const systemsTableExists = async () => createMockQueryResult([{ regclass: true }]);
|
||||
|
||||
describe('getCurrentDatabaseAlterationTimestamp()', () => {
|
||||
it('returns 0 if query failed (table not found)', async () => {
|
||||
mockQuery.mockRejectedValueOnce({ code: '42P01' });
|
||||
mockQuery.mockImplementationOnce(systemsTableExists).mockRejectedValueOnce({ code: '42P01' });
|
||||
|
||||
await expect(getCurrentDatabaseAlterationTimestamp(pool)).resolves.toBe(0);
|
||||
});
|
||||
|
@ -30,12 +31,14 @@ describe('getCurrentDatabaseAlterationTimestamp()', () => {
|
|||
select * from ${table} where ${fields.key}=$1
|
||||
`;
|
||||
|
||||
mockQuery.mockImplementationOnce(async (sql, values) => {
|
||||
expectSqlAssert(sql, expectSql.sql);
|
||||
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
||||
mockQuery
|
||||
.mockImplementationOnce(systemsTableExists)
|
||||
.mockImplementationOnce(async (sql, values) => {
|
||||
expectSqlAssert(sql, expectSql.sql);
|
||||
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
||||
|
||||
return createMockQueryResult([]);
|
||||
});
|
||||
return createMockQueryResult([]);
|
||||
});
|
||||
|
||||
await expect(getCurrentDatabaseAlterationTimestamp(pool)).resolves.toBe(0);
|
||||
});
|
||||
|
@ -45,12 +48,14 @@ describe('getCurrentDatabaseAlterationTimestamp()', () => {
|
|||
select * from ${table} where ${fields.key}=$1
|
||||
`;
|
||||
|
||||
mockQuery.mockImplementationOnce(async (sql, values) => {
|
||||
expectSqlAssert(sql, expectSql.sql);
|
||||
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
||||
mockQuery
|
||||
.mockImplementationOnce(systemsTableExists)
|
||||
.mockImplementationOnce(async (sql, values) => {
|
||||
expectSqlAssert(sql, expectSql.sql);
|
||||
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
||||
|
||||
return createMockQueryResult([{ value: 'some_value' }]);
|
||||
});
|
||||
return createMockQueryResult([{ value: 'some_value' }]);
|
||||
});
|
||||
|
||||
await expect(getCurrentDatabaseAlterationTimestamp(pool)).resolves.toBe(0);
|
||||
});
|
||||
|
@ -60,13 +65,15 @@ describe('getCurrentDatabaseAlterationTimestamp()', () => {
|
|||
select * from ${table} where ${fields.key}=$1
|
||||
`;
|
||||
|
||||
mockQuery.mockImplementationOnce(async (sql, values) => {
|
||||
expectSqlAssert(sql, expectSql.sql);
|
||||
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
||||
mockQuery
|
||||
.mockImplementationOnce(systemsTableExists)
|
||||
.mockImplementationOnce(async (sql, values) => {
|
||||
expectSqlAssert(sql, expectSql.sql);
|
||||
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
||||
|
||||
// @ts-expect-error createMockQueryResult doesn't support jsonb
|
||||
return createMockQueryResult([{ value: { timestamp, updatedAt: 'now' } }]);
|
||||
});
|
||||
// @ts-expect-error createMockQueryResult doesn't support jsonb
|
||||
return createMockQueryResult([{ value: { timestamp, updatedAt: 'now' } }]);
|
||||
});
|
||||
|
||||
await expect(getCurrentDatabaseAlterationTimestamp(pool)).resolves.toEqual(timestamp);
|
||||
});
|
||||
|
@ -90,15 +97,17 @@ describe('updateDatabaseTimestamp()', () => {
|
|||
});
|
||||
|
||||
it('sends upsert sql with timestamp and updatedAt', async () => {
|
||||
mockQuery.mockImplementationOnce(async (sql, values) => {
|
||||
expectSqlAssert(sql, expectSql.sql);
|
||||
expect(values).toEqual([
|
||||
AlterationStateKey.AlterationState,
|
||||
JSON.stringify({ timestamp, updatedAt }),
|
||||
]);
|
||||
mockQuery
|
||||
.mockImplementationOnce(systemsTableExists)
|
||||
.mockImplementationOnce(async (sql, values) => {
|
||||
expectSqlAssert(sql, expectSql.sql);
|
||||
expect(values).toEqual([
|
||||
AlterationStateKey.AlterationState,
|
||||
JSON.stringify({ timestamp, updatedAt }),
|
||||
]);
|
||||
|
||||
return createMockQueryResult([]);
|
||||
});
|
||||
return createMockQueryResult([]);
|
||||
});
|
||||
|
||||
await updateDatabaseTimestamp(pool, timestamp);
|
||||
});
|
||||
|
|
|
@ -52,7 +52,7 @@ describe('buildUpdateWhere()', () => {
|
|||
|
||||
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 *',
|
||||
'update "applications"\nset\n"custom_client_metadata"=\ncoalesce("custom_client_metadata",\'{}\'::jsonb) || $1\nwhere "id"=$2\nreturning *',
|
||||
(_, [customClientMetadata, id]) => ({
|
||||
id: String(id),
|
||||
customClientMetadata: String(customClientMetadata),
|
||||
|
|
|
@ -16,7 +16,7 @@ export const createLogtoConfigQueries = (pool: CommonQueryMethods) => {
|
|||
const updateAdminConsoleConfig = async (value: Partial<AdminConsoleData>) =>
|
||||
pool.one<Record<string, unknown>>(sql`
|
||||
update ${table}
|
||||
set ${fields.value}=coalesce(${fields.value},'{}'::jsonb) || ${sql.jsonb(value)}
|
||||
set ${fields.value} = coalesce(${fields.value},'{}'::jsonb) || ${sql.jsonb(value)}
|
||||
where ${fields.key} = ${AdminConsoleConfigKey.AdminConsole}
|
||||
returning ${fields.value}
|
||||
`);
|
||||
|
|
|
@ -13,7 +13,8 @@ export default function logtoConfigRoutes<T extends AuthedRouter>(
|
|||
'/configs/admin-console',
|
||||
koaGuard({ response: adminConsoleDataGuard, status: 200 }),
|
||||
async (ctx, next) => {
|
||||
ctx.body = await getAdminConsoleConfig();
|
||||
const { value } = await getAdminConsoleConfig();
|
||||
ctx.body = value;
|
||||
|
||||
return next();
|
||||
}
|
||||
|
@ -27,7 +28,8 @@ export default function logtoConfigRoutes<T extends AuthedRouter>(
|
|||
status: 200,
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
ctx.body = await updateAdminConsoleConfig(ctx.guard.body);
|
||||
const { value } = await updateAdminConsoleConfig(ctx.guard.body);
|
||||
ctx.body = value;
|
||||
|
||||
return next();
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import type { AlterationScript } from '../lib/types/alteration.js';
|
|||
|
||||
const alteration: AlterationScript = {
|
||||
up: async (pool) => {
|
||||
/* Drop settings table */
|
||||
await pool.query(sql`
|
||||
insert into _logto_configs (key, value)
|
||||
select 'adminConsole', admin_console from settings
|
||||
|
@ -22,8 +23,45 @@ const alteration: AlterationScript = {
|
|||
alter column tenant_id drop default;
|
||||
`);
|
||||
await pool.query(sql`drop table settings cascade;`);
|
||||
|
||||
/* Create systems table */
|
||||
await pool.query(sql`
|
||||
create table systems (
|
||||
key varchar(256) not null,
|
||||
value jsonb not null default '{}'::jsonb,
|
||||
primary key (key)
|
||||
);
|
||||
|
||||
alter table _logto_configs rename to logto_configs;
|
||||
alter table logto_configs
|
||||
drop constraint _logto_configs_pkey,
|
||||
add primary key (tenant_id, key);
|
||||
alter table logto_configs
|
||||
rename constraint _logto_configs_tenant_id_fkey to logto_configs_tenant_id_fkey;
|
||||
`);
|
||||
|
||||
await pool.query(sql`
|
||||
insert into systems (key, value)
|
||||
select key, value from logto_configs
|
||||
where key='alterationState';
|
||||
`);
|
||||
|
||||
await pool.query(sql`
|
||||
delete from logto_configs
|
||||
where key='alterationState';
|
||||
`);
|
||||
},
|
||||
down: async (pool) => {
|
||||
/* Drop systems table */
|
||||
await pool.query(sql`
|
||||
insert into logto_configs (key, value)
|
||||
select key, value from systems
|
||||
where key='alterationState';
|
||||
drop table systems;
|
||||
alter table logto_configs rename to _logto_configs;
|
||||
`);
|
||||
|
||||
/* Restore settings table */
|
||||
await pool.query(sql`
|
||||
create table settings (
|
||||
tenant_id varchar(21) not null
|
||||
|
@ -52,9 +90,12 @@ const alteration: AlterationScript = {
|
|||
`);
|
||||
|
||||
await pool.query(sql`
|
||||
drop trigger set_tenant_id on _logto_configs;
|
||||
|
||||
alter table _logto_configs
|
||||
drop column tenant_id,
|
||||
drop trigger set_tenant_id;
|
||||
drop constraint logto_configs_pkey,
|
||||
drop column tenant_id cascade,
|
||||
add primary key (key);
|
||||
`);
|
||||
},
|
||||
};
|
|
@ -1,39 +0,0 @@
|
|||
import { sql } from 'slonik';
|
||||
|
||||
import type { AlterationScript } from '../lib/types/alteration.js';
|
||||
|
||||
const alteration: AlterationScript = {
|
||||
up: async (pool) => {
|
||||
await pool.query(sql`
|
||||
create table systems (
|
||||
key varchar(256) not null,
|
||||
value jsonb not null default '{}'::jsonb,
|
||||
primary key (key)
|
||||
);
|
||||
|
||||
alter table _logto_configs rename to logto_configs;
|
||||
`);
|
||||
|
||||
await pool.query(sql`
|
||||
insert into systems (key, value)
|
||||
select key, value from logto_configs
|
||||
where key='alterationState';
|
||||
`);
|
||||
|
||||
await pool.query(sql`
|
||||
delete from logto_configs
|
||||
where key='alterationState';
|
||||
`);
|
||||
},
|
||||
down: async (pool) => {
|
||||
await pool.query(sql`
|
||||
insert into _logto_configs (key, value)
|
||||
select key, value from systems
|
||||
where key='alterationState';
|
||||
drop table systems;
|
||||
alter table logto_configs rename to _logto_configs;
|
||||
`);
|
||||
},
|
||||
};
|
||||
|
||||
export default alteration;
|
Loading…
Reference in a new issue