Skip to content

Commit

Permalink
Merge pull request #18 from narthur/codegen
Browse files Browse the repository at this point in the history
Codegen
  • Loading branch information
narthur committed Apr 11, 2024
2 parents d51fe43 + d1deba7 commit 0994ab8
Show file tree
Hide file tree
Showing 13 changed files with 275 additions and 140 deletions.
27 changes: 9 additions & 18 deletions src/codegen.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { BaserowSdk } from "./index.js";
import { BaserowSdk, ListFieldsResponse } from "./index.js";
import fs from "fs";
import makeType from "./codegen/makeType.js";
import makeClassMethods from "./codegen/makeClassMethods.js";
import makeModelMethods from "./codegen/makeModelMethods.js";
import path from "path";
import { getConfig } from "./getConfig.js";
import makeRepositoryMethods from "./codegen/makeRepositoryMethods.js";

export type Table = { id: number; name: string; fields: ListFieldsResponse };

const __dirname = path.dirname(new URL(import.meta.url).pathname);

Expand All @@ -20,7 +23,7 @@ export default async function main(): Promise<void> {

const sdk = new BaserowSdk(String(config.databaseToken));

const tables = await Promise.all(
const tables: Table[] = await Promise.all(
Object.entries(config.tables).map(async ([name, id]) => {
return {
name,
Expand Down Expand Up @@ -65,7 +68,7 @@ export class ${tableName}Row extends Row<${tableName}RowType> {
super(options);
this.repository = options.repository;
}
${makeClassMethods(table.id, tables)}
${makeModelMethods(table.id, tables)}
}`;

fs.writeFileSync(`${outDir}/${tableName}.ts`, typeDef);
Expand All @@ -79,21 +82,9 @@ ${Object.keys(config.tables)
`import { ${tableName}Row, ${tableName}RowType } from './${tableName}.js';`,
)
.join("\n")}
export class Repository extends Factory {
${Object.keys(config.tables)
.map(
(tableName) =>
`public async getMany${tableName}(options: ListRowsOptions = {}): Promise<${tableName}Row[]> {
const {results} = await this.sdk.listRows<${tableName}RowType>(${config.tables[tableName]}, options);
return results.map((row) => new ${tableName}Row({tableId: ${config.tables[tableName]}, rowId: row.id, row, sdk: this.sdk, repository: this}));
}
public async getOne${tableName}(id: number, options: GetRowOptions = {}): Promise<${tableName}Row> {
const row = await this.sdk.getRow<${tableName}RowType>(${config.tables[tableName]}, id, options);
return new ${tableName}Row({tableId: ${config.tables[tableName]}, rowId: row.id, row, sdk: this.sdk, repository: this});
}
`,
)
.join("\n")}
${makeRepositoryMethods(tables)}
}`;

fs.writeFileSync(`${outDir}/Repository.ts`, factoryCode);
Expand Down
72 changes: 0 additions & 72 deletions src/codegen/makeClassMethods.ts

This file was deleted.

26 changes: 0 additions & 26 deletions src/codegen/makeFieldType.spec.ts

This file was deleted.

12 changes: 10 additions & 2 deletions src/codegen/makeFieldType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export function makeFieldType(field: FieldDefinition): string {
if (field.type === "link_row") {
return '{ "id": number, "value": string }[]';
}

if (["rollup", "formula", "lookup"].includes(field.type)) {
switch (field.formula_type) {
case "array":
Expand All @@ -13,15 +14,22 @@ export function makeFieldType(field: FieldDefinition): string {
return mapPrimitive(field.formula_type);
}
}

if (field.type === "single_select") {
if (!field.select_options) {
throw new Error(
`Field ${field.name} is a single_select but has no select_options`,
);
}
return field.select_options
?.map((option) => `"${option.value}"`)

const options = field.select_options
.map((option) => {
return `{ id: ${option.id}, value: "${option.value}", color: "${option.color}" }`;
})
.join(" | ");

return `(${options})`;
}

return mapPrimitive(field.type);
}
75 changes: 75 additions & 0 deletions src/codegen/makeGetter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { describe, it, expect } from "vitest";
import f from "../test/fixtures/fieldDefinition";
import { makeGetter } from "./makeGetter";
import { FieldDefinition } from "..";

function run(field: Partial<FieldDefinition> = {}): string {
return makeGetter(f(field), []);
}

describe("makeGetter", () => {
it.each([
[{ type: "text" }, "string"],
[{ type: "number" }, "number"],
[
{
type: "single_select",
select_options: [
{
id: 1,
value: "the_option_name",
color: "red",
},
],
},
"the_option_name",
],
[{ type: "date" }, ": Date"],
[
{
type: "single_select",
select_options: [
{
id: 1,
value: "the_option_name",
color: "red",
},
],
},
`: "the_option_name"`,
],
[
{
type: "single_select",
select_options: [
{
id: 1,
value: "the_option_name",
color: "red",
},
],
},
`<({ id: 1, value: "the_option_name", color: "red" })>`,
],
[
{
type: "single_select",
select_options: [
{
id: 1,
value: "the_option_name",
color: "red",
},
{
id: 2,
value: "the_option_name_2",
color: "blue",
},
],
},
`<({ id: 1, value: "the_option_name", color: "red" } | { id: 2, value: "the_option_name_2", color: "blue" })>`,
],
])("%s => `%s`", (field, expected) => {
expect(run(field)).toContain(expected);
});
});
77 changes: 77 additions & 0 deletions src/codegen/makeGetter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Table } from "../codegen.js";
import { FieldDefinition, ListFieldsResponse } from "../index.js";
import { makeFieldType } from "./makeFieldType.js";
import { toCamelCase } from "./toCamelCase.js";

function getForeignTable(
field: FieldDefinition,
tables: Table[],
): { id: number; name: string } {
if (!field.link_row_table_id) {
throw new Error("link_row_table_id is missing");
}
const foreignTable = tables.find((t) => field.link_row_table_id === t.id);
if (!foreignTable) {
throw new Error("foreign table not found");
}
return foreignTable;
}

function getReturnType(field: FieldDefinition, tables: Table[]): string {
if (field.type === "date" || field.formula_type === "date") {
return "Date";
}

if (field.type === "link_row") {
const foreignTable = getForeignTable(field, tables);
return `Promise<${toCamelCase(foreignTable.name, true)}Row[]>`;
}

if (field.type === "single_select") {
if (!field.select_options) {
throw new Error(
`Field ${field.name} is a single_select but has no select_options`,
);
}
return field.select_options
?.map((option) => `"${option.value}"`)
.join(" | ");
}

return makeFieldType(field);
}

function getBody(field: FieldDefinition, tables: Table[]): string {
const rawType = makeFieldType(field);
const query = `this.getField<${rawType}>("${field.name}")`;

if (field.type === "number") {
return `return parseFloat(${query}.toString());`;
}

if (field.type === "single_select") {
return `return ${query}.value;`;
}

if (field.type === "link_row") {
const foreignTable = getForeignTable(field, tables);
return `return Promise.all(${query}.map((r) => this.repository.${toCamelCase(`get one ${foreignTable.name}`)}(r.id)));`;
}

if (field.type === "date" || field.formula_type === "date") {
return `return new Date(${query});`;
}

return `return ${query};`;
}

export function makeGetter(
field: FieldDefinition,
tables: { id: number; name: string; fields: ListFieldsResponse }[],
): string {
const fn = toCamelCase(`get ${field.name}`);
const rt = getReturnType(field, tables);
const bd = getBody(field, tables);

return `\n public ${fn}(): ${rt} {\n ${bd}\n }`;
}
Loading

0 comments on commit 0994ab8

Please sign in to comment.