first iteration of query and resolver
This commit is contained in:
parent
7839dbbc1c
commit
3656fc42ac
@ -1,6 +1,4 @@
|
|||||||
type QueryableObject = Record<string, any>;
|
export class TTCQueryParser {
|
||||||
|
|
||||||
class TtcQueryParser {
|
|
||||||
private data: QueryableObject;
|
private data: QueryableObject;
|
||||||
private relativeMap: Map<QueryableObject, QueryableObject>;
|
private relativeMap: Map<QueryableObject, QueryableObject>;
|
||||||
|
|
||||||
@ -26,24 +24,12 @@ class TtcQueryParser {
|
|||||||
} else if (query.startsWith("$")) {
|
} else if (query.startsWith("$")) {
|
||||||
result = this.queryRelativeObject(query, currentObject);
|
result = this.queryRelativeObject(query, currentObject);
|
||||||
} else {
|
} else {
|
||||||
result = this.queryPublication(query);
|
result = this.searchInObject(this.data, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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(
|
private queryCurrentObject(
|
||||||
query: string,
|
query: string,
|
||||||
currentObject: QueryableObject
|
currentObject: QueryableObject
|
||||||
@ -109,7 +95,9 @@ class TtcQueryParser {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
current = current.map((e: any) => e[key]);
|
current = Array.isArray(current)
|
||||||
|
? current.map((e: any) => e[key])
|
||||||
|
: current[key];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
@ -161,17 +149,11 @@ class TtcQueryParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Example usage:
|
// Example usage:
|
||||||
const data = {
|
// const
|
||||||
relative: true,
|
|
||||||
weapon_abilities: [
|
|
||||||
{ name: "Rapid Fire", body: "Shoot again" },
|
|
||||||
{ name: "Sustained Hits", body: "More damage", relative: true },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const parser = new TtcQueryParser(data);
|
// const parser = new TTCQueryParser(data);
|
||||||
|
|
||||||
// Example queries
|
// // Example queries
|
||||||
console.log(parser.search("weapon_abilities[name=Rapid Fire].body")); // Example output
|
// 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]", data)); // Example output
|
||||||
console.log(parser.search("$weapon_abilities[name=Rapid Fire].body", data)); // Example output
|
// console.log(parser.search("$weapon_abilities[name=Rapid Fire].body", data)); // Example output
|
||||||
|
117
lib/ttcQuery/TTCResolvers.ts
Normal file
117
lib/ttcQuery/TTCResolvers.ts
Normal file
@ -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<number>(n1);
|
||||||
|
if (n2.startsWith("$")) num2 = this.getFromStack<number>(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<T>(stackIndex: string): T {
|
||||||
|
const i = Number(stackIndex.replace("$", ""));
|
||||||
|
const val = this.stack[i] as T;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
9
types.d.ts
vendored
9
types.d.ts
vendored
@ -31,7 +31,7 @@ type FrontMatter = Record<string, string>;
|
|||||||
type SearchFunction = (
|
type SearchFunction = (
|
||||||
s: string,
|
s: string,
|
||||||
start: number,
|
start: number,
|
||||||
end: number,
|
end: number
|
||||||
) => {
|
) => {
|
||||||
start: number;
|
start: number;
|
||||||
end: number;
|
end: number;
|
||||||
@ -53,7 +53,7 @@ type IdentifierRegistration = <N = Record<string, string>>(
|
|||||||
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<N>,
|
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<N>,
|
||||||
renderFunction: TokenRenderer<N>,
|
renderFunction: TokenRenderer<N>,
|
||||||
openTagRx?: RegExp,
|
openTagRx?: RegExp,
|
||||||
closeTagRx?: RegExp,
|
closeTagRx?: RegExp
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
// Schema
|
// Schema
|
||||||
@ -88,6 +88,9 @@ type InputBinder = {
|
|||||||
name: string;
|
name: string;
|
||||||
value: string | number;
|
value: string | number;
|
||||||
onChange: (
|
onChange: (
|
||||||
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>,
|
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
|
||||||
) => void;
|
) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Query
|
||||||
|
type QueryableObject = Record<string, any>;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user