From 3656fc42acf6b4dbd659070d2f0e2ae918555b3f Mon Sep 17 00:00:00 2001 From: Emma Date: Mon, 5 Aug 2024 04:00:00 -0600 Subject: [PATCH] first iteration of query and resolver --- lib/ttcQuery/TTCQueryParser.ts | 40 ++++------- lib/ttcQuery/TTCResolvers.ts | 117 +++++++++++++++++++++++++++++++++ types.d.ts | 9 ++- 3 files changed, 134 insertions(+), 32 deletions(-) create mode 100644 lib/ttcQuery/TTCResolvers.ts diff --git a/lib/ttcQuery/TTCQueryParser.ts b/lib/ttcQuery/TTCQueryParser.ts index dd38aaa..8026652 100644 --- a/lib/ttcQuery/TTCQueryParser.ts +++ b/lib/ttcQuery/TTCQueryParser.ts @@ -1,6 +1,4 @@ -type QueryableObject = Record; - -class TtcQueryParser { +export class TTCQueryParser { private data: QueryableObject; private relativeMap: Map; @@ -26,24 +24,12 @@ class TtcQueryParser { } else if (query.startsWith("$")) { result = this.queryRelativeObject(query, currentObject); } else { - result = this.queryPublication(query); + result = this.searchInObject(this.data, query); } return result; } - private queryPublication(query: string): any[] { - // Example implementation for searching publication - const publicationMatch = query.match(/^(\w+)(\[(\w+)\])?(\..+)?/); - if (publicationMatch) { - const subQuery = publicationMatch[4]; - - // Search within the publication data - return this.searchInObject(this.data, subQuery); - } - return []; - } - private queryCurrentObject( query: string, currentObject: QueryableObject @@ -109,7 +95,9 @@ class TtcQueryParser { return []; } } else { - current = current.map((e: any) => e[key]); + current = Array.isArray(current) + ? current.map((e: any) => e[key]) + : current[key]; } } else { return []; @@ -161,17 +149,11 @@ class TtcQueryParser { } // Example usage: -const data = { - relative: true, - weapon_abilities: [ - { name: "Rapid Fire", body: "Shoot again" }, - { name: "Sustained Hits", body: "More damage", relative: true }, - ], -}; +// const -const parser = new TtcQueryParser(data); +// const parser = new TTCQueryParser(data); -// Example queries -console.log(parser.search("weapon_abilities[name=Rapid Fire].body")); // Example output -// console.log(parser.search("^weapon_abilities[name=Rapid Fire]", data)); // Example output -console.log(parser.search("$weapon_abilities[name=Rapid Fire].body", data)); // Example output +// // Example queries +// console.log(parser.search("$weapon_abilities[name=Rapid Fire].body")); // Example output +// // console.log(parser.search("^weapon_abilities[name=Rapid Fire]", data)); // Example output +// console.log(parser.search("$weapon_abilities[name=Rapid Fire].body", data)); // Example output diff --git a/lib/ttcQuery/TTCResolvers.ts b/lib/ttcQuery/TTCResolvers.ts new file mode 100644 index 0000000..80299ce --- /dev/null +++ b/lib/ttcQuery/TTCResolvers.ts @@ -0,0 +1,117 @@ +import { Dice } from "../dice"; +import { TTCQueryParser } from "./TTCQueryParser"; + +export class TTCQueryResolver { + private parser: TTCQueryParser | null; + private context: QueryableObject | null = null; + + private stack: any[] = []; + + constructor(parser?: TTCQueryParser) { + this.parser = parser || null; + } + + public setParser(parser: TTCQueryParser) { + this.parser = parser; + } + + public setContext(obj: QueryableObject) { + this.context = obj; + } + + public resolve(resolver: string, onDemand?: boolean) { + const resList = resolver.split(","); + for (const res of resList) { + this.stack.push(this.parseResolver(res)); + } + const last = this.stack.at(-1); + if (typeof last === "function" && !onDemand) return last(); + return last; + } + + private parseResolver(resolver: string) { + if (this.isArithmetic(resolver)) return this.solveArithmetic(resolver); + if (this.isQuery(resolver)) this.runQuery(resolver); + } + private isQuery(resolver: string) { + return ( + resolver.startsWith("?") || + resolver.startsWith("_") || + /^\$\d\./.test(resolver) + ); + } + private runQuery(query: string) { + if (!this.parser) throw "Parser not defined in query resolver"; + + if (query.startsWith("$")) { + const [_, idx, q] = query.match(/^(\$\d+)\.(.*)/) || []; + if (!_) throw "Detected stack query but did not match the regex"; + const stackItem = this.getFromStack(idx); + if (typeof stackItem === "string" && Dice.isDice(stackItem)) { + return this.handleDice(stackItem, q); + } + + return this.parser.search(q); + } + + // if (query.startsWith("?") || query.startsWith("_")) + return query.startsWith("_") && this.context + ? this.parser.search(query.replace("_", ""), this.context) + : this.parser.search(query.replace(/^[?_].?/, "")); + } + + private handleDice(dice: string, query: string) { + const d = new Dice(dice); + const [method, n] = query.split(":"); + let num = Number(n); + if (n.startsWith("$")) num = this.getFromStack(n); + switch (method) { + case "roll": + return () => d.roll(); + case "rollAvg": + return () => d.rollAvg(); + case "rollTimes": + return () => d.rollTimes(num); + case "rollTimesAvg": + return () => d.rollTimesAvg(num); + default: + return "No valid method provided for dice"; + } + } + + private isArithmetic(resolver: string) { + return resolver.split(/\+|\/|-|\*|\^/).filter((e) => !!e).length > 1; + } + private solveArithmetic(resolver: string) { + const [n1, op, n2] = resolver + .match(/(\$?\d+)([+\-*\/^])(\$?\d+)/) + ?.slice(1) || ["", "+", ""]; + let num1 = Number(n1), + num2 = Number(n2); + + if (n1.startsWith("$")) num1 = this.getFromStack(n1); + if (n2.startsWith("$")) num2 = this.getFromStack(n2); + console.log(num1, num2); + + switch (op) { + case "+": + return num1 + num2; + case "-": + return num1 - num2; + case "*": + return num1 * num2; + case "/": + return num1 / num2; + case "^": + return num1 ^ num2; + default: + throw "Arithmetic detected but no proper operator assigned"; + } + } + + private getFromStack(stackIndex: string): T { + const i = Number(stackIndex.replace("$", "")); + const val = this.stack[i] as T; + return val; + } +} diff --git a/types.d.ts b/types.d.ts index 1a627e9..318e0d7 100644 --- a/types.d.ts +++ b/types.d.ts @@ -31,7 +31,7 @@ type FrontMatter = Record; type SearchFunction = ( s: string, start: number, - end: number, + end: number ) => { start: number; end: number; @@ -53,7 +53,7 @@ type IdentifierRegistration = >( parseFunction: (s: string, rx: RegExp) => IdentifiedToken, renderFunction: TokenRenderer, openTagRx?: RegExp, - closeTagRx?: RegExp, + closeTagRx?: RegExp ) => void; // Schema @@ -88,6 +88,9 @@ type InputBinder = { name: string; value: string | number; onChange: ( - e: ChangeEvent, + e: ChangeEvent ) => void; }; + +// Query +type QueryableObject = Record;