diff --git a/src/fn.js b/src/fn.js index 982262f..b561082 100644 --- a/src/fn.js +++ b/src/fn.js @@ -39,8 +39,6 @@ export const converge = (fn, tfns) => curryN( (...args) => pipe(map(flip(apply)(args)), apply(fn))(tfns) ) -export const diverge = (fn, tfns) => pipe(applyTo, flip(map)(tfns), apply(fn)) - // types export const isArray = Array.isArray export const isNil = v => !v diff --git a/src/query.js b/src/query.js index 79799a0..81876d8 100644 --- a/src/query.js +++ b/src/query.js @@ -1,7 +1,7 @@ import { defineQuery, hasComponent } from 'bitecs' import { query as q } from './query-parser/index.js' import { parseAll } from './parser.js' -import { curry, of, is, reduce, flip, concat, map, when, assoc, mergeLeft, isNil, path, prop, ifElse, diverge, pipe, always, assocPath, prepend, orDefault, useWith, applyTo, tap } from './fn.js' +import { curry, of, is, reduce, flip, concat, map, when, assoc, mergeLeft, isNil, path, prop, ifElse, pipe, always, assocPath, prepend, orDefault, applyTo, lens, over } from './fn.js' import { Relationship } from './query-parser/types.js' const prepareQuery = (query, component) => { @@ -33,7 +33,21 @@ const matches = (world, type, query, set = new Set()) => entity => { } } -const queryRelationship = (from, edge, to, world) => { +const propFrom = flip(prop) +const getNode = when(prop('relationship'), prop('from')) +const queryLens = lens(prop('query'), assoc('results')) +const getQueryResults = curry((world, node) => over(queryLens, applyTo(world), node)) + +const queryRelationship = (query, world) => { + const [from, edge, to] = map( + pipe( + propFrom(query), + getNode, + getQueryResults(world) + ), + ['from', 'edge', 'to'] + ) + const matchesFrom = matches(world, from.type, from.results) const matchesTo = matches(world, to.type, to.results) @@ -58,22 +72,14 @@ const executeQuery = curry((query, world) => { return assembleQuery(query, query.query(world)) } - const { from, to: _to, edge } = query - const to = when(prop('relationship'), prop('from'), _to) + const edges = queryRelationship(query, world) - const edges = queryRelationship( - { type: from.type, results: from.query(world) }, - { type: edge.type, results: edge.query(world) }, - { type: to.type, results: to.query(world) }, - world - ) - - if (_to.relationship) { + if (query.to.relationship) { return reduce((acc, eid) => { const next = assocPath( 'from.query', - always(of(edge.type.to[eid])), - _to + always(of(query.edge.type.to[eid])), + query.to ) return pipe( @@ -96,29 +102,20 @@ const maybeAssoc = curry((pred, key, value, obj) => when(pred, assoc(key, value), obj) ) -const resolveNode = curry((returns, name, entity, obj) => - maybeAssoc(always(includes(name, returns)), name, entity, obj) -) +const resolveNode = curry((node, obj) => { + const name = nodeName(node) + const returns = returnValues(node) + return maybeAssoc(always(includes(name, returns)), name, node.entity, obj) +}) const resolveRelationship = edges => { const { entity, query } = edges const Edge = query.edge.type - const returns = returnValues(edges) - const queryProp = flip(prop)(query) - const [from, edge, to] = map(queryProp, ['from', 'edge', 'to']) - const [fn, en] = [from.name, edge.name] - const tn = ifElse(prop('relationship'), - path('from.name'), - prop('name'), - to - ) - - const resolve = resolveNode(returns) return pipe( - resolve(fn, Edge.from[entity]), - resolve(en, entity), - resolve(tn, Edge.to[entity]), + resolveNode({ entity: Edge.from[entity], query: query.from }), + resolveNode({ entity, query: query.edge }), + resolveNode({ entity: Edge.to[entity], query: query.to }), )({}) } @@ -127,7 +124,7 @@ const resolveReturns = map( map(ifElse( path('query.relationship'), resolveRelationship, - diverge(resolveNode, [returnValues, nodeName, prop('entity'), always({})]) + flip(resolveNode)({}) )), reduce(mergeLeft, {}) )