castelog
Version:
Programación JavaScript en castellano.
990 lines (984 loc) • 189 kB
JavaScript
//RestUtils.require("fs").writeFileSync(__dirname + "/../process.json", "" + process.pid, "utf8");
(function (scope, factory) {
const jsmodule = factory();
if (typeof window !== "undefined") {
window.Automatic_http_rest_api_interface = jsmodule;
}
if (typeof global !== "undefined") {
global.Automatic_http_rest_api_interface = jsmodule;
}
if (typeof define === "function") {
define("Automatic_http_rest_api_interface", jsmodule);
}
if (typeof module !== "undefined") {
module.exports = jsmodule;
}
return jsmodule;
})(this, () => function (factoryParameters) {
const defaultConfigurations = {
platform: "node", // "browser"
environment: "production", // "development", "testing"
debug: true,
debugSQL: true,
debugErrors: true,
responseWrapper: {
app: {
title: "Automatic HTTP REST API development",
author: {
name: "allnulled",
telephone: "+34 619 98 26 22",
url: "https://www.github.com/allnulled",
}
}
},
traceCallback: function (id) {
if (configurations.debug) {
if (configurations.platform === "node") {
console.log("\u001b[32m[TRACE]\u001b[0m " + id);
} else {
console.log("[TRACE] " + id);
}
}
},
traceSQLCallback: function (id) {
if (configurations.debugSQL) {
if (configurations.platform === "node") {
console.log("\u001b[33m[·SQL·]\u001b[0m " + id.split("\n").join("\n "));
} else {
console.log("[·SQL·] " + id);
}
}
},
traceErrorCallback: function (error) {
try {
if (configurations.debugErrors) {
let id = undefined;
if (typeof error === "string") {
id = error;
} else if (error instanceof Error) {
id = error.name + ": " + error.message + "\n " + error.stack + "";
}
if (configurations.platform === "node") {
console.log("\u001b[31m[ERROR]\u001b[0m " + id.split("\n").join("\n "));
} else {
console.log("[ERROR] " + id);
}
}
} catch (error) {
console.log(error);
}
},
};
const configurations = Object.assign(defaultConfigurations, factoryParameters);
const trace = configurations.traceCallback;
const traceSQL = configurations.traceSQLCallback;
const traceError = configurations.traceErrorCallback;
const RestClient = function (baseUrl, client = {}) {
Object.assign(client, {
defaults: {
headers: {
common: {
// @CONFIGURABLE
}
}
},
request: (method, url, requestArgs = {}, requestConfigArgs = {}, responseArgs = {}, ...args) => {
trace("DataServer.prototype.createClient:request");
const parsedUrl = RestUtils.require("url").parse(url);
trace("RestClient is requesting: " + url);
const requestParameters = Object.assign({}, requestArgs);
const responseParameters = Object.assign({}, responseArgs);
if (configurations.platform === "browser") {
const queryParameters = Object.assign({}, requestParameters);
requestParameters.headers = Object.assign({}, client.defaults.headers.common, requestConfigArgs.headers || {});
requestParameters.query = queryParameters;
if (parsedUrl.pathname.startsWith(client.server.basePathForData)) {
return client.server.dispatchSelf(method, url, requestParameters, responseParameters, ...args);
} else if (parsedUrl.pathname.startsWith(client.server.basePathForAuth)) {
return client.server.dispatchSelf(method, url, requestParameters, responseParameters, ...args);
} else if (parsedUrl.pathname.startsWith(client.server.basePathForProcess)) {
return client.server.dispatchSelf(method, url, requestParameters, responseParameters, ...args);
} else if (parsedUrl.pathname.startsWith(client.server.basePathForQuery)) {
return client.server.dispatchSelf(method, url, requestParameters, responseParameters, ...args);
} else {
throw new Error("Required parameter «url» to start as a valid basepath on browser in order to «createClient:request»");
}
} else if (configurations.platform === "node") {
const requestConfigParameters = Object.assign({}, { headers: {} }, requestConfigArgs);
Object.assign(requestConfigParameters.headers, client.defaults.headers.common,)
if (parsedUrl.pathname.startsWith(client.server.basePathForData)) {
return require("axios").create()[method](url, requestParameters, requestConfigParameters, ...args);
} else if (parsedUrl.pathname.startsWith(client.server.basePathForAuth)) {
return require("axios").create()[method](url, requestParameters, requestConfigParameters, ...args);
} else if (parsedUrl.pathname.startsWith(client.server.basePathForProcess)) {
return require("axios").create()[method](url, requestParameters, requestConfigParameters, ...args);
} else if (parsedUrl.pathname.startsWith(client.server.basePathForQuery)) {
return require("axios").create()[method](url, requestParameters, requestConfigParameters, ...args);
} else {
throw new Error("Required parameter «url» to start as a valid basepath on browser in order to «createClient:request»");
}
} else {
throw new Error("Required configuration «platform» to be a valid platform on node in order to «createClient:request»");
}
},
auth: {
login: (user, password) => {
trace("DataServer.prototype.createClient:auth:login");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForAuth, "/login");
return this.request("get", finalUrl + "?" + new URLSearchParams({
user,
password,
}).toString());
},
logout: (session_token) => {
trace("DataServer.prototype.createClient:auth:logout");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForAuth, "/logout");
return this.request("get", finalUrl + "?" + new URLSearchParams({
session_token: session_token,
}).toString());
},
register: (user, password, email) => {
trace("DataServer.prototype.createClient:auth:register");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForAuth, "/register");
return this.request("get", finalUrl + "?" + new URLSearchParams({
user,
password,
email,
}).toString());
},
confirm: (token) => {
trace("DataServer.prototype.createClient:auth:confirm");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForAuth, "/confirm");
return this.request("get", finalUrl + "?" + new URLSearchParams({
token,
}).toString());
},
forgot: (user) => {
trace("DataServer.prototype.createClient:auth:forgot");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForAuth, "/forgot");
return this.request("get", finalUrl + "?" + new URLSearchParams({
user,
}).toString());
},
recover: (token) => {
trace("DataServer.prototype.createClient:auth:recover");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForAuth, "/recover");
return this.request("get", finalUrl + "?" + new URLSearchParams({
token,
}).toString());
},
unregister: (user, password) => {
trace("DataServer.prototype.createClient:auth:unregister");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForAuth, "/unregister");
return this.request("get", finalUrl + "?" + new URLSearchParams({
user,
password,
}).toString());
},
},
rest: {
selectOne: (model, where) => {
trace("DataServer.prototype.createClient:rest:selectOne");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForData, model, "/select/one");
trace(finalUrl);
return this.request("get", finalUrl + "?" + new URLSearchParams({
where: JSON.stringify(where)
}).toString());
},
selectMany: (model, where = [], order = [], group = [], pagination = []) => {
trace("DataServer.prototype.createClient:rest:selectMany");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForData, model, "/select/many");
trace(finalUrl);
return this.request("get", finalUrl + "?" + new URLSearchParams({
where: JSON.stringify(where),
group: JSON.stringify(group),
order: JSON.stringify(order),
pagination: JSON.stringify(pagination)
}).toString());
},
insertOne: (model, item) => {
trace("DataServer.prototype.createClient:rest:insertOne");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForData, model, "/insert/one");
trace(finalUrl);
return this.request("get", finalUrl + "?" + new URLSearchParams({
item: JSON.stringify(item),
}).toString());
},
insertMany: (model, items) => {
trace("DataServer.prototype.createClient:rest:insertMany");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForData, model, "/insert/many");
trace(finalUrl);
return this.request("get", finalUrl + "?" + new URLSearchParams({
items: JSON.stringify(items),
}).toString());
},
updateOne: (model, where, values) => {
trace("DataServer.prototype.createClient:rest:updateOne");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForData, model, "/update/one");
trace(finalUrl);
return this.request("get", finalUrl + "?" + new URLSearchParams({
where: JSON.stringify(where),
values: JSON.stringify(values),
}).toString());
},
updateMany: (model, where, values) => {
trace("DataServer.prototype.createClient:rest:updateMany");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForData, model, "/update/many");
trace(finalUrl);
return this.request("get", finalUrl + "?" + new URLSearchParams({
where: JSON.stringify(where),
values: JSON.stringify(values),
}).toString());
},
deleteOne: (model, where) => {
trace("DataServer.prototype.createClient:rest:deleteOne");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForData, model, "/delete/one");
trace(finalUrl);
return this.request("get", finalUrl + "?" + new URLSearchParams({
where: JSON.stringify(where),
}).toString());
},
deleteMany: (model, where) => {
trace("DataServer.prototype.createClient:rest:deleteMany");
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForData, model, "/delete/many");
trace(finalUrl);
return this.request("get", finalUrl + "?" + new URLSearchParams({
where: JSON.stringify(where),
}).toString());
},
},
queries: client.server.queries.reduce((output, item) => {
output[item.id] = (parameters, ...args) => {
trace("DataServer.prototype.createClient:queries:" + item.id);
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForQuery, item.path);
trace(finalUrl);
return this.request("get", finalUrl + "?" + new URLSearchParams(parameters), ...args);
};
return output;
}, {}),
processes: client.server.processes.reduce((output, item) => {
output[item.id] = (parameters, ...args) => {
trace("DataServer.prototype.createClient:processes:" + item.id);
const finalUrl = baseUrl + RestUtils.require("path").join(client.server.basePathForProcess, item.path);
trace(finalUrl);
return this.request("get", finalUrl + "?" + new URLSearchParams(parameters), ...args);
};
return output;
}, {})
});
return Object.assign(this, client);
};
////////////////////////////////////////////////////////////////////////
// -1. Hooks class:
const Hooks = function () {
this.hooks = {};
};
Hooks.create = function (...args) {
trace("Hooks.create");
return new Hooks(...args);
};
Hooks.prototype.addHook = function (selectorString, hookId, event) {
trace("Hooks.prototype.addHook");
if (typeof selectorString !== "string") {
throw new Error("Required argument «selectorString» to be an array in order to «addHook»");
} else if (selectorString.length === 0) {
throw new Error("Required argument «selectorString» to have one or more items in order to «addHook»");
}
if (typeof hookId !== "string") {
throw new Error("Required argument «hookId» to be a string in order to «addHook»");
}
if (typeof event !== "function") {
throw new Error("Required argument «event» to be a function in order to «addHook»");
}
if (!(selectorString in this.hooks)) {
this.hooks[selectorString] = [];
}
this.hooks[selectorString].push({
id: hookId,
event
});
return this;
};
Hooks.prototype.addHooks = function (selectorList, hookId, event) {
trace("Hooks.prototype.addHooks");
if (!Array.isArray(selectorList)) {
throw new Error("Required argument «selectorList» to be an array in order to «addHooks»");
} else if (selectorList.length === 0) {
throw new Error("Required argument «selectorList» to have one or more items in order to «addHooks»");
}
if (typeof hookId !== "string") {
throw new Error("Required argument «hookId» to be a string in order to «addHooks»");
}
if (typeof event !== "function") {
throw new Error("Required argument «event» to be a function in order to «addHooks»");
}
const selectors = Array.isArray(selectorList) ? selectorList : [selectorList];
for (let indexSelectors = 0; indexSelectors < selectors.length; indexSelectors++) {
const selector = selectors[indexSelectors];
this.addHook(selector, hookId, event);
}
return this;
};
Hooks.prototype.useHook = async function (selectorString, parameters = {}) {
trace("Hooks.prototype.useHook");
try {
trace("Throwing hook: " + selectorString);
if (typeof selectorString !== "string") {
throw new Error("Required argument «selectorString» to be a string in order to «useHook»");
}
if (typeof parameters !== "object") {
throw new Error("Required argument «parameters» to be an object or omitted in order to «useHook»");
}
if (!(selectorString in this.hooks)) {
return parameters;
}
const hookEvents = this.hooks[selectorString];
IteratingSelection:
for (let indexList = 0; indexList < hookEvents.length; indexList++) {
const hookEvent = hookEvents[indexList];
let hookFunction = undefined;
if (typeof hookEvent === "object") {
if (typeof hookEvent.event === "function") {
hookFunction = hookEvent.event;
} else throw new Error("Required hook «" + selectorString + "» on index «" + indexList + "» on property «event» to be a function in order to «useHook»");
} else throw new Error("Required hook «" + selectorString + "» on index «" + indexList + "» to be an object in order to «useHook»");
const result = await hookFunction(parameters);
if (typeof result !== "undefined") {
parameters = result;
}
}
return parameters;
} catch (error) {
this.onError(error);
}
};
Hooks.prototype.replaceHook = function (selectorString, hookId, eventSource) {
trace("Hooks.prototype.replaceHook");
try {
if (typeof selectorString !== "string") {
throw new Error("Required argument «selectorString» to be a string in order to «replaceHook»");
}
if (!(selectorString in this.hooks)) {
throw new Error("Required argument «selectorString» to be a valid hook id in order to «replaceHook»");
}
if (typeof hookId !== "string") {
throw new Error("Required argument «hookId» to be a string in order to «replaceHook»");
}
if (typeof eventSource !== "object") {
throw new Error("Required argument «eventSource» to be an object in order to «replaceHook»");
}
if (typeof eventSource.id !== "string") {
throw new Error("Required argument «eventSource.id» to be a string in order to «replaceHook»");
}
if (typeof eventSource.event !== "function") {
throw new Error("Required argument «eventSource.event» to be a function in order to «replaceHook»");
}
let count = 0;
const hookEvents = this.hooks[selectorString];
IteratingSelection:
for (let indexList = 0; indexList < hookEvents.length; indexList++) {
const hookEvent = hookEvents[indexList];
if (hookEvent.id === hookId) {
this.hooks[selectorString].splice(indexList, 1, eventSource);
count++;
}
}
return count;
} catch (error) {
this.onError(error);
}
};
Hooks.prototype.removeHook = function (selectorString, hookId) {
trace("Hooks.prototype.removeHook");
try {
if (typeof selectorString !== "string") {
throw new Error("Required argument «selectorString» to be a string in order to «removeHook»");
}
if (!(selectorString in this.hooks)) {
throw new Error("Required argument «selectorString» to be a valid hook id in order to «removeHook»");
}
if (typeof hookId !== "string") {
throw new Error("Required argument «hookId» to be an string in order to «removeHook»");
}
let count = 0;
const hookEvents = this.hooks[selectorString];
IteratingSelection:
for (let indexList = 0; indexList < hookEvents.length; indexList++) {
const hookEvent = hookEvents[indexList];
if (typeof hookEvent === "object") {
if (hookEvent.id === hookId) {
this.hooks[selectorString].splice(indexList, 1);
count++;
}
}
}
return count;
} catch (error) {
this.onError(error);
}
};
////////////////////////////////////////////////////////////////////////
// 0. RestUtils object:
const RestUtils = {
prototype: {},
modules: {},
modulePolyfills: {
"mysql2/promise": {
createConnection: function () {
trace("polyfill://require:mysql2/promise:createConnection");
return {
ping() {
trace("polyfill://require:mysql2/promise:createConnection:ping");
// throw new Error("Method ping must be overriden");
},
query(query, ...args) {
trace("polyfill://require:mysql2/promise:createConnection:query");
console.log("Function «RestUtils.modulePolyfills.mysql2/promises.createConnection.query» to be overwritten");
console.log(query);
return [[], []];
},
proxifiedQuery(query, ...args) {
trace("polyfill://require:mysql2/promise:createConnection:proxifiedQuery");
traceSQL(query);
return this.query(query, ...args);
}
}
}
},
"url": {
parse: function (parameter) {
trace("polyfill://require:url:parse x " + parameter);
return new URL(parameter);
},
},
"sqlstring": {
sanitize: function (arg) {
trace("polyfill://require:sqlstring:sanitize");
return arg;
},
sanitizeId: function (arg) {
trace("polyfill://require:sqlstring:sanitizeId");
return arg;
},
},
"path": {
resolve: function (...args) {
trace("polyfill://require:path:resolve");
return ["", ...args].map(i => i.replace(/^\//g, "").replace(/\/$/g, "")).join("/");
},
join: function (...args) {
trace("polyfill://require:path:join");
return ["", ...args].filter(i => typeof i !== "undefined").map(i => i.replace(/^\//g, "").replace(/\/$/g, "")).join("/");
},
},
"http": {
createServer: function (controller) {
trace("polyfill://require:http:createServer");
return {
listen: function (options, callback) {
trace("polyfill://require:http:createServer:listen");
setTimeout(callback, 0);
}
}
}
},
},
require: function (modulepath) {
trace("RestUtils.require");
if (modulepath in RestUtils.modules) {
return RestUtils.modules[modulepath];
}
if (configurations.platform === "browser") {
if (modulepath in RestUtils.modulePolyfills) {
return RestUtils.modulePolyfills[modulepath];
} else {
throw new Error("Not identified package: " + modulepath);
}
}
RestUtils.modules[modulepath] = require(modulepath);
return RestUtils.modules[modulepath];
},
define: function (name, value) {
trace("RestUtils.define");
RestUtils.modules[name] = value;
},
definePolyfill: function (name, value) {
trace("RestUtils.definePolyfill");
RestUtils.modulePolyfills[name] = value;
},
wrapResponse: function (data) {
trace("RestUtils.wrapResponse");
return {
...configurations.responseWrapper,
...data,
time: new Date().toString()
};
},
respondContext: function (context) {
trace("RestUtils.respondContext");
const response = context.output;
const responseWrapped = RestUtils.wrapResponse(response);
const responseJson = JSON.stringify(responseWrapped, null, 2);
context.response.writeHead(200, { "Content-type": "application/json" });
context.response.write(responseJson);
return context.response.end();
},
generateRandomToken: function (len, alphabet = "abcdefghijklmnopqrstuvwxyz0123456789") {
trace("RestUtils.generateRandomToken");
let output = "";
for (let index = 0; index < len; index++) {
output += alphabet[Math.floor(Math.random() * alphabet.length)];
}
return output;
},
generateOnErrorFunction: function (id) {
trace("RestUtils.generateOnErrorFunction");
return function (error, propagate = true) {
trace(id);
traceError(error);
if (propagate) {
throw error;
}
};
},
generateContextByRequestResponseFactory: function (id) {
trace("RestUtils.generateContextByRequestResponseFactory");
return function (request, response) {
trace(id);
const parsedURL = RestUtils.require("url").parse(request.url, true);
return {
output: {},
parameters: {},
state: {},
input: {
url: parsedURL.pathname,
query: RestUtils.fromURLToQuerystringObject(request.url),
body: request.body,
params: request.params,
request,
response
},
request,
response,
};
};
},
generateOnDispatchErrorFunction: function (traceId) {
trace("RestUtils.generateOnDispatchErrorFunction");
return function (error, request, response) {
trace(traceId);
traceError(error);
response.writeHead(500, { "Content-Type": "application/json" });
const data = {
name: error.name,
message: error.message,
stack: Object.assign({}, error.stack.split(/\n /g))
};
const wrappedData = RestUtils.wrapResponse({
status: "error",
error: data
});
const wrappedJson = JSON.stringify(wrappedData, null, 2);
response.write(wrappedJson);
return response.end();
};
},
noop: function () { },
basicServiceFactory: function () {
trace("RestUtils.basicServiceFactory");
return function (modifications) {
trace("RestUtils.basicServiceFactory:Service");
Object.assign(this, modifications);
return this;
}
},
basicQueryFactory: function () {
trace("RestUtils.basicQueryFactory");
return function () {
trace("RestUtils.basicQueryFactory:Query");
return this;
}
},
basicProcessFactory: function () {
trace("RestUtils.basicProcessFactory");
return function () {
trace("RestUtils.basicProcessFactory:Process");
return this;
}
},
basicControllerFallback: function (request, response) {
trace("RestUtils.basicControllerFallback");
response.writeHead(404);
response.write("Error 404: Page was not found.");
return response.end();
},
sanitize: function (value) {
trace("RestUtils.sanitize");
return RestUtils.require("sqlstring").escape(value);
},
sanitizeId: function (id) {
trace("RestUtils.sanitizeId");
return RestUtils.require("sqlstring").escapeId(id);
},
availableOperators: {
"<": "<",
"<=": "<=",
">": ">",
">=": ">=",
"=": "=",
"!=": "!=",
"in": "IN",
"!in": "NOT IN",
// "contains": "contains",
// "!contains": "!contains",
},
validateStaticServiceInterface: function (staticInterface) {
trace("RestUtils.validateStaticServiceInterface");
if (typeof staticInterface !== "function") {
throw new Error("Required parameter «staticInterface» to be an function in order to «validateStaticServiceInterface»")
}
if (typeof staticInterface.table !== "string") {
throw new Error("Required parameter «staticInterface.table» to be a string in order to «validateStaticServiceInterface»")
}
if (typeof staticInterface.path !== "string") {
throw new Error("Required parameter «staticInterface.path» to be a string in order to «validateStaticServiceInterface»")
}
if (typeof staticInterface.creationScript !== "string") {
throw new Error("Required parameter «staticInterface.creationScript» to be a string in order to «validateStaticServiceInterface»")
}
if (typeof staticInterface.schema !== "object") {
throw new Error("Required parameter «staticInterface.schema» to be an object in order to «validateStaticServiceInterface»")
}
return true;
},
validateDynamicServiceInterface: function (dynamicInterface) {
trace("RestUtils.validateDynamicServiceInterface");
return true;
},
validateStaticQueryInterface: function (staticInterface) {
trace("RestUtils.validateStaticQueryInterface");
if (typeof staticInterface.path !== "string") {
throw new Error("Required parameter «staticInterface.path» to be a string in order to «validateStaticQueryInterface»")
}
if (typeof staticInterface.query !== "function") {
throw new Error("Required parameter «staticInterface.query» to be a function in order to «validateStaticQueryInterface»")
}
return true;
},
validateDynamicQueryInterface: function (dynamicInterface) {
trace("RestUtils.validateDynamicQueryInterface");
return true;
},
validateStaticProcessInterface: function (staticInterface) {
trace("RestUtils.validateStaticProcessInterface");
if (typeof staticInterface.path !== "string") {
throw new Error("Required parameter «staticInterface.path» to be a string in order to «validateStaticProcessInterface»")
}
if (typeof staticInterface.process !== "function") {
throw new Error("Required parameter «staticInterface.process» to be a function in order to «validateStaticProcessInterface»")
}
return true;
},
validateDynamicProcessInterface: function (dynamicInterface) {
trace("RestUtils.validateDynamicProcessInterface");
return true;
},
expandConnection: function (connection) {
trace("RestUtils.expandConnection");
connection.proxifiedQuery = function (query) {
trace("RestUtils.expandConnection:connection.proxifiedQuery");
traceSQL(query);
return this.query(query);
}
return connection;
},
formatTableFromRequest: function (context, { start, end }) {
trace("RestUtils.formatTableFromRequest");
return RestUtils.require("url").parse(context.request.url).pathname
.replace(start, "")
.split("")
.reverse()
.join("")
.replace(end.split("").reverse().join(""), "")
.split("")
.reverse()
.join("");
},
formatWhereFromRequest: function (context) {
trace("RestUtils.formatWhereFromRequest");
const where = context.input.query.where || "[]";
if (typeof where === "object") {
return where;
}
let whereData = undefined;
try {
whereData = JSON.parse(where);
} catch (error) {
throw new Error("Required parameter «where» to be a well-formed JSON object in order to «formatWhereFromRequest»");
}
if (!Array.isArray(whereData)) {
throw new Error("Required parameter «where» to be a JSON array in order to «formatWhereFromRequest»");
}
if (whereData.length === 0) {
return whereData;
}
for (let index = 0; index < whereData.length; index++) {
const whereRule = whereData[index];
if (!Array.isArray(whereRule)) {
throw new Error("Required parameter «where[" + index + "]» to be an array in order to «formatWhereFromRequest»");
}
if (whereRule.length < 3) {
throw new Error("Required parameter «where[" + index + "]» to be an array of 3 or more items in order to «formatWhereFromRequest»");
}
if (typeof whereRule[0] !== "string") {
throw new Error("Required parameter «where[" + index + "][0]» to be a string in order to «formatWhereFromRequest»");
}
if (typeof whereRule[1] !== "string") {
throw new Error("Required parameter «where[" + index + "][1]» to be a string in order to «formatWhereFromRequest»");
}
if (!(whereRule[1] in RestUtils.availableOperators)) {
throw new Error("Required parameter «where[" + index + "][1]» to be a valid query operator in order to «formatWhereFromRequest»");
}
}
return whereData;
},
formatOrderFromRequest: function (context) {
trace("RestUtils.formatOrderFromRequest");
const order = context.input.query.order || "[]";
let orderData = undefined;
if (typeof order === "object") {
orderData = order;
} else if (typeof order !== "string") {
throw new Error("Required parameter «context.input.query.order» to be an (optionally JSON) array in order to «formatOrderFromRequest»");
} else {
try {
orderData = JSON.parse(order);
} catch (error) {
throw new Error("Required parameter «order» to be a well-formed JSON object in order to «formatOrderFromRequest»");
}
}
if (!Array.isArray(orderData)) {
throw new Error("Required parameter «order» to be a JSON array in order to «formatOrderFromRequest»");
}
if (orderData.length === 0) {
orderData.push("id");
}
for (let index = 0; index < orderData.length; index++) {
const orderRule = orderData[index];
if (typeof orderRule !== "string") {
throw new Error("Required parameter «order[" + index + "]» to be a string in order to «formatOrderFromRequest»");
}
}
return orderData;
},
formatGroupFromRequest: function (context) {
trace("RestUtils.formatGroupFromRequest");
const group = context.input.query.group || "[]";
let groupData = undefined;
if (typeof group === "object") {
groupData = group;
} else if (typeof group !== "string") {
throw new Error("Required parameter «context.input.query.group» to be an (optionally JSON) array in order to «formatGroupFromRequest»");
} else {
try {
groupData = JSON.parse(group);
} catch (error) {
throw new Error("Required parameter «group» to be a well-formed JSON object in group to «formatGroupFromRequest»");
}
}
if (!Array.isArray(groupData)) {
throw new Error("Required parameter «group» to be a JSON array in group to «formatGroupFromRequest»");
}
if (groupData.length === 0) {
return groupData;
}
for (let index = 0; index < groupData.length; index++) {
const groupRule = groupData[index];
if (typeof groupRule !== "string") {
throw new Error("Required parameter «group[" + index + "]» to be a string in group to «formatGroupFromRequest»");
}
}
return groupData;
},
formatPaginationFromRequest: function (context) {
trace("RestUtils.formatPaginationFromRequest");
const pagination = context.input.query.pagination || "[1,20]";
let paginationData = undefined;
if (typeof pagination === "object") {
paginationData = pagination;
} else if (typeof pagination !== "string") {
throw new Error("Required parameter «context.input.query.pagination» to be an (optionally JSON) array in order to «formatPaginationFromRequest»");
} else {
try {
paginationData = JSON.parse(pagination);
} catch (error) {
throw new Error("Required parameter «pagination» to be a well-formed JSON object in pagination to «formatPaginationFromRequest»");
}
}
if (!Array.isArray(paginationData)) {
throw new Error("Required parameter «pagination» to be a JSON array in pagination to «formatPaginationFromRequest»");
}
if (paginationData.length === 0) {
return paginationData;
}
const [page = 1, items = 20] = paginationData;
if (typeof page !== "number") {
throw new Error("Required parameter «page» to be a number in order to «formatPaginationFromRequest»");
}
if (typeof items !== "number") {
throw new Error("Required parameter «items» to be a number in order to «formatPaginationFromRequest»");
}
if (page < 0) {
throw new Error("Required parameter «pagination[0]» to be a number higher or equal to 0 in order to «formatPaginationFromRequest»");
}
if (items < 1) {
throw new Error("Required parameter «pagination[1]» to be a number higher or equal to 1 in order to «formatPaginationFromRequest»");
}
return paginationData;
},
formatItemFromRequest: function (context) {
trace("RestUtils.formatItemFromRequest");
const item = context.input.query.item || "{}";
let itemData = undefined;
if (typeof item === "object") {
itemData = item;
} else if (typeof item !== "string") {
throw new Error("Required parameter «context.input.query.item» to be an (optionally JSON) object in order to «formatItemFromRequest»");
} else {
try {
itemData = JSON.parse(item);
} catch (error) {
throw new Error("Required parameter «item» to be a well-formed JSON object to «formatItemFromRequest»");
}
}
if (typeof itemData !== "object") {
throw new Error("Required parameter «item» to be a JSON object to «formatItemFromRequest»");
}
return itemData;
},
formatItemsFromRequest: function (context) {
trace("RestUtils.formatItemsFromRequest");
const items = context.input.query.items || "{}";
let itemsData = undefined;
if (typeof items === "object") {
itemsData = items;
} else if (typeof items !== "string") {
throw new Error("Required parameter «context.input.query.items» to be an (optionally JSON) object in order to «formatItemsFromRequest»");
} else {
try {
itemsData = JSON.parse(items);
} catch (error) {
throw new Error("Required parameter «item» to be a well-formed JSON object to «formatItemsFromRequest»");
}
}
if (!Array.isArray(itemsData)) {
throw new Error("Required parameter «items» to be an (optionally JSON) array in order to «formatItemsFromRequest»");
}
for (let index = 0; index < itemsData.length; index++) {
const itemData = itemsData[index];
if (typeof itemData !== "object") {
throw new Error("Required parameter «items[" + index + "]» to be a JSON object to «formatItemsFromRequest»");
}
}
return itemsData;
},
formatValuesFromRequest: function (context) {
trace("RestUtils.formatValuesFromRequest");
const values = context.input.query.values || "{}";
let valuesData = undefined;
if (typeof values === "object") {
valuesData = values;
} else if (typeof values !== "string") {
throw new Error("Required parameter «context.input.query.values» to be an (optionally JSON) object in order to «formatValuesFromRequest»");
} else {
try {
valuesData = JSON.parse(values);
} catch (error) {
throw new Error("Required parameter «values» to be a well-formed JSON object to «formatValuesFromRequest»");
}
}
if (Array.isArray(valuesData)) {
throw new Error("Required parameter «values» to be an object and not an array in order to «formatValuesFromRequest»");
} else if (typeof valuesData !== "object") {
throw new Error("Required parameter «values» to be an object in order to «formatValuesFromRequest»");
}
return valuesData;
},
fromWhereToSQL: function (where, wholeClause = false) {
trace("RestUtils.fromWhereToSQL");
if (!Array.isArray(where)) {
throw new Error("Required parameter «where» to be an array in order to «fromWhereToSQL»");
}
if (where.length === 0) {
return "# No filtering rules";
}
let query = where.map((whereRule, index) => {
const sanitizedSubject = RestUtils.sanitizeId(whereRule[0]);
const sanitizedOperation = RestUtils.availableOperators[whereRule[1]];
const unsanitizedObject = whereRule[2];
const thirdArgumentMode = whereRule[3] || "default";
let sanitizedObject = whereRule[2];
if (thirdArgumentMode === "default") {
if ((typeof unsanitizedObject !== "string") && (typeof unsanitizedObject !== "number")) {
throw new Error("Required argument «where[" + index + "][2]» to be a string or a number (on «default» mode) in order to «RestUtils.fromWhereToSQL»");
}
sanitizedObject = RestUtils.sanitize(unsanitizedObject);
} else if (thirdArgumentMode === "column") {
throw new Error("Required argument «where[" + index + "][3]» to be a valid mode and 'column' mode is not allowed in order to «RestUtils.fromWhereToSQL»");
sanitizedObject = RestUtils.sanitizeId(unsanitizedObject);
} else if (thirdArgumentMode === "null") {
sanitizedObject = "NULL";
} else if (thirdArgumentMode === "array") {
let parsedObject = undefined;
if (typeof unsanitizedObject === "string") {
try {
parsedObject = JSON.parse(unsanitizedObject);
} catch (error) {
throw new Error("Required argument «where[" + index + "][3]» to be a well-formed JSON in order to «RestUtils.fromWhereToSQL»");
}
} else if (Array.isArray(unsanitizedObject)) {
parsedObject = unsanitizedObject;
} else {
throw new Error("Required argument «where[" + index + "][2]» to be an (optionally JSON) array in order to «RestUtils.fromWhereToSQL»");
}
if (!Array.isArray(parsedObject)) {
throw new Error("Required argument «where[" + index + "][2]» to be a JSON array in order to «RestUtils.fromWhereToSQL»");
} else if (parsedObject.length === 0) {
throw new Error("Required argument «where[" + index + "][2]» to be a JSON array with 1 or more items in order to «RestUtils.fromWhereToSQL»");
}
sanitizedObject = "(" + parsedObject.map(item => RestUtils.sanitize(item)) + ")";
} else {
throw new Error("Required argument «where[" + index + "][3]» to be a a known mode in order to «RestUtils.fromWhereToSQL»");
}
return ` AND ${sanitizedSubject} ${sanitizedOperation} ${sanitizedObject}`;
}).join("\n");
if (wholeClause) {
query = query.replace(' AND ', ' WHERE ');
}
return query;
},
fromOrderToSQL: function (order, wholeClause = true) {
trace("RestUtils.fromOrderToSQL");
if (!Array.isArray(order)) {
throw new Error("Required parameter «order» to be an array in order to «fromOrderToSQL»");
}
if (order.length === 0) {
return "# No ordering rules";
}
let query = order.map((orderRule, index) => {
if (typeof orderRule !== "string") {
throw new Error("Required parameter «order[" + index + "]» to be a string in order «fromOrderToSQL»");
}
const isDescending = orderRule.startsWith("!");
const orderColumn = isDescending ? orderRule.substr(1) : orderRule;
return ", " + RestUtils.sanitizeId(orderColumn) + (isDescending ? ' DESC' : ' ASC');
}).join(", ");
if (wholeClause) {
query = query.replace(', ', ' ORDER BY ');
}
return query;
},
fromGroupToSQL: function (groups, wholeClause = true) {
trace("RestUtils.fromGroupToSQL");
if (!Array.isArray(groups)) {
throw new Error("Required parameter «groups» to be an array in order to «fromGroup