sails-arangojs
Version:
A sails-arangojs adapter for Sails / Waterline
186 lines (153 loc) • 6.47 kB
JavaScript
// ███████╗██╗ ██╗███╗ ███╗ █████╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
// ██╔════╝██║ ██║████╗ ████║ ██╔══██╗██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
// ███████╗██║ ██║██╔████╔██║ ███████║██║ ██║ ██║██║ ██║██╔██╗ ██║
// ╚════██║██║ ██║██║╚██╔╝██║ ██╔══██║██║ ██║ ██║██║ ██║██║╚██╗██║
// ███████║╚██████╔╝██║ ╚═╝ ██║ ██║ ██║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
// ╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
//
module.exports = require('machine').build({
friendlyName: 'FINDINBOUND',
description: 'Return the FINDINBOUND 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: 'Graph traversal in INBOUND direction',
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 findInbound(inputs, exits) {
const _ = require('@sailshq/lodash');
const Helpers = require('./private');
// Store the Query input for easier access
const { query } = inputs;
query.meta = query.meta || {};
// Find the model definition
const WLModel = inputs.models[query.using];
if (!WLModel) {
return exits.invalidDatastore();
}
if (WLModel.classType !== 'Vertex') {
return exits.badConnection(
new Error(
'\n\nThe this method can only be used in a model of type Vertex\n\n'
)
);
}
// Grab the pk column name (for use below)
let pkColumnName;
try {
pkColumnName = WLModel.attributes[WLModel.primaryKey].columnName;
} catch (e) {
return exits.error(e);
}
// ╔═╗╔═╗╔╗╔╦ ╦╔═╗╦═╗╔╦╗ ┌┬┐┌─┐ ┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┐┌┌┬┐
// ║ ║ ║║║║╚╗╔╝║╣ ╠╦╝ ║ │ │ │ └─┐ │ ├─┤ │ ├┤ │││├┤ │││ │
// ╚═╝╚═╝╝╚╝ ╚╝ ╚═╝╩╚═ ╩ ┴ └─┘ └─┘ ┴ ┴ ┴ ┴ └─┘┴ ┴└─┘┘└┘ ┴
// 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: 'findInbound',
criteria: query.criteria,
edgeCollections: query.edgeCollections,
});
} catch (e) {
return exits.error(e);
}
const { dbConnection, graph, graphName } = Helpers.connection.getConnection(
inputs.datastore,
query.meta
);
const where = statement.primarywhere || {};
if (!graph && !statement.edgeCollections) {
return exits.badConnection(
new Error('The edgeCollections for findInbound is null or undefined')
);
}
if (!where._id) {
return exits.badConnection(
new Error(
`Please provide the start vertex if ${pkColumnName} or _id for findInbound is null or undefined`
)
);
}
let result;
try {
// Construct sql statement
let sql = '';
sql = `FOR vertex, edge, path IN INBOUND '${where._id}' ${
graphName ? `GRAPH '${graphName}'` : statement.edgeCollections
}`;
if (statement.whereVertexClause || statement.whereEdgeClause) {
const arr = [statement.whereVertexClause, statement.whereEdgeClause]
.filter((a) => !!a)
.join(' AND ');
sql = `${sql} FILTER ${arr}`;
}
_.each(query.criteria, (value, key) => {
if (key === 'limit' && statement.limit) {
if (statement.skip) {
sql = `${sql} LIMIT ${statement.skip}, ${statement.limit}`;
} else {
sql = `${sql} LIMIT ${statement.limit}`;
}
}
if (key === 'sort' && statement.graphSort) {
sql = `${sql} SORT ${statement.graphSort}`;
}
});
sql = `${sql} RETURN {vertex, edge }`;
const cursor = await dbConnection.query(sql);
Helpers.connection.releaseConnection(dbConnection);
} catch (error) {
if (dbConnection) {
Helpers.connection.releaseConnection(dbConnection);
}
return exits.badConnection(error);
}
let records = result.map(({ vertex, edge }) => ({
vertex: vertex
? Helpers.query.processNativeRecord(vertex, WLModel, query.meta)
: null,
edge: edge
? Helpers.query.processNativeRecord(edge, WLModel, query.meta)
: null,
}));
records = records.filter((r) => r.vertex !== null && r.edge !== null);
return exits.success({ record: records });
},
});