Skip to content

Commit

Permalink
feat(core): impl Selection.join
Browse files Browse the repository at this point in the history
  • Loading branch information
Hieuzest committed Apr 21, 2024
1 parent 1cd3492 commit c742bcf
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 1 deletion.
34 changes: 33 additions & 1 deletion packages/core/src/selection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineProperty, Dict, filterKeys, valueMap } from 'cosmokit'
import { defineProperty, Dict, filterKeys, mapValues, valueMap } from 'cosmokit'
import { Driver } from './driver.ts'
import { Eval, executeEval } from './eval.ts'
import { Model } from './model.ts'
Expand Down Expand Up @@ -235,6 +235,30 @@ export class Selection<S = any> extends Executable<S, S[]> {
return new Selection(this.driver, this)
}

join<K extends string, U>(
name: K,
selection: Selection<U>,
callback: (self: Row<S>, other: Row<U>) => Eval.Expr<boolean> = () => Eval.and(),
type: 'inner' | 'left' | 'right' = 'inner',
): Selection<S & { [P in K]: U}> {
const fields = Object.fromEntries(Object.entries(this.model.fields)
.filter(([, field]) => !field!.deprecated)
.map(([key]) => [key, (row) => key.split('.').reduce((r, k) => r[k], row[this.ref])]))
if (type === 'left') {
return this.driver.database
.join({ [this.ref]: this as Selection, [name]: selection }, (t: any) => callback(t[this.ref], t[name]), { [this.ref]: false, [name]: true })
.project({ ...fields, [name]: name }) as any
} else if (type === 'right') {
return this.driver.database
.join({ [name]: selection, [this.ref]: this as Selection }, (t: any) => callback(t[this.ref], t[name]), { [name]: true, [this.ref]: false })
.project({ ...fields, [name]: name }) as any
} else {
return this.driver.database
.join({ [this.ref]: this as Selection, [name]: selection }, (t: any) => callback(t[this.ref], t[name]))
.project({ ...fields, [name]: name }) as any
}
}

_action(type: Executable.Action, ...args: any[]) {
return new Executable(this.driver, { ...this, type, args })
}
Expand Down Expand Up @@ -278,6 +302,14 @@ export class Selection<S = any> extends Executable<S, S[]> {
})
})
}

format(result = {}) {
result['ref'] = this.ref
if (typeof this.table === 'string') result['table'] = this.table
else if (this.table instanceof Selection) result['table'] = this.table.format()
else result['table'] = mapValues(this.table, (v: any) => v.format())
return result
}
}

export function executeSort(data: any[], modifier: Modifier, name: string) {
Expand Down
35 changes: 35 additions & 0 deletions packages/tests/src/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ namespace SelectionTests {
.join(['foo', 'bar'], (foo, bar) => $.eq(foo.value, bar.value))
.execute()
).to.eventually.have.length(2)

await expect(database.select('foo')
.join('bar', database.select('bar'), (foo, bar) => $.eq(foo.value, bar.value))
.execute()
).to.eventually.have.length(2)
})

it('left join', async () => {
Expand All @@ -303,6 +308,30 @@ namespace SelectionTests {
{ foo: { value: 2, id: 2 }, bar: {} },
{ foo: { value: 2, id: 3 }, bar: {} },
])

await expect(database.select('foo')
.join('bar', database.select('bar'), (foo, bar) => $.eq(foo.value, bar.value), 'left')
.execute()
).to.eventually.have.shape([
{
value: 0, id: 1,
bar: { uid: 1, pid: 1, value: 0, id: 1 },
},
{
value: 0, id: 1,
bar: { uid: 1, pid: 2, value: 0, id: 3 },
},
{ value: 2, id: 2, bar: {} },
{ value: 2, id: 3, bar: {} },
])
})

it('duplicate', async () => {
await expect(database.select('foo')
.project(['value'])
.join('bar', database.select('bar'), (foo, bar) => $.eq(foo.value, bar.uid))
.execute()
).to.eventually.have.length(4)
})

it('group', async () => {
Expand Down Expand Up @@ -344,6 +373,12 @@ namespace SelectionTests {
}, ({ t1, t2, t3 }) => $.gt($.add(t1.id, t2.id, t3.id), 14))
.execute()
).to.eventually.have.length(4)

await expect(database.select('bar').where(row => $.gt(row.pid, 1))
.join('t2', database.select('bar').where(row => $.gt(row.uid, 1)))
.join('t3', database.select('bar').where(row => $.gt(row.id, 4)), (self, t3) => $.gt($.add(self.id, self.t2.id, t3.id), 14))
.execute()
).to.eventually.have.length(4)
})

it('aggregate', async () => {
Expand Down

0 comments on commit c742bcf

Please sign in to comment.