mirror of
https://github.com/Ratstail91/sineQL.git
synced 2025-11-29 02:34:28 +11:00
Create keyword is working, very complex
This commit is contained in:
@@ -36,11 +36,6 @@ const sineQL = (schema, { queryHandlers, createHandlers }, options = {}) => {
|
|||||||
|
|
||||||
const result = await createHandlers[tokens[1]](createTree, typeGraph);
|
const result = await createHandlers[tokens[1]](createTree, typeGraph);
|
||||||
|
|
||||||
if (options.debug) {
|
|
||||||
console.log('Create tree results:');
|
|
||||||
console.dir(result, { depth: null });
|
|
||||||
}
|
|
||||||
|
|
||||||
return [200, result];
|
return [200, result];
|
||||||
|
|
||||||
case 'update':
|
case 'update':
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const parseCreateTree = (tokens, typeGraph, options) => {
|
|||||||
|
|
||||||
//the return
|
//the return
|
||||||
const result = [];
|
const result = [];
|
||||||
|
const type = tokens[current - 1];
|
||||||
|
|
||||||
if (tokens[current] == '[') {
|
if (tokens[current] == '[') {
|
||||||
current++;
|
current++;
|
||||||
@@ -33,10 +34,10 @@ const parseCreateTree = (tokens, typeGraph, options) => {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
//read the block of lines
|
//read the block of lines
|
||||||
const [block, pos] = readBlock(tokens, current, tokens[current - 1], typeGraph, options);
|
const [block, pos] = readBlock(tokens, current, type, typeGraph, options);
|
||||||
|
|
||||||
//insert the typename into the top-level block
|
//insert the typename into the top-level block
|
||||||
block['typeName'] = tokens[current - 1];
|
block['typeName'] = type;
|
||||||
|
|
||||||
//insert create into the top-level block
|
//insert create into the top-level block
|
||||||
block['create'] = true;
|
block['create'] = true;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ const parseInput = (body, allowStrings, options) => {
|
|||||||
switch(body[current - 1]) {
|
switch(body[current - 1]) {
|
||||||
case '{':
|
case '{':
|
||||||
case '}':
|
case '}':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
//push just this symbol
|
//push just this symbol
|
||||||
tokens.push(body.substring(current - 1, current));
|
tokens.push(body.substring(current - 1, current));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -62,10 +62,17 @@ const createHandlers = {
|
|||||||
//apply the following to an array of authors
|
//apply the following to an array of authors
|
||||||
const promises = create.map(async author => {
|
const promises = create.map(async author => {
|
||||||
//get the fields alone
|
//get the fields alone
|
||||||
const { typeName, create, match, set, ...fields } = author;
|
const { typeName, create, match, ...fields } = author;
|
||||||
|
|
||||||
//if we are creating a new element (default with Author as a top-level only type)
|
//if we are creating a new element (default with Author as a top-level only type)
|
||||||
if (create) {
|
if (create) {
|
||||||
|
//check every unique field is being created
|
||||||
|
Object.keys(fields).forEach(field => {
|
||||||
|
if (graph[typeName][field].unique && !fields[field].create) {
|
||||||
|
throw `Must create a new value for unique fields (${typeName} ${field})`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
//check the created scalar fields (value must not exist in the database yet)
|
//check the created scalar fields (value must not exist in the database yet)
|
||||||
const createdOrs = Object.keys(fields).filter(field => fields[field].scalar && fields[field].create).map(field => { return { [field]: fields[field].create }; });
|
const createdOrs = Object.keys(fields).filter(field => fields[field].scalar && fields[field].create).map(field => { return { [field]: fields[field].create }; });
|
||||||
|
|
||||||
@@ -79,53 +86,30 @@ const createHandlers = {
|
|||||||
//enter error state
|
//enter error state
|
||||||
Object.keys(fields).forEach(field => {
|
Object.keys(fields).forEach(field => {
|
||||||
if (fields[field].create == createdFound[field]) {
|
if (fields[field].create == createdFound[field]) {
|
||||||
throw `Cannot create Author ${field} with value ${fields[field].create} (value already exists)`;
|
throw `Cannot create Author field '${field}' with value '${fields[field].create}' (value already exists)`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//no error field found, continue?
|
//no error field found, why?
|
||||||
|
throw 'Unknown error (createHandlers.Author)';
|
||||||
}
|
}
|
||||||
|
|
||||||
//create the element
|
//create the element (with created scalar fields)
|
||||||
const args = {};
|
const args = {};
|
||||||
Object.keys(fields).filter(field => fields[field].scalar).forEach(field => args[field] = fields[field].create || fields[field].set);
|
Object.keys(fields).filter(field => fields[field].scalar).forEach(field => args[field] = fields[field].create);
|
||||||
const createdAuthor = await authors.create(args);
|
const createdAuthor = await authors.create(args);
|
||||||
|
|
||||||
//pass on to the books
|
//pass on to the sub-objects (books)
|
||||||
Object.keys(fields).filter(field => !fields[field].scalar).forEach(nonScalar => fields[nonScalar].forEach(element => element.authorId = createdAuthor.id));
|
Object.keys(fields).filter(field => !fields[field].scalar).forEach(nonScalar => fields[nonScalar].forEach(element => element.authorId = createdAuthor.id)); //hack in the authorId
|
||||||
Object.keys(fields).filter(field => !fields[field].scalar).forEach(nonScalar => {
|
Object.keys(fields).filter(field => !fields[field].scalar).forEach(nonScalar => {
|
||||||
//delegation
|
//delegation
|
||||||
createHandlers[graph[typeName][nonScalar].typeName](fields[nonScalar], graph);
|
createHandlers[graph[typeName][nonScalar].typeName](fields[nonScalar], graph);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//if we are matching an existing element
|
//just to check
|
||||||
else if (match) {
|
else {
|
||||||
//check the matched scalar fields (value must exist in the database)
|
throw `Fall through not implemented for Author (missed create & match)`;
|
||||||
const matchedAnds = Object.keys(fields).filter(field => fields[field].scalar && fields[field].match).map(field => { return { [field]: fields[field].match }; });
|
|
||||||
|
|
||||||
//these only match one
|
|
||||||
const matchedFound = await authors.findOne({
|
|
||||||
where: {
|
|
||||||
[Op.and]: matchedAnds
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!matchedFound) {
|
|
||||||
throw `Cannot match Author (no match exists)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
//pass on to the books
|
|
||||||
Object.keys(fields).filter(field => !fields[field].scalar).forEach(nonScalar => fields[nonScalar].forEach(element => element.authorId = matchedAuthor.id));
|
|
||||||
Object.keys(fields).filter(field => !fields[field].scalar).forEach(nonScalar => {
|
|
||||||
//delegation
|
|
||||||
createHandlers[graph[typeName][nonScalar].typeName](fields[nonScalar], graph);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//get the remaining scalar fields without create or match ('set' by default), not used - just an error
|
|
||||||
else if (set) {
|
|
||||||
throw 'Set not implemented for create Author';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -137,8 +121,85 @@ const createHandlers = {
|
|||||||
|
|
||||||
//simple compound
|
//simple compound
|
||||||
Book: async (create, graph) => {
|
Book: async (create, graph) => {
|
||||||
//TODO: incomplete
|
const promises = create.map(async book => {
|
||||||
console.log('-----', create)
|
//get the fields alone
|
||||||
|
const { typeName, authorId, create, match, ...fields } = book;
|
||||||
|
|
||||||
|
//if we are creating a new element(s)
|
||||||
|
if (create) {
|
||||||
|
//check every unique field is being created
|
||||||
|
Object.keys(fields).forEach(field => {
|
||||||
|
//authorId is hacked in from above
|
||||||
|
if (graph[typeName][field].unique && !fields[field].create) {
|
||||||
|
throw `Must create a new value for unique fields (${typeName} ${field})`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//check the created scalar fields (value must not exist in the database yet)
|
||||||
|
const createdOrs = Object.keys(fields).filter(field => fields[field].scalar && fields[field].create).map(field => { return { [field]: fields[field].create }; });
|
||||||
|
|
||||||
|
const createdFound = await books.findOne({
|
||||||
|
where: {
|
||||||
|
[Op.or]: createdOrs
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (createdFound) {
|
||||||
|
//enter error state
|
||||||
|
Object.keys(fields).forEach(field => {
|
||||||
|
if (fields[field].create == createdFound[field]) {
|
||||||
|
throw `Cannot create Book field '${field}' with value '${fields[field].create}' (value already exists)`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//no error field found, why?
|
||||||
|
throw 'Unknown error (createHandlers.Book)';
|
||||||
|
}
|
||||||
|
|
||||||
|
//create the element (with created scalar fields)
|
||||||
|
const args = {};
|
||||||
|
Object.keys(fields).filter(field => fields[field].scalar).forEach(field => args[field] = fields[field].create);
|
||||||
|
args['authorId'] = authorId; //hacked in
|
||||||
|
await books.create(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
//pulled from query (match existing books)
|
||||||
|
else if (match) {
|
||||||
|
//get the names of matched fields
|
||||||
|
const matchedNames = Object.keys(fields).filter(field => fields[field].match);
|
||||||
|
|
||||||
|
//short-circuit if querying everything
|
||||||
|
const where = {};
|
||||||
|
if (matchedNames.length > 0) {
|
||||||
|
//build the "where" object
|
||||||
|
matchedNames.forEach(mn => {
|
||||||
|
if (fields[mn].match !== true) {
|
||||||
|
where[mn] = { [Op.eq]: fields[mn].match };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//don't steal books
|
||||||
|
where['authorId'] = { [Op.eq]: null };
|
||||||
|
|
||||||
|
//update the sub-elements
|
||||||
|
await books.update({
|
||||||
|
authorId: authorId
|
||||||
|
}, {
|
||||||
|
where: where
|
||||||
|
}); //sequelize ORM model
|
||||||
|
}
|
||||||
|
|
||||||
|
//just to check
|
||||||
|
else {
|
||||||
|
throw `Fall through not implemented for Book (missed create & match)`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//handle promises
|
||||||
|
await Promise.all(promises).catch(e => console.error(e));
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const { books, authors } = require('./database/models');
|
|||||||
//create the dummy data
|
//create the dummy data
|
||||||
sequelize.sync().then(async () => {
|
sequelize.sync().then(async () => {
|
||||||
//*
|
//*
|
||||||
return; //DEBUG: delete this for debugging
|
// return; //DEBUG: delete this for debugging
|
||||||
|
|
||||||
await sequelize.query('DELETE FROM authors;');
|
await sequelize.query('DELETE FROM authors;');
|
||||||
await sequelize.query('DELETE FROM books;');
|
await sequelize.query('DELETE FROM books;');
|
||||||
@@ -72,7 +72,7 @@ const queryHandlers = require('./handlers/query-handlers');
|
|||||||
const createHandlers = require('./handlers/create-handlers');
|
const createHandlers = require('./handlers/create-handlers');
|
||||||
|
|
||||||
//run the setup function to create the closure (creates the type graph)
|
//run the setup function to create the closure (creates the type graph)
|
||||||
const sine = sineQL(schema, { queryHandlers, /* createHandlers */ }, { debug: true });
|
const sine = sineQL(schema, { queryHandlers, createHandlers }, { debug: false });
|
||||||
|
|
||||||
//actually ask the question
|
//actually ask the question
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user