Working on test framework

This commit is contained in:
2021-03-30 09:07:02 +11:00
parent 9f4b869d84
commit f4dd51ac31
4 changed files with 129 additions and 13 deletions

View File

@@ -138,8 +138,9 @@ The fields can be altered as well, using the query language's built-in keywords:
* delete * delete
* match * match
* set * set
* typeName
`create`, `update` and `delete` work as expected. `create`, `update` and `delete` are still to be defined properly, but they'll probably work like this:
### Create ### Create

View File

@@ -7,10 +7,10 @@ const parseInput = require('./parse-input');
const buildTypeGraph = (schema, options) => { const buildTypeGraph = (schema, options) => {
//the default graph //the default graph
let graph = { let graph = {
String: { scalar: true }, String: { typeName: 'String', scalar: true },
Integer: { scalar: true }, Integer: { typeName: 'Integer', scalar: true },
Float: { scalar: true }, Float: { typeName: 'Float', scalar: true },
Boolean: { scalar: true }, Boolean: { typeName: 'Boolean', scalar: true },
}; };
//parse the schema //parse the schema
@@ -35,7 +35,7 @@ const buildTypeGraph = (schema, options) => {
throw 'Unexpected keyword ' + tokens[pos]; throw 'Unexpected keyword ' + tokens[pos];
} }
graph[tokens[pos++]] = { scalar: true }; graph[tokens[pos++]] = { typeName: tokens[pos - 1], scalar: true };
if (options.debug) { if (options.debug) {
console.log(`Defined ${tokens[pos - 1]}:\n`, graph[tokens[pos - 1]]); console.log(`Defined ${tokens[pos - 1]}:\n`, graph[tokens[pos - 1]]);
@@ -63,7 +63,7 @@ const parseCompoundType = (tokens, pos, scalars, options) => {
} }
//graph component to be returned //graph component to be returned
const compound = {}; const compound = { typeName: tokens[pos - 1] };
//for each line of the compound type //for each line of the compound type
while (tokens[pos++] && tokens[pos] !== '}') { while (tokens[pos++] && tokens[pos] !== '}') {

View File

@@ -1 +1 @@
["type", "scalar", "create", "update", "delete", "set", "match"] ["type", "scalar", "create", "update", "delete", "set", "match", "typeName"]

View File

@@ -1,7 +1,122 @@
//the library to test //mock tools
const sineQL = require('../source/index.js'); const books = {
findAll: async args => {
let arr = [
{ title: 'The Wind in the Willows', published: '1908-06-15' }
];
//the dummy values const { attributes, where } = args;
arr = arr.filter(el => !where || el.title == where.title || el.published == where.published); //TODO: fix this
return arr;
}
}
const authors = {
findAll: async args => {
const arr = [
{ name: 'Kenneth Grahame', bookIds: [1] },
];
const { attributes, where } = args;
arr = arr.filter(el => !where || el.title == where.title || el.published == where.published); //TODO: fix this
return arr;
}
}
//the handler functions return arrays for each type, containing every element that satisfies the queries
//the "query" argument contains the object built from the sineQL query
//the "graph" argument contains the typeGraph
//the task of the handler functions is to query the database, and return the correct results
/* possible values for "query" include:
{
typeName: 'Author',
name: { typeName: 'String', scalar: true, match: 'Kenneth Grahame' },
books: { typeName: 'Book', match: {
typeName: 'Book',
title: { typeName: 'String', scalar: true, match: 'The wind in the Willows' }
published: { typeName: 'Date', scalar: true }
}
}
*/
//depth-first search seems to be the best option
//Each query shouldn't know if it's a sub-query
const handler = {
//complex compound
Author: async (query, graph) => {
//get the fields alone
const { typeName, ...fields } = query;
//get the names of matched fields
const matchedNames = Object.keys(fields.filter(field => field.match));
//short-circuit if querying everything
const where = {};
if (matchedNames.length > 0) {
//build the "where" object
matchedNames.forEach(mn => {
where[mn] = {
[Op.eq]: query[mn].match
}
});
}
//these are field names
const scalars = Object.keys(fields).filter(field => graph[field.typeName].scalar);
const nonScalars = Object.keys(fields).filter(field => !graph[field.typeName].scalar);
const results = await authors.findAll({
attributes: scalars, //fields to find (keys)
where: where
}); //sequelize ORM model
nonScalars.forEach(nonScalar => {
//delegate to a deeper part of the tree
results[nonScalar] = handler[fields[nonScalar].typeName](fields[nonScalar], graph);
});
//finally, return the results
return results;
},
//simple compound
Book: async (query, graph) => {
//get the fields alone
const { typeName, ...fields } = query;
//get the names of matched fields
const matchedNames = Object.keys(fields.filter(field => field.match));
//short-circuit if querying everything
const where = {};
if (matchedNames.length > 0) {
//build the "where" object
matchedNames.forEach(mn => {
where[mn] = {
[Op.eq]: query[mn].match
}
});
}
//return the result
return await books.findAll({
attributes: Object.keys(fields), //fields to find
where: where
}); //sequelize ORM model
}
};
//the matching schema
const schema = ` const schema = `
scalar Date scalar Date
@@ -16,8 +131,8 @@ type Author {
} }
`; `;
const handler = null; //the library to test
const sineQL = require('../source/index.js');
//run the function in debug mode (builds type graph) //run the function in debug mode (builds type graph)
const sine = sineQL(schema, handler, { debug: true }); const sine = sineQL(schema, handler, { debug: true });