0
Fork 0
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:
Gao Sun 2021-07-04 21:17:55 +08:00
parent f180f42d65
commit 6e7a4700d9
No known key found for this signature in database
GPG key ID: 0F0EFA2E36639F31
6 changed files with 61 additions and 38 deletions

View file

@ -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);

View file

@ -0,0 +1,6 @@
export type OidcModelInstancePayload = {
[key: string]: unknown;
userCode?: string;
uid?: string;
grantId?: string;
};

View file

@ -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 }) =>

View file

@ -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<{

View file

@ -1 +1,2 @@
export * from './foundations';
export * from './db-entries'; export * from './db-entries';

View file

@ -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')
); );