Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
retro committed Aug 18, 2024
1 parent d16392e commit 23eba3b
Show file tree
Hide file tree
Showing 18 changed files with 1,305 additions and 210 deletions.
3 changes: 3 additions & 0 deletions src/__tests__/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@ const userModel = semanticLayer
.withMetric("count", {
type: "string",
format: (value) => `Count: ${value}`,
sql: ({ sql }) => sql`COUNT(1)`,
})
.withMetric("percentage", {
type: "string",
format: "percentage",
sql: ({ sql }) => sql`COUNT(1)`,
})
.withMetric("currency", {
type: "string",
format: "currency",
sql: ({ sql }) => sql`COUNT(1)`,
});

const repository = semanticLayer.repository().withModel(userModel);
Expand Down
123 changes: 123 additions & 0 deletions src/__tests__/view-model.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { assert, it } from "vitest";

import { model } from "../lib/model.js";
import { viewModel } from "../lib/view-model.js";

const customers = model()
.withName("customers")
.fromTable("Customer")
.withDimension("customer_id", {
type: "number",
primaryKey: true,
sql: ({ model, sql }) => sql`${model.column("CustomerId")}`,
})
.withDimension("first_name", {
type: "string",
sql: ({ model }) => model.column("FirstName"),
});

const invoices = model()
.withName("invoices")
.fromTable("Invoice")
.withDimension("invoice_id", {
type: "number",
primaryKey: true,
sql: ({ model }) => model.column("InvoiceId"),
})
.withDimension("customer_id", {
type: "number",
sql: ({ model }) => model.column("CustomerId"),
})
.withDimension("invoice_date", {
type: "date",
sql: ({ model }) => model.column("InvoiceDate"),
})
.withMetric("total", {
type: "string",
sql: ({ model, sql }) => sql`SUM(COALESCE(${model.column("Total")}, 0))`,
});

const invoiceLines = model()
.withName("invoice_lines")
.fromTable("InvoiceLine")
.withDimension("invoice_line_id", {
type: "number",
primaryKey: true,
sql: ({ model }) => model.column("InvoiceLineId"),
})
.withDimension("invoice_id", {
type: "number",
sql: ({ model }) => model.column("InvoiceId"),
})
.withDimension("track_id", {
type: "number",
sql: ({ model }) => model.column("TrackId"),
})
.withMetric("quantity", {
type: "string",
sql: ({ model, sql }) => sql`SUM(COALESCE(${model.column("Quantity")}, 0))`,
})
.withMetric("unit_price", {
type: "string",
sql: ({ model, sql }) =>
sql`SUM(COALESCE(${model.column("UnitPrice")}, 0))`,
});

it("can create a view model", () => {
const v = viewModel()
.withName("customers")
.fromModel(customers)
.leftJoin(
invoices,
({ sql, models }) =>
sql`${models.customers.dimension(
"customer_id",
)} = ${models.invoices.dimension("customer_id")}`,
)
.leftJoin(
invoiceLines,
({ sql, models }) =>
sql`${models.invoices.dimension(
"invoice_id",
)} = ${models.invoice_lines.dimension("invoice_id")}`,
)
.withIncludedDimensionsFrom("invoices", {
exclude: ["invoice_date"],
})
.withIncludedDimension("customers.first_name", {
// omitGranularity: true,
//alias: "my_customer_name"
})
.withIncludedDimension("invoices.invoice_date", {
omitGranularity: true,
alias: "my_invoice_date",
})
.withCompoundDimension("foo", {
type: "string",
sql: ({ models, sql }) =>
sql`${models.customers.dimension(
"customer_id",
)}: ${models.invoices.dimension("invoice_id")}`,
})
.withIncludedMetricsFrom("invoices")
.withIncludedMetricsFrom("invoice_lines", {
exclude: ["quantity"],
})
.withIncludedMetric("invoice_lines.quantity", {
alias: "invoice_lines_quantity",
})
.withCompoundMetric("invoice_line_ratio_of_total", {
type: "number",
sql: ({ models, sql }) =>
sql`CAST(SUM(${models.invoice_lines.column(
"quantity",
)}) AS DOUBLE) / CAST(SUM(${models.invoices.column(
"total",
)}) AS DOUBLE)`,
});

const dimensions = v.getDimensions();

Check warning on line 119 in src/__tests__/view-model.test.ts

View workflow job for this annotation

GitHub Actions / 🔬 Lint & Format

This variable is unused.
const metrics = v.getMetrics();

Check warning on line 120 in src/__tests__/view-model.test.ts

View workflow job for this annotation

GitHub Actions / 🔬 Lint & Format

This variable is unused.

assert.ok(viewModel);
});
21 changes: 21 additions & 0 deletions src/lib/member.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { MemberFormat, MemberType } from "./types.js";

import { AnyBaseDialect } from "./dialect/base.js";
import { SqlFragment } from "./sql-builder.js";

export type NextColumnRefOrDimensionRefAlias = () => string;

export abstract class Member {
public abstract readonly name: string;

abstract getSql(dialect: AnyBaseDialect, context: unknown): SqlFragment;
abstract getQuotedAlias(dialect: AnyBaseDialect): string;
abstract getAlias(): string;
abstract getPath(): string;
abstract getDescription(): string | undefined;
abstract getType(): MemberType;
abstract getFormat(): MemberFormat | undefined;
abstract unsafeFormatValue(value: unknown): string;
abstract isDimension(): boolean;
abstract isMetric(): boolean;
}
Loading

0 comments on commit 23eba3b

Please sign in to comment.