sails-arangojs
Version:
A sails-arangojs adapter for Sails / Waterline
145 lines (119 loc) • 6.02 kB
JavaScript
// █████╗ ██╗ ██╗ ██████╗ █████╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
// ██╔══██╗██║ ██║██╔════╝ ██╔══██╗██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
// ███████║██║ ██║██║ ███╗ ███████║██║ ██║ ██║██║ ██║██╔██╗ ██║
// ██╔══██║╚██╗ ██╔╝██║ ██║ ██╔══██║██║ ██║ ██║██║ ██║██║╚██╗██║
// ██║ ██║ ╚████╔╝ ╚██████╔╝ ██║ ██║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
// ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
//
module.exports = require('machine').build({
friendlyName: 'AVG',
description: 'Return the Average of the records matched by the query.',
inputs: {
datastore: {
description: 'The datastore to use for connections.',
extendedDescription:
'Datastores represent the config and manager required to obtain an active database connection.',
required: true,
readOnly: true,
example: '===',
},
models: {
description:
'An object containing all of the model definitions that have been registered.',
required: true,
example: '===',
},
query: {
description: 'A valid stage three Waterline query.',
required: true,
example: '===',
},
},
exits: {
success: {
description: 'The results of the avg query.',
outputType: 'ref',
},
invalidDatastore: {
description: 'The datastore used is invalid. It is missing key pieces.',
},
badConnection: {
friendlyName: 'Bad connection',
description:
'A connection either could not be obtained or there was an error using the connection.',
},
},
fn: async function avg(inputs, exits) {
// Dependencies
const _ = require('@sailshq/lodash');
const Helpers = require('./private');
// Store the Query input for easier access
const { query, models } = inputs;
query.meta = query.meta || {};
// Find the model definition
const WLModel = models[query.using];
if (!WLModel) {
return exits.invalidDatastore();
}
// Grab the pk column name (for use below)
let pkColumnName;
try {
pkColumnName = WLModel.attributes[WLModel.primaryKey].columnName;
} catch (e) {
return exits.error(e);
}
// Set a flag if a leased connection from outside the adapter was used or not.
const leased = _.has(query.meta, 'leasedConnection');
// ╔═╗╔═╗╔╗╔╦ ╦╔═╗╦═╗╔╦╗ ┌┬┐┌─┐ ┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┐┌┌┬┐
// ║ ║ ║║║║╚╗╔╝║╣ ╠╦╝ ║ │ │ │ └─┐ │ ├─┤ │ ├┤ │││├┤ │││ │
// ╚═╝╚═╝╝╚╝ ╚╝ ╚═╝╩╚═ ╩ ┴ └─┘ └─┘ ┴ ┴ ┴ ┴ └─┘┴ ┴└─┘┘└┘ ┴
// Convert the Waterline criteria into a Waterline Query Statement. This
// turns it into something that is declarative and can be easily used to
// build a SQL query.
// See: https://github.com/treelinehq/waterline-query-docs for more info
// on Waterline Query Statements.
let statement;
try {
statement = Helpers.query.compileStatement({
pkColumnName,
model: query.using,
method: 'avg',
criteria: query.criteria,
numericAttrName: query.numericAttrName,
});
} catch (e) {
return exits.error(e);
}
// ╔═╗╔═╗╔═╗╦ ╦╔╗╔ ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
// ╚═╗╠═╝╠═╣║║║║║║ │ │ │││││││├┤ │ │ ││ ││││
// ╚═╝╩ ╩ ╩╚╩╝╝╚╝ └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
// ┌─┐┬─┐ ┬ ┬┌─┐┌─┐ ┬ ┌─┐┌─┐┌─┐┌─┐┌┬┐ ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
// │ │├┬┘ │ │└─┐├┤ │ ├┤ ├─┤└─┐├┤ ││ │ │ │││││││├┤ │ │ ││ ││││
// └─┘┴└─ └─┘└─┘└─┘ ┴─┘└─┘┴ ┴└─┘└─┘─┴┘ └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
// Spawn a new connection for running queries on.
let session;
let results;
const { dbConnection } = Helpers.connection.getConnection(
inputs.datastore,
query.meta
);
try {
let sql = `FOR record in ${statement.tableName} \n`;
if (statement.letStatements) {
sql = `${sql}${statement.letStatements} \n`;
}
if (statement.whereClause) {
sql = `${sql} FILTER ${statement.whereClause}`;
}
sql = `${sql} COLLECT AGGREGATE avg = AVG(record.${statement.numericAttrName})`;
sql = `${sql} RETURN avg`;
const cursor = await dbConnection.query(sql);
cursor._result = await cursor.all();
results = _.isArray(cursor._result) ? cursor._result[0] : 0;
Helpers.connection.releaseConnection(session, leased);
} catch (error) {
return exits.badConnection(error);
}
return exits.success(results);
},
});