"use strict"; const NoChange = require("./util/no-change"); const deriveNode = require("../derive-node"); const operations = require("../operations"); module.exports = { name: "test-context", category: [ "testing" ], visitors: { field: (node, { setState }) => { setState("seenField", node.name); return NoChange; }, select: (node, { registerStateHandler, defer }) => { let seenFields = new Set(); registerStateHandler("seenFieldsInWhere", (names) => { for (let name of names) { seenFields = seenFields.add(name); } }); // FIXME: Definitely need better AST modification/derivation tools... probably some sort of deep-modifying utility, for starters. Maybe merge-by-template can be of use here? With a custom AST node merger? It probably doesn't support non-enumerable properties correctly right now, though... return defer(() => { // console.log("Seen fields in WHERE in SELECT:", seenFields); let onlyFieldsClause = node.clauses.find((clause) => clause.type === "onlyFields"); let fieldsAlreadyAdded = onlyFieldsClause != null && Array.from(seenFields).every((field) => { return onlyFieldsClause.fields.some((existingField) => existingField.name === field); }); if (!fieldsAlreadyAdded) { // NOTE: This is a good test case for optimizer stability! Just returning a derived node in every case. let newOnlyFieldsClause = (onlyFieldsClause == null) ? operations.onlyFields(Array.from(seenFields)) : deriveNode(onlyFieldsClause, { fields: onlyFieldsClause.fields.concat(Array.from(seenFields).map((fieldName) => { return operations.field(fieldName); })) }); return deriveNode(node, { clauses: node.clauses .filter((clause) => clause.type !== "onlyFields") .concat([ newOnlyFieldsClause ]) }); } else { return NoChange; } }); }, where: (node, { registerStateHandler, defer, setState }) => { let seenFields = []; registerStateHandler("seenField", (name) => seenFields.push(name)); return defer(() => { setState("seenFieldsInWhere", seenFields); return NoChange; }); // let seenFields = []; // let id = Math.random(); // registerStateHandler("seenField", (name) => { // seenFields.push(name); // }); // console.log("Scheduling defer", id); // return defer(() => { // console.log("Defer called", id); // // MARKER: This gets called twice, but should only be called once! // // console.log("Seen fields in WHERE:", seenFields, require("util").inspect(node, {colors:true,depth:null})); // console.log("Seen fields in WHERE:", seenFields); // return NoChange; // }); } } };