From a5b77d4d03d9121004ace8028eaf026acafddc67 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Fri, 6 Mar 2020 17:40:02 +1100 Subject: [PATCH] Wrote some example client code --- server/handler.js | 71 ++++++++++++++++++++++++++++++++++------ server/simpleQL/index.js | 21 ++++++++---- 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/server/handler.js b/server/handler.js index 341f2c7..0468582 100644 --- a/server/handler.js +++ b/server/handler.js @@ -1,20 +1,71 @@ const database = require('./database.js'); +/* DOCS: The handler module connects the database to simpleQL. + * this will be user-implemented, but for now uses a fake database provided in database.js + * The 'scalars' will be objects containing a name and the type for each scalar field requested by a query. + * This can be used in several ways... + * + * The handlers should only handle scalar fields - compound fields will be queried separately by simpleQL. +*/ + //the handler routines const handler = { - Book: scalars => { + Book: (parent, scalars) => { + //takes an object which is the result of the parent query, if there is one { typeName: 'Author', scalars: [scalars], context: parentObject } + //takes an array of scalar types as objects: { typeName: 'String', name: 'title' } + //must return an array of objects containing the results + + let books = database.books; + + //if this is a sub-query, use the parent to narrow the search + if (parent && parent.typeName == 'Author') { + //filter based on parent object + books = books.filter(b => b.author.name == parent.context.name); + } + + //return all books + const fields = scalars.map(s => s.name); + return books.map(b => { + const ret = {}; + + if (fields.includes('title')) { + ret.title = b.title; + } + + if (fields.includes('published')) { + ret.published = b.published; + } + + return ret; + }); + }, + + Author: (parent, scalars) => { + let authors = database.authors; + + //if this is a sub-query, use the parent to find the author + if (parent && parent.typeName == 'Book') { + return authors.find(a => a.books.filter(b => b.title == parent.context.title).length > 0); + } + + //return all authors + const fields = scalars.map(s => s.name); + return authors.map(a => { + const ret = {}; + + if (fields.includes('name')) { + ret.name = a.name; + } + + return ret; + }); + }, + + create: (matches, sets) => { //TODO }, - Author: scalars => { - //TODO - }, - - create: (sets, matches) => { - //TODO - }, - - update: (sets, matches) => { + update: (matches, sets) => { //TODO }, diff --git a/server/simpleQL/index.js b/server/simpleQL/index.js index 075717c..ada206d 100644 --- a/server/simpleQL/index.js +++ b/server/simpleQL/index.js @@ -12,17 +12,17 @@ const main = (schema, handler) => { try { //check for keywords - switch(tokens[pos++]) { + switch(tokens[pos]) { case 'create': case 'update': case 'delete': - throw 'keyword not implemented'; + throw 'keyword not implemented: ' + tokens[pos]; //TODO break; //no leading keyword - regular query default: - //TODO: parse the query + parseQuery(handler, tokens, pos, typeGraph); return [200, '']; @@ -110,14 +110,19 @@ const parseCompoundType = (tokens, pos) => { type = type.slice(0, type.length - 2); } + //no mangled types or names + checkAlphaNumeric(type); + checkAlphaNumeric(name); + //can't use keywords if (['type', 'scalar'].includes(type) || ['type', 'scalar'].includes(name)) { throw 'Unexpected keyword found as type field or type name'; } - //no mangled types or names - checkAlphaNumeric(type); - checkAlphaNumeric(name); + //check for duplicate fields + if (Object.keys(compound).includes(name)) { + throw 'Unexpected duplicate filed name'; + } //finally, push to the compound definition compound[name] = { @@ -130,6 +135,10 @@ const parseCompoundType = (tokens, pos) => { return compound; }; +const parseQuery = (handler, tokens, pos, typeGraph) => { + //TODO +}; + //utils const checkAlphaNumeric = (str) => { if (!/^[a-z0-9]+$/i.test(str)) {