Skip to content

Commit

Permalink
feat: generate columnTypes as const rather than Record
Browse files Browse the repository at this point in the history
This changes the '$Types' object generation to generate `as const`
objects rather than `Record`.

Using `as const` allows the type system itself to know the types of
columns statically, which it previously could not infer because the
specific values were lost due to the generic `Record` use.

This is a necessary change to enable the JSON column schema parsing to
only allow callers to specify schemas for JSON/JSONB columns. It's also
just better, I think, but I was unaware of it at the time the feature
was originally written.
  • Loading branch information
rintaun committed Apr 13, 2022
1 parent 51a2957 commit 8bda964
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 51 deletions.
66 changes: 33 additions & 33 deletions src/generator/__tests__/__snapshots__/Generator.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ export interface TableWithNoColumns {
}
export interface TableWithNoColumns$Insert {
}
export const TableWithNoColumns$Types: Record<keyof TableWithNoColumns, string> = {};
export const TableWithNoColumns$Types = {} as const;
export interface TableWithNumericId {
id: number;
}
export interface TableWithNumericId$Insert {
id?: number;
}
export const TableWithNumericId$Types: Record<keyof TableWithNumericId, string> = {
export const TableWithNumericId$Types = {
id: \\"int8\\"
};
} as const;
export interface TableWithCustomTypes {
enum_type: TestEnum;
enum_array_type: TestEnum[];
Expand All @@ -40,21 +40,21 @@ export interface TableWithCustomTypes$Insert {
table_type: TableWithUuidId;
table_array_type: TableWithUuidId[];
}
export const TableWithCustomTypes$Types: Record<keyof TableWithCustomTypes, string> = {
export const TableWithCustomTypes$Types = {
enum_type: \\"test_enum\\",
enum_array_type: \\"test_enum\\",
table_type: \\"table_with_uuid_id\\",
table_array_type: \\"table_with_uuid_id\\"
};
} as const;
export interface TableWithUuidId {
id: string;
}
export interface TableWithUuidId$Insert {
id?: string;
}
export const TableWithUuidId$Types: Record<keyof TableWithUuidId, string> = {
export const TableWithUuidId$Types = {
id: \\"uuid\\"
};
} as const;
export interface TableWithNullableFields {
nullable: string | null;
nullable_with_default: string | null;
Expand All @@ -67,12 +67,12 @@ export interface TableWithNullableFields$Insert {
nullable_array?: string[] | null;
nullable_array_with_default?: string[] | null;
}
export const TableWithNullableFields$Types: Record<keyof TableWithNullableFields, string> = {
export const TableWithNullableFields$Types = {
nullable: \\"text\\",
nullable_with_default: \\"text\\",
nullable_array: \\"text\\",
nullable_array_with_default: \\"text\\"
};
} as const;
export interface TableWithJsonJsonb<TJson = SerializableValueType, TJsonb = SerializableValueType> {
json: MapToSerializable<TJson>;
jsonb: MapToSerializable<TJsonb> | null;
Expand All @@ -81,10 +81,10 @@ export interface TableWithJsonJsonb$Insert<TJson = SerializableValueType, TJsonb
json: MapToSerializable<TJson>;
jsonb?: MapToSerializable<TJsonb> | null;
}
export const TableWithJsonJsonb$Types: Record<keyof TableWithJsonJsonb, string> = {
export const TableWithJsonJsonb$Types = {
json: \\"json\\",
jsonb: \\"jsonb\\"
};
} as const;
"
`;
Expand All @@ -106,16 +106,16 @@ export interface TableWithNoColumns {
}
export interface TableWithNoColumns$Insert {
}
export const TableWithNoColumns$Types: Record<keyof TableWithNoColumns, string> = {};
export const TableWithNoColumns$Types = {} as const;
export interface TableWithNumericId {
id: number;
}
export interface TableWithNumericId$Insert {
id?: number;
}
export const TableWithNumericId$Types: Record<keyof TableWithNumericId, string> = {
export const TableWithNumericId$Types = {
id: \\"int8\\"
};
} as const;
export interface TableWithCustomTypes {
enumType: TestEnum;
enumArrayType: TestEnum[];
Expand All @@ -128,21 +128,21 @@ export interface TableWithCustomTypes$Insert {
tableType: TableWithUuidId;
tableArrayType: TableWithUuidId[];
}
export const TableWithCustomTypes$Types: Record<keyof TableWithCustomTypes, string> = {
export const TableWithCustomTypes$Types = {
enumType: \\"test_enum\\",
enumArrayType: \\"test_enum\\",
tableType: \\"table_with_uuid_id\\",
tableArrayType: \\"table_with_uuid_id\\"
};
} as const;
export interface TableWithUuidId {
id: string;
}
export interface TableWithUuidId$Insert {
id?: string;
}
export const TableWithUuidId$Types: Record<keyof TableWithUuidId, string> = {
export const TableWithUuidId$Types = {
id: \\"uuid\\"
};
} as const;
export interface TableWithNullableFields {
nullable: string | null;
nullableWithDefault: string | null;
Expand All @@ -155,12 +155,12 @@ export interface TableWithNullableFields$Insert {
nullableArray?: string[] | null;
nullableArrayWithDefault?: string[] | null;
}
export const TableWithNullableFields$Types: Record<keyof TableWithNullableFields, string> = {
export const TableWithNullableFields$Types = {
nullable: \\"text\\",
nullableWithDefault: \\"text\\",
nullableArray: \\"text\\",
nullableArrayWithDefault: \\"text\\"
};
} as const;
export interface TableWithJsonJsonb<TJson = SerializableValueType, TJsonb = SerializableValueType> {
json: MapToSerializable<TJson>;
jsonb: MapToSerializable<TJsonb> | null;
Expand All @@ -169,10 +169,10 @@ export interface TableWithJsonJsonb$Insert<TJson = SerializableValueType, TJsonb
json: MapToSerializable<TJson>;
jsonb?: MapToSerializable<TJsonb> | null;
}
export const TableWithJsonJsonb$Types: Record<keyof TableWithJsonJsonb, string> = {
export const TableWithJsonJsonb$Types = {
json: \\"json\\",
jsonb: \\"jsonb\\"
};
} as const;
"
`;
Expand Down Expand Up @@ -308,29 +308,29 @@ export type SerializableValueType = SimpleValueType | {
export type MapToSerializable<T> = T extends SerializableValueType ? T : T extends Array<infer U> ? Array<MapToSerializable<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<MapToSerializable<U>> : T extends {
[K in keyof T]: K extends string ? T[K] extends SimpleValueType ? T[K] : T[K] extends Function ? never : MapToSerializable<T[K]> : never;
} ? T : never;
export const TableWithNoColumns$Types: Record<keyof TableWithNoColumns, string> = {};
export const TableWithNumericId$Types: Record<keyof TableWithNumericId, string> = {
export const TableWithNoColumns$Types = {} as const;
export const TableWithNumericId$Types = {
id: \\"int8\\"
};
export const TableWithCustomTypes$Types: Record<keyof TableWithCustomTypes, string> = {
} as const;
export const TableWithCustomTypes$Types = {
enum_type: \\"test_enum\\",
enum_array_type: \\"test_enum\\",
table_type: \\"table_with_uuid_id\\",
table_array_type: \\"table_with_uuid_id\\"
};
export const TableWithUuidId$Types: Record<keyof TableWithUuidId, string> = {
} as const;
export const TableWithUuidId$Types = {
id: \\"uuid\\"
};
export const TableWithNullableFields$Types: Record<keyof TableWithNullableFields, string> = {
} as const;
export const TableWithNullableFields$Types = {
nullable: \\"text\\",
nullable_with_default: \\"text\\",
nullable_array: \\"text\\",
nullable_array_with_default: \\"text\\"
};
export const TableWithJsonJsonb$Types: Record<keyof TableWithJsonJsonb, string> = {
} as const;
export const TableWithJsonJsonb$Types = {
json: \\"json\\",
jsonb: \\"jsonb\\"
};
} as const;
"
`;
Expand Down
12 changes: 6 additions & 6 deletions src/generator/__tests__/__snapshots__/integration.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ export interface TestTableOrder {
export interface TestTableOrder$Insert {
subsequent_table_type?: TestTableStandard | null;
}
export const TestTableOrder$Types: Record<keyof TestTableOrder, string> = {
export const TestTableOrder$Types = {
subsequent_table_type: \\"test_table_standard\\"
};
} as const;
export interface TestTableStandard<TJsonbTest = SerializableValueType> {
arr_test: string[] | null;
caseTest_upper: string | null;
Expand All @@ -44,7 +44,7 @@ export interface TestTableStandard$Insert<TJsonbTest = SerializableValueType> {
id?: number;
jsonb_test?: MapToSerializable<TJsonbTest> | null;
}
export const TestTableStandard$Types: Record<keyof TestTableStandard, string> = {
export const TestTableStandard$Types = {
arr_test: \\"text\\",
caseTest_upper: \\"text\\",
casetest_lower: \\"text\\",
Expand All @@ -53,7 +53,7 @@ export const TestTableStandard$Types: Record<keyof TestTableStandard, string> =
enum_test: \\"test_type_enum\\",
id: \\"int4\\",
jsonb_test: \\"jsonb\\"
};
} as const;
export interface TestTableTypes {
id: string;
table_arr_test: TestTableStandard[];
Expand All @@ -64,10 +64,10 @@ export interface TestTableTypes$Insert {
table_arr_test?: TestTableStandard[];
table_test?: TestTableStandard | null;
}
export const TestTableTypes$Types: Record<keyof TestTableTypes, string> = {
export const TestTableTypes$Types = {
id: \\"uuid\\",
table_arr_test: \\"test_table_standard\\",
table_test: \\"test_table_standard\\"
};
} as const;
"
`;
22 changes: 10 additions & 12 deletions src/generator/builders/TypeObjectBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import {
VariableStatement,
PropertyAssignment,
SyntaxKind,
ObjectLiteralExpression,
TypeNode,
NodeFlags,
Identifier,
KeywordTypeSyntaxKind,
AsExpression,
} from 'typescript'

import { ColumnInfo, TableInfo, TypeRegistry } from '../database'
Expand Down Expand Up @@ -41,17 +41,15 @@ export default class TypeObjectBuilder extends TypeBuilder<VariableStatement> {
})
}

protected buildObjectLiteral(): ObjectLiteralExpression {
protected buildObjectLiteral(): AsExpression {
const properties = this.buildProperties()
return factory.createObjectLiteralExpression(properties, true)
}

protected buildType(): TypeNode {
const parentType = factory.createTypeReferenceNode(super.typename())
return factory.createTypeReferenceNode('Record', [
factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, parentType),
factory.createKeywordTypeNode(SyntaxKind.StringKeyword),
])
return factory.createAsExpression(
factory.createObjectLiteralExpression(properties, true),
factory.createKeywordTypeNode(
SyntaxKind.ConstKeyword as KeywordTypeSyntaxKind
)
)
}

public typename(name: string = this.name): Identifier {
Expand All @@ -62,7 +60,7 @@ export default class TypeObjectBuilder extends TypeBuilder<VariableStatement> {
const declaration = factory.createVariableDeclaration(
this.typename(),
undefined,
this.buildType(),
undefined,
this.buildObjectLiteral()
)

Expand Down

0 comments on commit 8bda964

Please sign in to comment.