Skip to content

Commit

Permalink
revert(core): back to original join model
Browse files Browse the repository at this point in the history
  • Loading branch information
Hieuzest committed Dec 30, 2023
1 parent 7816db8 commit a7da54c
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 25 deletions.
10 changes: 8 additions & 2 deletions packages/core/src/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,15 @@ class Executable<S = any, T = any> {

constructor(driver: Driver, payload: Executable.Payload) {
Object.assign(this, payload)
defineProperty(this, 'driver', driver)
defineProperty(this, 'model', driver.model(this.table))
defineProperty(this, 'row', createRow(this.ref, {}, '', this.model))
const expr = { $model: this.model }
if (typeof payload.table !== 'string' && !(payload.table instanceof Selection)) {
for (const key in payload.table) {
expr[key] = createRow(key, {}, '', this.model)
}
}
defineProperty(this, 'driver', driver)
defineProperty(this, 'row', createRow(this.ref, expr, '', this.model))
}

protected resolveQuery(query?: Query<S>): Query.Expr<S>
Expand Down
21 changes: 6 additions & 15 deletions packages/memory/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,25 @@ export class MemoryDriver extends Driver {
// await this.#loader?.stop(this.#store)
}

table(sel: string | Selection.Immutable | Dict<string | Selection.Immutable>, env: any = {}): any[] {
table(sel: string | Selection.Immutable | Dict<string | Selection.Immutable>, env: any = {}, expr?: any): any[] {
if (typeof sel === 'string') {
return this.#store[sel] ||= []
}

if (!(sel instanceof Selection)) {
throw new Error('Should not reach here')
}

const { ref, query, table, args, model } = sel
const { fields, group, having } = sel.args[0]

let data: any[]

if (typeof table === 'object' && !(table instanceof Selection)) {
const entries = Object.entries(table).map(([name, sel]) => [name, this.table(sel, env)] as const)
const entries = Object.entries(sel).map(([name, sel]) => [name, this.table(sel, env)] as const)
const catesian = (entries: (readonly [string, any[]])[]): any[] => {
if (!entries.length) return []
const [[name, rows], ...tail] = entries
if (!tail.length) return rows.map(row => ({ [name]: row }))
return rows.flatMap(row => catesian(tail).map(tail => ({ ...tail, [name]: row })))
}
data = catesian(entries).map(x => ({ ...env, [ref]: x })).filter(data => executeEval(data, having)).map(x => x[ref])
} else {
data = this.table(table, env).filter(row => executeQuery(row, query, ref, env))
return catesian(entries).filter(data => executeEval({ ...env, ...data }, expr))
}

env[ref] = data
const { ref, query, table, args, model } = sel
const { fields, group, having } = sel.args[0]
const data = this.table(table, env, having).filter(row => executeQuery(row, query, ref, env))

const branches: { index: Dict; table: any[] }[] = []
const groupFields = group ? pick(fields!, group) : fields
Expand Down
23 changes: 15 additions & 8 deletions packages/mongo/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export class Transformer {
} else if (this.refTables.includes(arg[0])) {
return `$$${arg[0]}.` + this.getActualKey(arg[1], arg[0])
} else {
throw new Error(`$ not transformed: ${JSON.stringify(arg)}`)
return this.recursivePrefix + this.getActualKey(arg[1])
}
},
$if: (arg, group) => ({ $cond: arg.map(val => this.eval(val, group)) }),
Expand Down Expand Up @@ -382,30 +382,37 @@ export class Transformer {
this.table = predecessor.table
this.pipeline.push(...predecessor.flushLookups(), ...predecessor.pipeline)
} else {
for (const [name, subtable] of Object.entries(table)) {
const refs: string[] = []
Object.entries(table).forEach(([name, subtable], i) => {
const predecessor = this.createSubquery(subtable)
if (!predecessor) return
if (!this.table) {
this.table = predecessor.table
this.pipeline.push(...predecessor.flushLookups(), ...predecessor.pipeline, {
$replaceRoot: { newRoot: { [name]: '$$ROOT' } },
})
continue
refs.push(name)
return
}
if (sel.args[0].having['$and'].length && i === Object.keys(table).length - 1) {
const thisRefTables = this.refTables
this.refTables = [...this.refTables, ...refs]
const $expr = this.eval(sel.args[0].having['$and'][0])
predecessor.pipeline.push(...this.flushLookups(), { $match: { $expr } })
this.refTables = thisRefTables
}
const $lookup = {
from: predecessor.table,
as: name,
let: Object.fromEntries(refs.map(name => [name, `$$ROOT.${name}`])),
pipeline: predecessor.pipeline,
}
const $unwind = {
path: `$${name}`,
}
this.pipeline.push({ $lookup }, { $unwind })
}
if (sel.args[0].having['$and'].length) {
const $expr = this.eval(sel.args[0].having)
this.pipeline.push(...this.flushLookups(), { $match: { $expr } })
}
refs.push(name)
})
}

// where
Expand Down
1 change: 1 addition & 0 deletions packages/sql-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ export class Builder {
} else {
const sqlTypes: Dict<SQLType> = {}
const joins: string[] = Object.entries(table).map(([key, table]) => {
this.state.tables![key] = this.state.tables![table.ref]
const restore = this.saveState({ tables: table.tables })
const t = `${this.get(table, true, false, false)} AS ${this.escapeId(key)}`
for (const [fieldKey, fieldType] of Object.entries(this.state.sqlTypes!)) {
Expand Down
9 changes: 9 additions & 0 deletions packages/tests/src/selection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { $, Database } from '@minatojs/core'
import { expect } from 'chai'
import { setup } from './utils'
import MongoDriver from '@minatojs/driver-mongo'

Check failure on line 4 in packages/tests/src/selection.ts

View workflow job for this annotation

GitHub Actions / build

Cannot find module '@minatojs/driver-mongo' or its corresponding type declarations.

interface Foo {
id: number
Expand Down Expand Up @@ -442,6 +443,14 @@ namespace SelectionTests {
).to.eventually.have.length(6)
})

it('join inside subquery', async () => {
const sel = database.select('foo').project({
x: row => database.join(['foo', 'bar'] as const, (foo, bar) => $.eq(foo.id, row.id))
.evaluate(r => $.count(r.foo.id)),
})
await expect(database.select(sel).execute(row => $.sum(row.x))).to.eventually.equal(3)
})

it('join selection', async () => {
await expect(database
.select(
Expand Down

0 comments on commit a7da54c

Please sign in to comment.