-
Notifications
You must be signed in to change notification settings - Fork 38
Description
Invalid code is generated if the database schema contains table columns whose names are not valid Typescript identifiers. Specifically, the generated interfaces contain properties that are not valid.
For example, if my schema file contains:
CREATE TABLE exampledb.example (
"id" integer,
"invalid-name" text
);Then the interface generated for a query tagged with -- name: CreateExample :one is:
export interface CreateExampleRow {
id: any;
invalid-name: any;
}The Typescript spec. applies the same limitations to object properties as it does to identifiers and so the solution appears to be to check whether column names are valid Typescript identifiers during generation and, if so, quote the property name in the generated code.
The following function is not perfect for determining whether a string is a valid Typescript identifier in the general case since keywords may not be used as identifiers. However, modern versions of Typescript do allow keywords to be used as property names so it's good enough for our purposes. In my test code, I added this to utlis.ts:
export function isIdentifier(str: string): boolean {
return /^[\p{ID_Start}_$][\p{ID_Continue}_$]*$/u.test(str);
}Then, in app.ts, I updated the import line for ./drivers/utlis to include isIdentifier and I updated the rowDecl function to look like this:
function rowDecl(
name: string,
driver: Driver,
columns: Column[]
) {
return factory.createInterfaceDeclaration(
[factory.createToken(SyntaxKind.ExportKeyword)],
factory.createIdentifier(name),
undefined,
undefined,
columns.map((column, i) => {
const name = colName(i, column);
return factory.createPropertySignature(
undefined,
isIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name),
undefined,
driver.columnType(column)
)
})
);
}Following these changes, the generated interface for the example above now looks like this:
export interface CreateExampleRow {
id: any;
"invalid-name": any;
}