Skip to content

Commit

Permalink
feat: allow to use user as pivot row label
Browse files Browse the repository at this point in the history
  • Loading branch information
nichenqin committed Nov 13, 2024
1 parent 1e57d4a commit 0a596d6
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<script lang="ts">
import type { PivotView, SelectField, StringField } from "@undb/table"
import type { PivotView, SelectField, StringField, UserField } from "@undb/table"
import { createQuery } from "@tanstack/svelte-query"
import { trpc } from "$lib/trpc/client"
import { getTable } from "$lib/store/table.store"
import * as Table from "$lib/components/ui/table"
import Option from "$lib/components/blocks/option/option.svelte"
import UserFieldComponent from "$lib/components/blocks/field-value/user-field.svelte"
const table = getTable()
export let view: PivotView
Expand Down Expand Up @@ -35,7 +36,11 @@
$: aggregate = view.pivotAggregate.unwrapOr("count")
$: columnField = $table.schema.getFieldByIdOrName(columnFieldId).into(undefined) as SelectField | undefined
$: rowField = $table.schema.getFieldByIdOrName(rowFieldId).into(undefined) as SelectField | StringField | undefined
$: rowField = $table.schema.getFieldByIdOrName(rowFieldId).into(undefined) as
| SelectField
| StringField
| UserField
| undefined
$: valueField = $table.schema.getFieldByIdOrName(valueFieldId).into(undefined)
$: options = columnField?.options ?? []
Expand Down Expand Up @@ -81,16 +86,22 @@
{:else}
{#each data as row}
{@const rowTotal = row["agg"]}
{@const label = row.label}
{@const labelValues = row.labelValues}
<Table.Row>
<Table.Cell class="border-r bg-gray-50 font-semibold">
{#if rowField.type === "select"}
{@const optionId = row.label}
{#if label === null}
(Is Empty)
{:else if rowField.type === "select"}
{@const optionId = label}
{@const option = rowField.options.find((o) => o.id === optionId)}
{#if option}
<Option {option} />
{/if}
{:else if rowField.type === "user"}
<UserFieldComponent value={label} displayValue={labelValues} />
{:else}
{row.label}
{label}
{/if}
</Table.Cell>
{#each options as option}
Expand Down
96 changes: 41 additions & 55 deletions packages/persistence/src/record/record.query-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ import {
type View,
type ViewId,
} from "@undb/table"
import { sql, type AliasedExpression, type Expression } from "kysely"
import { getTableName } from "drizzle-orm"
import { sql, type AliasedExpression, type Expression, type ExpressionBuilder } from "kysely"
import type { IRecordQueryBuilder } from "../qb"
import { injectQueryBuilder } from "../qb.provider"
import { users } from "../tables"
import { UnderlyingTable } from "../underlying/underlying-table"
import { RecordQueryHelper } from "./record-query.helper"
import { RecordReferenceVisitor } from "./record-reference-visitor"
Expand Down Expand Up @@ -164,10 +166,38 @@ export class RecordQueryRepository implements IRecordQueryRepository {
const aggFn = convertAggFn(aggregate)

const t = new UnderlyingTable(table)
const result = await this.qb
.selectFrom(t.name)
.select((eb) => {
const selects: AliasedExpression<any, any>[] = [eb.ref(`${t.name}.${rowField.id.value}`).as("label")]
const createSelects =
(isTotal = false) =>
(eb: ExpressionBuilder<any, any>) => {
const selects: AliasedExpression<any, any>[] = [
isTotal ? sql.raw("'Total'").as("label") : eb.ref(`${t.name}.${rowField.id.value}`).as("label"),
]

if (rowField.type === "user") {
if (!isTotal) {
const user = getTableName(users)

const q = eb
.selectFrom(user)
.select(
eb
.fn("json_object", [
sql.raw("'username'"),
eb.fn.coalesce(`${user}.${users.username.name}`, sql`NULL`),
sql.raw("'email'"),
eb.fn.coalesce(`${user}.${users.email.name}`, sql`NULL`),
])
.as("labelValues"),
)
.whereRef(rowField.id.value, "=", `${user}.${users.id.name}`)
.limit(1)
.as("labelValues")

selects.push(q)
} else {
selects.push(sql`NULL`.as("labelValues"))
}
}

const columnSelects = options
.map((option) => {
Expand Down Expand Up @@ -210,57 +240,13 @@ export class RecordQueryRepository implements IRecordQueryRepository {
}

return selects
})
.groupBy(`${t.name}.${rowField.id.value}`)
.unionAll((qb) => {
return qb.selectFrom(t.name).select((eb) => {
const selects: AliasedExpression<any, any>[] = [sql.raw("'Total'").as("label")]

const columnSelects = options
.map((option) => {
if (aggFn === "count") {
const caseString = `count(CASE WHEN "${t.name}"."${columnField.id.value}" = '${option.id}' THEN 1 END)`
return [sql.raw(`'${option.name}'`), sql.raw(caseString)]
} else {
if (!valueField) {
throw new Error("value field is required")
}

let valueFieldAlias = `${t.name}.${valueField.id.value}`
if (valueField.type === "currency") {
valueFieldAlias = `${t.name}.${valueField.id.value} / 100`
}

const caseString =
`${aggFn}(CASE WHEN ` +
`"${t.name}"."${columnField.id.value}" = '${option.id}' ` +
`THEN ${valueFieldAlias} ` +
`END)`
return [sql.raw(`'${option.name}'`), sql.raw(caseString)]
}
})
.flat()

selects.push(eb.fn("json_object", columnSelects).as("values"))

if (aggFn === "count") {
selects.push(
sql.raw(`sum(CASE WHEN "${t.name}"."${columnField.id.value}" IS NOT NULL THEN 1 END)`).as(`agg`),
)
} else {
if (!valueField) {
throw new Error("value field is required")
}
const rowTotalString =
valueField.type === "currency"
? `${aggFn}("${t.name}"."${valueField.id.value}") / 100`
: `${aggFn}("${t.name}"."${valueField.id.value}")`
selects.push(sql.raw(rowTotalString).as(`agg`))
}
}

return selects
})
})
const result = await this.qb
.selectFrom(t.name)
.select(createSelects())
.groupBy(`${t.name}.${rowField.id.value}`)
.unionAll((qb) => qb.selectFrom(t.name).select(createSelects(true)))
.execute()

return result as IGetPivotDataOutput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export class PivotView extends AbstractView {
}

export function isValidColumnLabel(field: Field) {
return (field.type === "select" && field.isSingle) || (field.type === "user" && field.isSingle)
return field.type === "select" && field.isSingle
}

export function isValidRowLabel(field: Field) {
Expand Down

0 comments on commit 0a596d6

Please sign in to comment.