mirror of
https://github.com/logto-io/logto.git
synced 2025-01-20 21:32:31 -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(
|
const { getCurrentDatabaseAlterationTimestamp } = await mockEsmWithActual(
|
||||||
'../../../queries/logto-config.js',
|
'../../../queries/system.js',
|
||||||
() => ({
|
() => ({
|
||||||
getCurrentDatabaseAlterationTimestamp: jest.fn(),
|
getCurrentDatabaseAlterationTimestamp: jest.fn(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -31,6 +31,7 @@ export const updateValueByKey = async <T extends LogtoConfigKey>(
|
||||||
sql`
|
sql`
|
||||||
insert into ${table} (${fields.key}, ${fields.value})
|
insert into ${table} (${fields.key}, ${fields.value})
|
||||||
values (${key}, ${sql.jsonb(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 { table, fields } = convertToIdentifiers(Systems);
|
||||||
const timestamp = 1_663_923_776;
|
const timestamp = 1_663_923_776;
|
||||||
|
const systemsTableExists = async () => createMockQueryResult([{ regclass: true }]);
|
||||||
|
|
||||||
describe('getCurrentDatabaseAlterationTimestamp()', () => {
|
describe('getCurrentDatabaseAlterationTimestamp()', () => {
|
||||||
it('returns 0 if query failed (table not found)', async () => {
|
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);
|
await expect(getCurrentDatabaseAlterationTimestamp(pool)).resolves.toBe(0);
|
||||||
});
|
});
|
||||||
|
@ -30,7 +31,9 @@ describe('getCurrentDatabaseAlterationTimestamp()', () => {
|
||||||
select * from ${table} where ${fields.key}=$1
|
select * from ${table} where ${fields.key}=$1
|
||||||
`;
|
`;
|
||||||
|
|
||||||
mockQuery.mockImplementationOnce(async (sql, values) => {
|
mockQuery
|
||||||
|
.mockImplementationOnce(systemsTableExists)
|
||||||
|
.mockImplementationOnce(async (sql, values) => {
|
||||||
expectSqlAssert(sql, expectSql.sql);
|
expectSqlAssert(sql, expectSql.sql);
|
||||||
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
||||||
|
|
||||||
|
@ -45,7 +48,9 @@ describe('getCurrentDatabaseAlterationTimestamp()', () => {
|
||||||
select * from ${table} where ${fields.key}=$1
|
select * from ${table} where ${fields.key}=$1
|
||||||
`;
|
`;
|
||||||
|
|
||||||
mockQuery.mockImplementationOnce(async (sql, values) => {
|
mockQuery
|
||||||
|
.mockImplementationOnce(systemsTableExists)
|
||||||
|
.mockImplementationOnce(async (sql, values) => {
|
||||||
expectSqlAssert(sql, expectSql.sql);
|
expectSqlAssert(sql, expectSql.sql);
|
||||||
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
||||||
|
|
||||||
|
@ -60,7 +65,9 @@ describe('getCurrentDatabaseAlterationTimestamp()', () => {
|
||||||
select * from ${table} where ${fields.key}=$1
|
select * from ${table} where ${fields.key}=$1
|
||||||
`;
|
`;
|
||||||
|
|
||||||
mockQuery.mockImplementationOnce(async (sql, values) => {
|
mockQuery
|
||||||
|
.mockImplementationOnce(systemsTableExists)
|
||||||
|
.mockImplementationOnce(async (sql, values) => {
|
||||||
expectSqlAssert(sql, expectSql.sql);
|
expectSqlAssert(sql, expectSql.sql);
|
||||||
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
expect(values).toEqual([AlterationStateKey.AlterationState]);
|
||||||
|
|
||||||
|
@ -90,7 +97,9 @@ describe('updateDatabaseTimestamp()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends upsert sql with timestamp and updatedAt', async () => {
|
it('sends upsert sql with timestamp and updatedAt', async () => {
|
||||||
mockQuery.mockImplementationOnce(async (sql, values) => {
|
mockQuery
|
||||||
|
.mockImplementationOnce(systemsTableExists)
|
||||||
|
.mockImplementationOnce(async (sql, values) => {
|
||||||
expectSqlAssert(sql, expectSql.sql);
|
expectSqlAssert(sql, expectSql.sql);
|
||||||
expect(values).toEqual([
|
expect(values).toEqual([
|
||||||
AlterationStateKey.AlterationState,
|
AlterationStateKey.AlterationState,
|
||||||
|
|
|
@ -52,7 +52,7 @@ describe('buildUpdateWhere()', () => {
|
||||||
|
|
||||||
it('return query with jsonb partial update if input data type is jsonb', async () => {
|
it('return query with jsonb partial update if input data type is jsonb', async () => {
|
||||||
const pool = createTestPool(
|
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]) => ({
|
(_, [customClientMetadata, id]) => ({
|
||||||
id: String(id),
|
id: String(id),
|
||||||
customClientMetadata: String(customClientMetadata),
|
customClientMetadata: String(customClientMetadata),
|
||||||
|
|
|
@ -16,7 +16,7 @@ export const createLogtoConfigQueries = (pool: CommonQueryMethods) => {
|
||||||
const updateAdminConsoleConfig = async (value: Partial<AdminConsoleData>) =>
|
const updateAdminConsoleConfig = async (value: Partial<AdminConsoleData>) =>
|
||||||
pool.one<Record<string, unknown>>(sql`
|
pool.one<Record<string, unknown>>(sql`
|
||||||
update ${table}
|
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}
|
where ${fields.key} = ${AdminConsoleConfigKey.AdminConsole}
|
||||||
returning ${fields.value}
|
returning ${fields.value}
|
||||||
`);
|
`);
|
||||||
|
|
|
@ -13,7 +13,8 @@ export default function logtoConfigRoutes<T extends AuthedRouter>(
|
||||||
'/configs/admin-console',
|
'/configs/admin-console',
|
||||||
koaGuard({ response: adminConsoleDataGuard, status: 200 }),
|
koaGuard({ response: adminConsoleDataGuard, status: 200 }),
|
||||||
async (ctx, next) => {
|
async (ctx, next) => {
|
||||||
ctx.body = await getAdminConsoleConfig();
|
const { value } = await getAdminConsoleConfig();
|
||||||
|
ctx.body = value;
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +28,8 @@ export default function logtoConfigRoutes<T extends AuthedRouter>(
|
||||||
status: 200,
|
status: 200,
|
||||||
}),
|
}),
|
||||||
async (ctx, next) => {
|
async (ctx, next) => {
|
||||||
ctx.body = await updateAdminConsoleConfig(ctx.guard.body);
|
const { value } = await updateAdminConsoleConfig(ctx.guard.body);
|
||||||
|
ctx.body = value;
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { AlterationScript } from '../lib/types/alteration.js';
|
||||||
|
|
||||||
const alteration: AlterationScript = {
|
const alteration: AlterationScript = {
|
||||||
up: async (pool) => {
|
up: async (pool) => {
|
||||||
|
/* Drop settings table */
|
||||||
await pool.query(sql`
|
await pool.query(sql`
|
||||||
insert into _logto_configs (key, value)
|
insert into _logto_configs (key, value)
|
||||||
select 'adminConsole', admin_console from settings
|
select 'adminConsole', admin_console from settings
|
||||||
|
@ -22,8 +23,45 @@ const alteration: AlterationScript = {
|
||||||
alter column tenant_id drop default;
|
alter column tenant_id drop default;
|
||||||
`);
|
`);
|
||||||
await pool.query(sql`drop table settings cascade;`);
|
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) => {
|
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`
|
await pool.query(sql`
|
||||||
create table settings (
|
create table settings (
|
||||||
tenant_id varchar(21) not null
|
tenant_id varchar(21) not null
|
||||||
|
@ -52,9 +90,12 @@ const alteration: AlterationScript = {
|
||||||
`);
|
`);
|
||||||
|
|
||||||
await pool.query(sql`
|
await pool.query(sql`
|
||||||
|
drop trigger set_tenant_id on _logto_configs;
|
||||||
|
|
||||||
alter table _logto_configs
|
alter table _logto_configs
|
||||||
drop column tenant_id,
|
drop constraint logto_configs_pkey,
|
||||||
drop trigger set_tenant_id;
|
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…
Add table
Reference in a new issue