allow multiple component matching and entity id binding

This commit is contained in:
Rowan 2024-11-26 11:54:57 -06:00
parent c1520b7a59
commit 28ea665212
4 changed files with 29 additions and 55 deletions

View file

@ -46,7 +46,7 @@ export const node = map(
export const edge = map( export const edge = map(
x => new Edge(x), x => new Edge(x),
bracketed(components, Bracket.Square) bracketed(component, Bracket.Square)
) )
const arrowRight = map(() => Direction.Right, seq(Hyphen, Bracket.Angle.Right)) const arrowRight = map(() => Direction.Right, seq(Hyphen, Bracket.Angle.Right))

View file

@ -1,4 +1,3 @@
import { pipe } from 'bitecs'
import { assoc, assocPath, is, nth } from '../fn.js' import { assoc, assocPath, is, nth } from '../fn.js'
class Value { class Value {
@ -8,6 +7,10 @@ class Value {
this.#value = value this.#value = value
} }
toString() {
return this.#value.toString()
}
get value() { get value() {
return this.#value?.value ?? this.#value return this.#value?.value ?? this.#value
} }
@ -28,10 +31,6 @@ export class Identifier extends Value {
super(value) super(value)
} }
toString() {
return this.value.toString()
}
from(component) { from(component) {
return component return component
} }
@ -189,33 +188,20 @@ export class ReturnValues {
#forComponentType(value, type) { #forComponentType(value, type) {
if (this.#isTag(type)) { if (this.#isTag(type)) {
return () => ({}) return {}
} else if (typeof type === 'function') { } else if (typeof type === 'function') {
return type return type
} else { } else {
return value.from(type) return entity => value.from(type)[entity]
//return Object.fromEntries(
// Object.entries(type).map(([k, v]) => [k, v[entity]])
//)
} }
} }
// TODO: adjust froms to accent entity, return data with built up objects as necessary // TODO: adjust froms to accent entity, return data with built up objects as necessary
from(components) { from(components) {
/* const values = components.map(cmp => ({ ...cmp, rv: this.findName(cmp.name) }))
* const { entity, query: { components } } = node .map(({ type, rv }) => new ReturnValue(rv, this.#forComponentType(rv, type)))
* const returns2 = components.map(c => ({ ...c, returnValue: returns.find(x => x.equals(c.name)) }))
* returns2.map(({ returnValue, type }) => getValue(returnValue, type, entity))
* const values = returns2.filter(({ name }) => returns.includes(name))
* .map(({ name, type, returnValue }) => ({ [name]: getValue(returnValue, type, entity) }))
* const values = components.filter(({ name }) => returns.includes(name))
* .map(({ name, type }) => ({ [name]: getValue(type, entity) }))
* return Object.assign(obj, ...values)
*/
const values = components.map(component => ({ ...component, returnValue: this.findName(component.name) })) return entity => values.reduce((acc, rv) => Object.assign(acc, rv.withEntity(entity)), {})
.map(({ name, type, returnValue }) => ([returnValue.toString(), this.#forComponentType(returnValue, type)]))
console.log(this, values)
} }
find(fn) { find(fn) {
@ -235,6 +221,21 @@ export class ReturnValues {
} }
} }
class ReturnValue {
#value
#getter
constructor(value, getter) {
this.#value = value
this.#getter = getter
}
withEntity(entity) {
return assocPath(this.#value.toString(), this.#getter(entity), {})
}
}
export class KeyValuePair { export class KeyValuePair {
constructor(key, value) { constructor(key, value) {
this.key = key this.key = key

View file

@ -26,7 +26,7 @@ const prepareQuery = (query, component) => {
} else { } else {
const components = match.components.map(nodeComponent(component)) const components = match.components.map(nodeComponent(component))
const types = components.filter(notEntity).map(prop('type')) const types = components.filter(notEntity).map(prop('type'))
return { components, relationship, query: defineQuery(types), schema: query } return { components, relationship, getReturns: returnValues.from(components), query: defineQuery(types), schema: query }
} }
} }
@ -95,38 +95,10 @@ const executeQuery = curry((query, world) => {
} }
}) })
const isTag = type => (
type && Object.getOwnPropertySymbols(type).find(
(s) => s.description === 'tagStore'
) || false
)
const getValue = (returnValue, type, entity) => {
if (isTag(type)) {
return {}
} else if (typeof type === 'function') {
return type(entity)
} else {
return returnValue.from(type)
//return Object.fromEntries(
// Object.entries(type).map(([k, v]) => [k, v[entity]])
//)
}
}
const resolveNode = curry((node, obj) => { const resolveNode = curry((node, obj) => {
const returns = path('query.schema.returnValues', node) const { entity, query: { getReturns } } = node
const { entity, query: { components } } = node return { ...obj, ...getReturns(entity) }
// TODO: do this work in prepareQuery
returns.from(components)
//const returns2 = components.map(c => ({ ...c, returnValue: returns.find(x => x.equals(c.name)) }))
//returns2.map(({ returnValue, type }) => getValue(returnValue, type, entity))
//const values = returns2.filter(({ name }) => returns.includes(name))
// .map(({ name, type, returnValue }) => ({ [name]: getValue(returnValue, type, entity) }))
//const values = components.filter(({ name }) => returns.includes(name))
// .map(({ name, type }) => ({ [name]: getValue(type, entity) }))
//return Object.assign(obj, ...values)
}) })
const resolveRelationship = edges => { const resolveRelationship = edges => {

View file

@ -55,6 +55,7 @@ describe('query', () => {
relate(world, b, Knows, a) // 9 relate(world, b, Knows, a) // 9
relate(world, c, Knows, player) // 10 relate(world, c, Knows, player) // 10
// tag components should return an object object
assert.deepEqual( assert.deepEqual(
query('MATCH (player:Player) RETURN player', engine).unwrap(), query('MATCH (player:Player) RETURN player', engine).unwrap(),
[{ player: {} }] [{ player: {} }]