Skip to content

Commit

Permalink
Merge pull request #32 from narthur/perf
Browse files Browse the repository at this point in the history
optimize link_row fetching
  • Loading branch information
narthur committed Apr 17, 2024
2 parents 8f0eea9 + d58e3b6 commit b0e004d
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 26 deletions.
16 changes: 15 additions & 1 deletion src/codegen/makeGetter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { makeGetter } from "./makeGetter";
import { FieldDefinition } from "..";

function run(field: Partial<FieldDefinition> = {}): string {
return makeGetter(f(field), []);
return makeGetter(f(field), [
{
id: 1,
name: "table_name",
fields: [],
},
]);
}

describe("makeGetter", () => {
Expand Down Expand Up @@ -84,6 +90,14 @@ describe("makeGetter", () => {
},
`parseFloat(`,
],
[
{
type: "link_row",
link_row_table_id: 1,
link_row_related_field_id: 2,
},
"this.getLinkedRows",
],
])("%s => `%s`", (field, expected) => {
expect(run(field)).toContain(expected);
});
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/makeGetter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function getBody(field: FieldDefinition, tables: Table[]): string {

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)));`;
return `return this.getLinkedRows(${field.link_row_table_id}, ${field.link_row_related_field_id}, ${foreignTable.name}Row);`;
}

if (field.type === "date" || field.formula_type === "date") {
Expand Down
13 changes: 0 additions & 13 deletions src/codegen/makeModelMethods.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,6 @@ describe("makeClassMethods", () => {
).toContain("value: number[]");
});

it("uses repository to get linked row objects", () => {
expect(
makeModelMethods(1, [
{
id: 1,
name: "the_table_name",
fields: [f({ type: "link_row", link_row_table_id: 2 })],
},
{ id: 2, name: "the_foreign_table_name", fields: [] },
]),
).toContain("this.repository.getOneTheForeignTableName");
});

it("properly set link row getter return type", () => {
expect(
makeModelMethods(1, [
Expand Down
4 changes: 1 addition & 3 deletions src/codegen/makeRepositoryMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ export default function makeRepositoryMethods(tables: Table[]): string {
return tables
.map(({ id, name }) => {
return ` public async getMany${name}<T extends ${name}Row>(options: ListRowsOptions = {}): Promise<T[]> {
const { results } = await this.sdk.listRows<${name}RowType>(${id}, options);
const rowClass = this.getRowClass(${id}) || ${name}Row;
return results.map((row) => new rowClass({ tableId: ${id}, rowId: row.id, row, sdk: this.sdk, repository: this })) as T[];
return this.getMany<T, ${name}RowType, Repository>(${id}, ${name}Row, options);
}
public async getOne${name}<T extends ${name}Row>(id: number, options: GetRowOptions = {}): Promise<T> {
Expand Down
27 changes: 21 additions & 6 deletions src/factory.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { BaserowConfig, getConfig } from "./getConfig.js";
import { BaserowSdk } from "./index.js";
import { Row, RowOptions, RowType } from "./row.js";

interface RowClass<T extends RowType, R extends Factory> {
new (options: RowOptions<T, R>): Row<T, R>;
}
import { BaserowSdk, RowClass } from "./index.js";
import { Row, RowType } from "./row.js";

export abstract class Factory {
public readonly config: BaserowConfig;
Expand Down Expand Up @@ -32,4 +28,23 @@ export abstract class Factory {
): RowClass<T, R> | undefined {
return this.classes.get(tableId) as RowClass<T, R> | undefined;
}

public async getMany<T extends Row, R extends RowType, F extends Factory>(
tableId: number,
defaultClass: RowClass<R, F>,
options: Record<string, unknown> = {},
): Promise<T[]> {
const { results } = await this.sdk.listRows<R>(tableId, options);
const rowClass = this.getRowClass(tableId) || defaultClass;
return results.map(
(row) =>
new rowClass({
tableId,
rowId: row.id,
row,
sdk: this.sdk,
repository: this as unknown as F,
}),
) as T[];
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export type FieldDefinition = {
array_formula_type?: string;
formula_type?: string;
link_row_table_id?: number;
link_row_related_field_id?: number;
select_options?: { id: number; value: string; color: string }[];
};

Expand Down
27 changes: 25 additions & 2 deletions src/row.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Factory } from "./factory.js";
import { BaserowSdk } from "./index.js";
import { BaserowSdk, RowClass } from "./index.js";

export type RowType = Record<string, unknown> & { id: number; order: string };
export type RowOptions<T extends RowType, R extends Factory> = {
Expand All @@ -9,7 +9,10 @@ export type RowOptions<T extends RowType, R extends Factory> = {
sdk: BaserowSdk;
repository: R;
};
export abstract class Row<T extends RowType, R extends Factory> {
export abstract class Row<
T extends RowType = RowType,
R extends Factory = Factory,
> {
protected tableId: number;
protected rowId: number;
protected row: T;
Expand Down Expand Up @@ -46,4 +49,24 @@ export abstract class Row<T extends RowType, R extends Factory> {
[field]: value,
});
}

protected getLinkedRows<T extends Row, R extends RowType, F extends Factory>(
tableId: number,
field: string | number,
defaultClass: RowClass<R, F>,
): Promise<T[]> {
return this.repository.getMany(tableId, defaultClass, {
filters: {
filter_type: "AND",
filters: [
{
type: "link_row_has",
field: field.toString(),
value: this.getId().toString(),
},
],
groups: [],
},
});
}
}
10 changes: 10 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
import { Factory } from "./factory.js";
import { Row, RowOptions, RowType } from "./row.js";

export type FieldValue<T> =
| T
| { id: number; value: T }
| { ids: Record<string, number>; value: T };

export interface RowClass<
T extends RowType = RowType,
R extends Factory = Factory,
> {
new (options: RowOptions<T, R>): Row<T, R>;
}

0 comments on commit b0e004d

Please sign in to comment.