From 71c201cae5c0d6e47f7641db89f01243ffa1cc61 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sat, 3 Jun 2023 22:32:27 +1000 Subject: [PATCH] Added Author query, creation handlers --- server/database/models/author.js | 8 +- server/database/models/book.js | 4 +- server/type-handlers/author-handlers.js | 149 +++++++++++++++++++++++- server/type-handlers/book-handlers.js | 9 +- tools/request.rest | 47 ++++---- 5 files changed, 181 insertions(+), 36 deletions(-) diff --git a/server/database/models/author.js b/server/database/models/author.js index 3f5b317..14ef765 100644 --- a/server/database/models/author.js +++ b/server/database/models/author.js @@ -1,7 +1,9 @@ const Sequelize = require('sequelize'); const sequelize = require('..'); -module.exports = sequelize.define('author', { +const Book = require("./book"); + +const Author = sequelize.define('author', { index: { type: Sequelize.INTEGER(11), allowNull: false, @@ -17,3 +19,7 @@ module.exports = sequelize.define('author', { unique: true, } }); + +Author.hasMany(Book); + +module.exports = Author; \ No newline at end of file diff --git a/server/database/models/book.js b/server/database/models/book.js index 30b7c28..acbf0c7 100644 --- a/server/database/models/book.js +++ b/server/database/models/book.js @@ -1,7 +1,7 @@ const Sequelize = require('sequelize'); const sequelize = require('..'); -module.exports = sequelize.define('book', { +const Book = sequelize.define('book', { index: { type: Sequelize.INTEGER(11), allowNull: false, @@ -23,3 +23,5 @@ module.exports = sequelize.define('book', { defaultValue: null } }); + +module.exports = Book; \ No newline at end of file diff --git a/server/type-handlers/author-handlers.js b/server/type-handlers/author-handlers.js index 74de90f..2958161 100644 --- a/server/type-handlers/author-handlers.js +++ b/server/type-handlers/author-handlers.js @@ -1,17 +1,158 @@ +const { Author, Book } = require('../database/models'); + +const { queryBookFields } = require("./book-handlers"); + +const queryAuthorFields = (query) => { + //subtypes to find + const subtypes = { + "books": { + model: Book, + query: queryBookFields, + } + }; + const include = []; + + //sequelize stuff to find + const attributes = []; + const where = {}; + + //specify fields to find + Object.keys(query) + .filter(key => query[key]) + .filter(key => key != 'typeName') //filter out this meta-field + .forEach(key => { + //all author members queried should be scalar + if (query[key].scalar) { + //push this key into the attributes list + attributes.push(key); + } + //handle compounds + else { + include.push({ + model: subtypes[key].model, + ...subtypes[key].query(query[key]) + }); //handle compound subtypes + } + + //filter the members to a specific value + if (query[key].match) { + where[key] = query[key].match == 'NULL' ? null : query[key].match; + } + }) + ; + + return { attributes, where, include }; +}; + const queryAuthor = async (query, typeGraph) => { - throw 'Not yet implemented'; + const authorFields = queryAuthorFields(query); + + try { + //search the database + return await Author.findAll({ + ...authorFields, + raw: true, + }); + } + catch(e) { + console.log(e); + throw "Query failed"; + } +}; + +const createAuthorFields = (query) => { + const subtypes = { + "Book": { + model: Book, + query: queryBookFields, + } + }; + + //hook to monkey wrap + let afterBulkCreate = (instances, options) => null; + + //the array of objects to insert + const records = []; + + query.forEach((q, idx) => { + //just in case + if (!q.create) { + throw 'Unexpected create == false'; + } + + //specify fields to create + Object.keys(q) + .filter(key => q[key]) + .filter(key => key != 'typeName' && key != 'create') //filter out these meta-fields + .forEach(key => { + //some author members should be scalar + if (q[key].scalar) { + //make sure this exists + records[idx] = records[idx] || {}; + + //push this key into the inserts list + records[idx][key] = q[key].create; + return; + } + + //find each compound type, associate it with the created instances (using a wrapped hook) + q[key].forEach(compoundType => { + const prev = afterBulkCreate; //cache prev impl. + + const { where } = subtypes[compoundType.typeName].query(compoundType); + + afterBulkCreate = (instances, options) => { + //monkey patch the associations + instances.forEach(instance => { + //BUGFIX: don't want records mixed + if (instance.name != q["name"]?.create) { + return; + } + + subtypes[compoundType.typeName].model.update({ + authorIndex: instance["index"], + }, { + where: where + }); + }); + + //continue + return prev(instances, options); + } + }); + }) + ; + }); + + return [records, { afterBulkCreate }]; }; const createAuthor = async (query, typeGraph) => { - throw 'Not yet implemented'; + const [authorRecords, authorOptions] = createAuthorFields(query); + + try { + Author.afterBulkCreate(authorOptions.afterBulkCreate) + + //insert into the database + await Author.bulkCreate( + authorRecords, + authorOptions, + ); + } + catch(e) { + console.log(e); + throw "Create failed"; + } + + return "OK"; }; const updateAuthor = async (query, typeGraph) => { - throw 'Not yet implemented'; + throw 'Author update handler not yet implemented'; }; const deleteAuthor = async (query, typeGraph) => { - throw 'Not yet implemented'; + throw 'Author delete handler not yet implemented'; }; module.exports = { diff --git a/server/type-handlers/book-handlers.js b/server/type-handlers/book-handlers.js index a8bec64..17f3877 100644 --- a/server/type-handlers/book-handlers.js +++ b/server/type-handlers/book-handlers.js @@ -1,7 +1,7 @@ const { Book } = require('../database/models'); //utils -const checkDateFormat = date => /(19\d{2}|20\d{2})[-\/.](0[1-9]|1[012])[-\/.](0[1-9]|[12][0-9]|3[01])/.test(date) || date == 'NULL'; +const checkDateFormat = date => /(19\d{2}|20\d{2})[-\/.](0[1-9]|1[012])[-\/.](0[1-9]|[12][0-9]|3[01])/.test(date) || date.toString().toUpperCase() == 'NULL'; const queryBookFields = (query) => { //sequelize stuff to find @@ -10,6 +10,7 @@ const queryBookFields = (query) => { //specify fields to find Object.keys(query) + .filter(key => query[key]) .filter(key => key != 'typeName') //filter out this meta-field .forEach(key => { //all book members queried should be scalar @@ -142,7 +143,7 @@ const updateBookFields = (query) => { const updateBook = async (query, typeGraph) => { const { updates, ...opts } = updateBookFields(query); -console.log(opts) + try { await Book.bulkCreate( updates, @@ -182,7 +183,7 @@ const deleteBook = async (query, typeGraph) => { //filter the members to a specific value if (q[key].match) { - where[key] = q[key].match == 'NULL' ? null : q[key].match; + where[key] = q[key].match.toString().toUpperCase() == 'NULL' ? null : q[key].match; } }) ; @@ -208,4 +209,6 @@ module.exports = { createBook, updateBook, deleteBook, + + queryBookFields, }; diff --git a/tools/request.rest b/tools/request.rest index 7779cd1..9b17804 100644 --- a/tools/request.rest +++ b/tools/request.rest @@ -13,7 +13,7 @@ Content-Type: text/plain create Book [ { - create title "The Philosophers Kidney Stone" + create title "The Philosopher's Kidney Stone" } { create title "The Chamber Pot of Secrets" @@ -42,32 +42,32 @@ Content-Type: text/plain update Book [ { - match title "The Philosophers Kidney Stone" - update published "1969-04-21" + match title "The Philosopher's Kidney Stone" + update published "1997-06-26" } { match title "The Chamber Pot of Secrets" - update published "1969-04-22" + update published "1998-07-02" } { match title "The Prisoner of Aunt Kazban" - update published "1969-04-23" + update published "1999-07-08" } { match title "The Goblet of the Fire Cocktail" - update published "1969-04-24" + update published "2000-07-08" } { match title "The Order for Kleenex" - update published "1969-04-25" + update published "2003-06-21" } { match title "The Half-Priced Pharmacy" - update published "1969-04-26" + update published "2005-07-16" } { match title "Yeah, I Got Nothing" - update published "1969-04-27" + update published "2007-07-21" } ] @@ -76,27 +76,20 @@ update Book [ POST http://localhost:4000/sineql HTTP/1.1 Content-Type: text/plain -delete Book [ +create Author [ { - match title "The Philosophers Kidney Stone" + create name "Just Kidding" + match books [ + { + match title "Yeah, I Got Nothing" + } + { + match title "The Half-Priced Pharmacy" + } + ] } { - match title "The Chamber Pot of Secrets" - } - { - match title "The Prisoner of Aunt Kazban" - } - { - match title "The Goblet of the Fire Cocktail" - } - { - match title "The Order for Kleenex" - } - { - match title "The Half-Priced Pharmacy" - } - { - match title "Yeah, I Got Nothing" + create name "Mark Twain" } ]