graph-ecs/src/query/match.js
2024-11-15 00:36:19 -06:00

64 lines
1.9 KiB
JavaScript

import { identifier, literal, Symbol, ws } from './common.js'
import { Node, Edge, KeyValuePair, Label, Name, Direction, DirectedEdge } from './types.js'
import { curry, is } from '../fn.js'
import { many, maybe, map, seq, skip, between, noCaseString, separated, list, any } from '../parser.js'
const { Bracket, Colon, Comma, Hyphen } = Symbol
const name = map(
([x]) => new Name(x),
identifier
)
const trim = curry((parser, state) => (
between(ws, parser, ws, state)
))
const label = map(([x]) => new Label(x), seq(trim(skip(Colon)), identifier))
const bracketed = curry((value, { Left, Right }, state) => (
between(trim(Left), value, trim(Right), state)
))
const kvp = map(
([k, v]) => new KeyValuePair(k, v),
separated(name, trim(Colon), literal)
)
export const kvps = list(trim(Comma), kvp)
export const properties = bracketed(kvps, Bracket.Curly)
const id = seq(maybe(name), label)
const makeObj = Ctr => params => {
const [name, label] = is(Name, params[0]) ? [params[0], params[1]] : [undefined, params[0]]
const properties = !name ? params.slice(1) : params.slice(2)
return new Ctr(name, label, properties)
}
export const node = map(
makeObj(Node),
bracketed(seq(id, maybe(properties)), Bracket.Round)
)
export const edge = map(
makeObj(Edge),
bracketed(seq(id, maybe(properties)), Bracket.Square)
)
const arrowRight = map(() => Direction.Right, seq(Hyphen, Bracket.Angle.Right))
const arrowLeft = map(() => Direction.Left, seq(Bracket.Angle.Left, Hyphen))
const relationshipRight = map(([edge, direction]) =>
DirectedEdge.fromEdge(edge, direction),
seq(skip(Hyphen), edge, arrowRight)
)
const relationshipLeft = map(([direction, edge]) =>
DirectedEdge.fromEdge(edge, direction),
seq(arrowLeft, edge, skip(Hyphen))
)
const relationship = seq(any(relationshipRight, relationshipLeft), node)
const keyword = noCaseString('match')
const params = seq(node, many(relationship))
export const statement = seq(skip(keyword), ws, params)