async function queryExecutor({
testIds,
fetchQueriesFn = (d) => d,
runFn,
successFn,
failedFn,
getTotalQueriesFn,
getLastExecutedQueryFn,
initialCounter = 1,
backends = ["Arquero", "DuckDB", "VanillaJS"],
checkBackendPoss = false,
sleepTime = 1000
} = {}) {
let backendsComb = checkBackendPoss
? generatePermutations(backends)
: [d3.shuffle(backends)];
let log = { success: [], failed: [], error: [] };
let query;
let runAllTests = Inputs.toggle({ label: "Run All Experiments" });
let runBtn = Inputs.toggle({ label: "Run Experiment" });
let displayLogBtn = Inputs.toggle({ label: "Display Log" });
let queryCounter = initialCounter;
let testId = Inputs.select(testIds, { label: "Experiment Name" });
let target = html` ${
testIds?.length != 1 ? html`${runAllTests} ${testId}` : ""
} ${runBtn} ${displayLogBtn}`;
let lock = false;
let totalQueries;
let data;
let runBtnLabel;
let dataset;
let queryCount = { failed: 0 };
function displayLog() {
try {
if (displayLogBtn.value) {
if ({ ...arguments }[0] ? { ...arguments }[0].error : false) {
console.error(new Date().toTimeString(), ...arguments);
} else {
console.log(new Date().toTimeString(), ...arguments);
}
}
} catch (error) {
console.error(error);
}
}
displayLog();
function getStatus() {
return runBtnLabel;
}
async function executeQueries() {
lock = true;
let currentBackend = "";
let res = await getTotalQueriesFn(testId.value);
totalQueries = res?.queryId;
displayLog("Executing Queries");
while (runBtn.value) {
try {
let queries = await fetchQueriesFn(testId.value, queryCounter);
query = queries[0];
displayLog(`fetched Query ${query} for testId ${testId.value}`);
runBtnLabel?.remove();
runBtnLabel = htl.html`Status: Running Query <b>${queryCounter}</b> out of ${totalQueries} || Failed : <b>${queryCount.failed}</b>`;
target.appendChild(runBtnLabel);
if (!query) {
displayLog("Completed execution");
runBtnLabel?.remove();
runBtnLabel = htl.html`Completed All Queries Execiton`;
target.appendChild(runBtnLabel);
runBtn.value = false;
lock = false;
return;
}
for (let backends of backendsComb) {
displayLog(`Executing query : ${queryCounter}`);
if (dataset != query.dataset) {
let res = await getdatasets(query.dataset);
data = res[query.dataset];
dataset = query.dataset;
}
let res = await runFn({
query,
backends,
data,
successFn,
failedFn,
log,
displayLog,
testId: testId.value,
queryCount
});
target.dispatchEvent(new Event("input", { bubbles: true }));
await new Promise((d) => setTimeout(d, sleepTime));
}
} catch (error) {
log["error"].push({ query, error });
displayLog({ error, query });
failedFn({ error, query });
return;
} finally {
queryCounter += 1;
}
}
}
runBtn.addEventListener("input", async () => {
if (runBtn.value && !lock) {
runBtnLabel?.remove();
runBtnLabel = htl.html`Starting Execution`;
runBtn.appendChild(runBtnLabel);
await executeQueries();
}
});
testId.addEventListener("input", async () => {
runBtn.value = false;
runBtn.dispatchEvent(new Event("input", { bubbles: true }));
await updateQueryCounter();
});
async function updateQueryCounter() {
let res = await getTotalQueriesFn(testId.value);
totalQueries = res.queryId;
let successQuery = await getLastExecutedQueryFn(testId.value);
console.log({ successQuery, test: testId.value });
queryCounter = successQuery.queryId + 1;
}
let runAllBtnLabel;
runAllTests.addEventListener("input", async () => {
if (runAllTests.value) {
let testCounter = 1;
for (let test of testIds) {
queryCount = { failed: 0 };
runAllBtnLabel?.remove();
runAllBtnLabel = html`Running test ${testCounter} out ${testIds.length}`;
runAllTests.appendChild(runAllBtnLabel);
if (runAllTests.value) {
testId.childNodes[1].disabled = true;
testId.value = test;
await updateQueryCounter();
runBtn.value = true;
runBtn.childNodes[1].disabled = true;
await executeQueries();
await new Promise((d) => setTimeout(d, sleepTime / 10));
}
testCounter += 1;
}
runAllBtnLabel?.remove();
runAllBtnLabel = html`All Tests execution completed`;
testId.childNodes[1].disabled = false;
runAllTests.value = false;
runBtn.childNodes[1].disabled = false;
} else {
runAllBtnLabel?.remove();
}
});
testId.dispatchEvent(new Event("input", { bubbles: true }));
target.log = log;
target.status = getStatus;
return target;
}