mirror of
https://github.com/logto-io/logto.git
synced 2025-02-17 22:04:19 -05:00
feat: remove redundant fields and add TS type support in generated files
This commit is contained in:
parent
f180f42d65
commit
6e7a4700d9
6 changed files with 61 additions and 38 deletions
|
@ -1,14 +1,13 @@
|
||||||
// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
|
||||||
|
import { OidcModelInstancePayload } from '../foundations';
|
||||||
|
|
||||||
export type OidcModelInstanceDBEntry = {
|
export type OidcModelInstanceDBEntry = {
|
||||||
modelName: string;
|
modelName: string;
|
||||||
id: string;
|
id: string;
|
||||||
payload: Record<string, unknown>;
|
payload: OidcModelInstancePayload;
|
||||||
expiresAt: number;
|
expiresAt: number;
|
||||||
consumedAt?: number;
|
consumedAt?: number;
|
||||||
userCode?: string;
|
|
||||||
uid?: string;
|
|
||||||
grantId?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const OidcModelInstances = Object.freeze({
|
export const OidcModelInstances = Object.freeze({
|
||||||
|
@ -19,18 +18,6 @@ export const OidcModelInstances = Object.freeze({
|
||||||
payload: 'payload',
|
payload: 'payload',
|
||||||
expiresAt: 'expires_at',
|
expiresAt: 'expires_at',
|
||||||
consumedAt: 'consumed_at',
|
consumedAt: 'consumed_at',
|
||||||
userCode: 'user_code',
|
|
||||||
uid: 'uid',
|
|
||||||
grantId: 'grant_id',
|
|
||||||
},
|
},
|
||||||
fieldKeys: [
|
fieldKeys: ['modelName', 'id', 'payload', 'expiresAt', 'consumedAt'],
|
||||||
'modelName',
|
|
||||||
'id',
|
|
||||||
'payload',
|
|
||||||
'expiresAt',
|
|
||||||
'consumedAt',
|
|
||||||
'userCode',
|
|
||||||
'uid',
|
|
||||||
'grantId',
|
|
||||||
],
|
|
||||||
} as const);
|
} as const);
|
||||||
|
|
6
packages/schemas/src/foundations.ts
Normal file
6
packages/schemas/src/foundations.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export type OidcModelInstancePayload = {
|
||||||
|
[key: string]: unknown;
|
||||||
|
userCode?: string;
|
||||||
|
uid?: string;
|
||||||
|
grantId?: string;
|
||||||
|
};
|
|
@ -12,6 +12,7 @@ type Field = {
|
||||||
name: string;
|
name: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
customType?: string;
|
customType?: string;
|
||||||
|
tsType?: string;
|
||||||
required: boolean;
|
required: boolean;
|
||||||
isArray: boolean;
|
isArray: boolean;
|
||||||
};
|
};
|
||||||
|
@ -56,8 +57,7 @@ const generate = async () => {
|
||||||
.split(';')
|
.split(';')
|
||||||
.map((value) => normalizeWhitespaces(value));
|
.map((value) => normalizeWhitespaces(value));
|
||||||
const tables = statements
|
const tables = statements
|
||||||
.map((value) => value.toLowerCase())
|
.filter((value) => value.toLowerCase().startsWith('create table'))
|
||||||
.filter((value) => value.startsWith('create table'))
|
|
||||||
.map((value) => findFirstParentheses(value))
|
.map((value) => findFirstParentheses(value))
|
||||||
.filter((value): value is NonNullable<typeof value> => Boolean(value))
|
.filter((value): value is NonNullable<typeof value> => Boolean(value))
|
||||||
.map<Table>(({ prefix, body }) => {
|
.map<Table>(({ prefix, body }) => {
|
||||||
|
@ -69,23 +69,35 @@ const generate = async () => {
|
||||||
.map((value) => normalizeWhitespaces(value))
|
.map((value) => normalizeWhitespaces(value))
|
||||||
.filter((value) =>
|
.filter((value) =>
|
||||||
['primary', 'foreign', 'unique', 'exclude', 'check'].every(
|
['primary', 'foreign', 'unique', 'exclude', 'check'].every(
|
||||||
(constraint) => !value.startsWith(constraint + ' ')
|
(constraint) => !value.toLowerCase().startsWith(constraint + ' ')
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.map<Field>((value) => {
|
.map<Field>((value) => {
|
||||||
const [name, type, ...rest] = value.split(' ');
|
const [nameRaw, typeRaw, ...rest] = value.split(' ');
|
||||||
assert(name && type, 'Missing column name or type: ' + value);
|
assert(nameRaw && typeRaw, 'Missing column name or type: ' + value);
|
||||||
|
|
||||||
|
const name = nameRaw.toLowerCase();
|
||||||
|
const type = typeRaw.toLowerCase();
|
||||||
const restJoined = rest.join(' ');
|
const restJoined = rest.join(' ');
|
||||||
|
const restLowercased = restJoined.toLowerCase();
|
||||||
// CAUTION: Only works for single dimension arrays
|
// CAUTION: Only works for single dimension arrays
|
||||||
const isArray = Boolean(/\[.*]/.test(type)) || restJoined.includes('array');
|
const isArray = Boolean(/\[.*]/.test(type)) || restLowercased.includes('array');
|
||||||
const required = restJoined.includes('not null');
|
const required = restLowercased.includes('not null');
|
||||||
const primitiveType = getType(type);
|
const primitiveType = getType(type);
|
||||||
|
const tsType = /\/\* @use (.*) \*\//.exec(restJoined)?.[1];
|
||||||
|
|
||||||
|
assert(
|
||||||
|
!(!primitiveType && tsType),
|
||||||
|
`TS type can only be applied on primitive types, found ${
|
||||||
|
tsType ?? 'N/A'
|
||||||
|
} over ${type}`
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
type: primitiveType,
|
type: primitiveType,
|
||||||
customType: conditional(!primitiveType && type),
|
customType: conditional(!primitiveType && type),
|
||||||
|
tsType,
|
||||||
isArray,
|
isArray,
|
||||||
required,
|
required,
|
||||||
};
|
};
|
||||||
|
@ -116,11 +128,14 @@ const generate = async () => {
|
||||||
|
|
||||||
const generatedDir = 'src/db-entries';
|
const generatedDir = 'src/db-entries';
|
||||||
const generatedTypesFilename = 'custom-types';
|
const generatedTypesFilename = 'custom-types';
|
||||||
|
const tsTypesFilename = '../foundations';
|
||||||
const header = '// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n\n';
|
const header = '// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n\n';
|
||||||
const getOutputFileName = (file: string) => pluralize(file.slice(0, -4).replace(/_/g, '-'), 1);
|
const getOutputFileName = (file: string) => pluralize(file.slice(0, -4).replace(/_/g, '-'), 1);
|
||||||
|
|
||||||
await fs.rmdir(generatedDir, { recursive: true });
|
await fs.rmdir(generatedDir, { recursive: true });
|
||||||
await fs.mkdir(generatedDir, { recursive: true });
|
await fs.mkdir(generatedDir, { recursive: true });
|
||||||
|
|
||||||
|
// Postgres custom types
|
||||||
const allTypes = generated
|
const allTypes = generated
|
||||||
.flatMap((data) => data[1].types)
|
.flatMap((data) => data[1].types)
|
||||||
.map<GeneratedType>((type) => ({
|
.map<GeneratedType>((type) => ({
|
||||||
|
@ -149,13 +164,18 @@ const generate = async () => {
|
||||||
// Generate DB entry types
|
// Generate DB entry types
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
generated.map(async ([file, { tables }]) => {
|
generated.map(async ([file, { tables }]) => {
|
||||||
|
const tsTypes: string[] = [];
|
||||||
const customTypes: string[] = [];
|
const customTypes: string[] = [];
|
||||||
const tableWithTypes = tables.map<TableWithType>(({ fields, ...rest }) => ({
|
const tableWithTypes = tables.map<TableWithType>(({ fields, ...rest }) => ({
|
||||||
...rest,
|
...rest,
|
||||||
fields: fields.map(({ type, customType, ...rest }) => {
|
fields: fields.map(({ type, customType, tsType, ...rest }) => {
|
||||||
const finalType = type ?? allTypes.find(({ name }) => name === customType)?.tsName;
|
const finalType =
|
||||||
|
tsType ?? type ?? allTypes.find(({ name }) => name === customType)?.tsName;
|
||||||
assert(finalType, `Type ${customType ?? 'N/A'} not found`);
|
assert(finalType, `Type ${customType ?? 'N/A'} not found`);
|
||||||
if (type === undefined) {
|
|
||||||
|
if (tsType) {
|
||||||
|
tsTypes.push(tsType);
|
||||||
|
} else if (type === undefined) {
|
||||||
customTypes.push(finalType);
|
customTypes.push(finalType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +183,17 @@ const generate = async () => {
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const importTsTypes = conditionalString(
|
||||||
|
tsTypes.length > 0 &&
|
||||||
|
[
|
||||||
|
'import {',
|
||||||
|
uniq(tsTypes)
|
||||||
|
.map((value) => ` ${value}`)
|
||||||
|
.join(',\n'),
|
||||||
|
`} from './${tsTypesFilename}';`,
|
||||||
|
].join('\n') + '\n\n'
|
||||||
|
);
|
||||||
|
|
||||||
const importTypes = conditionalString(
|
const importTypes = conditionalString(
|
||||||
customTypes.length > 0 &&
|
customTypes.length > 0 &&
|
||||||
[
|
[
|
||||||
|
@ -176,6 +207,7 @@ const generate = async () => {
|
||||||
|
|
||||||
const content =
|
const content =
|
||||||
header +
|
header +
|
||||||
|
importTsTypes +
|
||||||
importTypes +
|
importTypes +
|
||||||
tableWithTypes
|
tableWithTypes
|
||||||
.map(({ name, fields }) =>
|
.map(({ name, fields }) =>
|
||||||
|
|
|
@ -28,7 +28,7 @@ export const removeParentheses = (value: string) =>
|
||||||
}
|
}
|
||||||
).result;
|
).result;
|
||||||
|
|
||||||
type ParenthesesMatch = { body: string; prefix: string };
|
export type ParenthesesMatch = { body: string; prefix: string };
|
||||||
|
|
||||||
export const findFirstParentheses = (value: string): Optional<ParenthesesMatch> => {
|
export const findFirstParentheses = (value: string): Optional<ParenthesesMatch> => {
|
||||||
const { matched, count, ...rest } = Object.values(value).reduce<{
|
const { matched, count, ...rest } = Object.values(value).reduce<{
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
|
export * from './foundations';
|
||||||
export * from './db-entries';
|
export * from './db-entries';
|
||||||
|
|
|
@ -1,29 +1,26 @@
|
||||||
create table oidc_model_instances (
|
create table oidc_model_instances (
|
||||||
model_name varchar(64) not null,
|
model_name varchar(64) not null,
|
||||||
id varchar(128) not null,
|
id varchar(128) not null,
|
||||||
payload jsonb not null,
|
payload jsonb /* @use OidcModelInstancePayload */ not null,
|
||||||
expires_at bigint not null,
|
expires_at bigint not null,
|
||||||
consumed_at bigint,
|
consumed_at bigint,
|
||||||
user_code varchar(128),
|
|
||||||
uid varchar(128),
|
|
||||||
grant_id varchar(128),
|
|
||||||
primary key (model_name, id)
|
primary key (model_name, id)
|
||||||
);
|
);
|
||||||
|
|
||||||
create index oidc_model_instances__model_name_user_code
|
create index oidc_model_instances__model_name_payload_user_code
|
||||||
on oidc_model_instances (
|
on oidc_model_instances (
|
||||||
model_name,
|
model_name,
|
||||||
user_code
|
(payload->>'userCode')
|
||||||
);
|
);
|
||||||
|
|
||||||
create index oidc_model_instances__model_name_uid
|
create index oidc_model_instances__model_name_payload_uid
|
||||||
on oidc_model_instances (
|
on oidc_model_instances (
|
||||||
model_name,
|
model_name,
|
||||||
uid
|
(payload->>'uid')
|
||||||
);
|
);
|
||||||
|
|
||||||
create index oidc_model_instances__model_name_grant_id
|
create index oidc_model_instances__model_name_payload_grant_id
|
||||||
on oidc_model_instances (
|
on oidc_model_instances (
|
||||||
model_name,
|
model_name,
|
||||||
grant_id
|
(payload->>'grantId')
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Reference in a new issue