type-arango
Version:
ArangoDB Foxx decorators and utilities for TypeScript
385 lines • 19.2 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Collection = exports.getCollectionForContainer = exports.findCollectionForContainer = void 0;
var joi_1 = require("../joi");
var __1 = require("..");
var index_1 = require("./index");
var utils_1 = require("../utils");
var _1 = require(".");
var METHODS_BODYLESS = ['get', 'delete'];
/**
* Creates a new Collection for a decorated class
*/
function createCollectionFromContainer(someClass) {
var c = new Collection(someClass);
__1.collections.push(c);
return c;
}
/**
* Finds a collection for a decorated class
*/
function findCollectionForContainer(someClass) {
return __1.collections.find(function (c) { return someClass === c.Class || someClass.prototype instanceof c.Class; });
}
exports.findCollectionForContainer = findCollectionForContainer;
/**
* Returns the respective collection instance for a decorated class
*/
function getCollectionForContainer(someClass) {
var col = findCollectionForContainer(someClass);
if (col)
return col;
return createCollectionFromContainer(someClass);
}
exports.getCollectionForContainer = getCollectionForContainer;
/**
* Collections represent tables in ArangoDB
*/
var Collection = /** @class */ (function () {
/**
* Creates a new collection instance
*/
function Collection(Class) {
this.Class = Class;
this.completed = false;
this.schema = {};
this.routes = [];
this.roles = {
creators: [],
readers: [],
updaters: [],
deleters: []
};
this.decorator = {};
this.name = Collection.toName(Class.name);
this.db = __1.isActive ? utils_1.db._collection(this.name) : null;
}
/**
* Returns a valid collection name
*/
Collection.toName = function (input) {
return __1.config.prefixCollectionName ? module.context.collectionName(input) : input;
};
Object.defineProperty(Collection.prototype, "allowUserKeys", {
/**
* Whether users can provide custom document keys on creation
*/
get: function () {
var keyOptions = this.opt && this.opt.keyOptions;
return !keyOptions ? false : (keyOptions && keyOptions.allowUserKeys === true && keyOptions.type !== 'autoincrement');
},
enumerable: false,
configurable: true
});
Object.defineProperty(Collection.prototype, "route", {
get: function () {
var name = this.name;
name = name.charAt(0).toLowerCase() + name.substr(1);
if (__1.config.dasherizeRoutes)
name = name.replace(/[A-Z]/g, function (m) { return '-' + m.toLowerCase(); });
return name;
},
enumerable: false,
configurable: true
});
Collection.prototype.addRoles = function (key, roles, onlyWhenEmpty) {
if (onlyWhenEmpty === void 0) { onlyWhenEmpty = true; }
if (onlyWhenEmpty && this.roles[key].length)
return;
this.roles[key] = utils_1.concatUnique(this.roles[key], roles);
if (this.doc)
this.doc.roles = utils_1.concatUnique(this.doc.roles, roles);
// else console.log('CANNOT ADD ROLES, DOCUMENT NOT READY')
};
Collection.prototype.decorate = function (decorator, data) {
this.decorator[decorator] = __spreadArrays((this.decorator[decorator] || []), [__assign(__assign({}, data), { decorator: decorator })]);
};
Object.defineProperty(Collection.prototype, "routeAuths", {
get: function () {
return (this.decorator['Route.auth'] || []).map(function (d) { return d.authorizeFn; }).reverse();
},
enumerable: false,
configurable: true
});
Object.defineProperty(Collection.prototype, "routeRoles", {
get: function () {
return (this.decorator['Route.roles'] || []).map(function (d) { return d.rolesFn; }).reverse();
},
enumerable: false,
configurable: true
});
Collection.prototype.query = function (q) {
if (typeof q === 'string') {
return utils_1.db._query(q);
}
if (!q.keep) {
q.unset = [];
if (__1.config.stripDocumentId)
q.unset.push('_id');
if (__1.config.stripDocumentRev)
q.unset.push('_rev');
if (__1.config.stripDocumentKey)
q.unset.push('_key');
}
return utils_1.db._query(utils_1.queryBuilder(this.name, q));
};
Collection.prototype.finalize = function () {
var _a = this.decorator, Collection = _a.Collection, Route = _a.Route, Task = _a.Task, Function = _a.Function;
var _b = Collection[0], ofDocument = _b.ofDocument, _c = _b.options, options = _c === void 0 ? {} : _c;
this.opt = options;
if (options.name) {
this.name = options.name;
}
var doc = this.doc = index_1.getDocumentForContainer(utils_1.argumentResolve(ofDocument));
doc.col = this;
if (options.creators)
this.addRoles('creators', options.creators, false);
if (options.readers)
this.addRoles('readers', options.readers, false);
if (options.updaters)
this.addRoles('updaters', options.updaters, false);
if (options.deleters)
this.addRoles('deleters', options.deleters, false);
if (__1.isActive) {
// create collection
if (!this.db) {
__1.logger.info('Creating ArangoDB Collection "%s"', this.name);
var of = options.of, creators = options.creators, readers = options.readers, updaters = options.updaters, deleters = options.deleters, roles = options.roles, auth = options.auth, routes = options.routes, opt = __rest(options, ["of", "creators", "readers", "updaters", "deleters", "roles", "auth", "routes"]);
this.db = doc.isEdge
? utils_1.db._createEdgeCollection(this.name, opt || {})
: utils_1.db._createDocumentCollection(this.name, opt || {});
}
// create indices
for (var _i = 0, _d = doc.indexes; _i < _d.length; _i++) {
var options_1 = _d[_i].options;
this.db.ensureIndex(options_1);
}
var task = require('@arangodb/tasks');
var tasks = task.get();
// setup Tasks
if (Task) {
var _loop_1 = function (prototype, attribute, period, offset, id, name_1, params) {
var opt = {
id: id,
offset: offset,
name: name_1,
params: params
};
eval('opt.command = function ' + prototype[attribute].toString());
if (period > 0)
opt.period = period;
if (tasks.find(function (t) { return t.id === id; })) {
__1.logger.debug('Unregister previously active task', id);
task.unregister(id);
}
__1.logger.debug('Register task', opt);
try {
task.register(opt);
}
catch (e) {
__1.logger.error('Could not register task:', e.message);
}
};
for (var _e = 0, Task_1 = Task; _e < Task_1.length; _e++) {
var _f = Task_1[_e], prototype = _f.prototype, attribute = _f.attribute, period = _f.period, offset = _f.offset, id = _f.id, name_1 = _f.name, params = _f.params;
_loop_1(prototype, attribute, period, offset, id, name_1, params);
}
}
var aqlfunction = require('@arangodb/aql/functions');
// unregister old
if (__1.config.unregisterAQLFunctionEntityGroup) {
__1.logger.debug('Unregister AQLFunction-group "' + this.name + '::*"');
aqlfunction.unregisterGroup(this.name);
}
// setup AQLFunctions
if (Function)
for (var _g = 0, Function_1 = Function; _g < Function_1.length; _g++) {
var _h = Function_1[_g], prototype = _h.prototype, attribute = _h.attribute, name_2 = _h.name, isDeterministic = _h.isDeterministic;
__1.logger.debug('Register AQLFunction "' + name_2 + '"');
var f = null;
eval('f = function ' + prototype[attribute].toString());
aqlfunction.register(name_2, f, isDeterministic);
}
}
if (Route)
for (var _j = 0, Route_1 = Route; _j < Route_1.length; _j++) {
var _k = Route_1[_j], prototype = _k.prototype, attribute = _k.attribute, method = _k.method, pathOrRolesOrOptions = _k.pathOrRolesOrOptions, schemaOrRolesOrSummary = _k.schemaOrRolesOrSummary, rolesOrSchemaOrSummary = _k.rolesOrSchemaOrSummary, summaryOrSchemaOrRoles = _k.summaryOrSchemaOrRoles, options_2 = _k.options;
var schema = void 0;
var a = utils_1.argumentResolve(pathOrRolesOrOptions, function (inp) { return utils_1.enjoi(inp, 'required'); }, joi_1.Joi);
var opt = Object.assign({
queryParams: []
}, typeof a === 'string'
? { path: a }
: Array.isArray(a)
? { roles: a }
: typeof a === 'object' && a && !a.method
? { schema: a.isJoi ? a : utils_1.enjoi(a) }
: a || {});
// allow options for schema param
if (utils_1.isObject(schemaOrRolesOrSummary)) {
opt = Object.assign(schemaOrRolesOrSummary, opt);
}
else {
schema = utils_1.argumentResolve(schemaOrRolesOrSummary, function (inp) { return utils_1.enjoi(inp, 'required'); }, joi_1.Joi);
if (schema instanceof Array) {
opt.roles = schema;
}
else if (typeof schema === 'string') {
opt.summary = schema;
}
else if (typeof schema === 'object' && schema) {
}
else
schema = null;
}
// allow options for roles param
if (utils_1.isObject(rolesOrSchemaOrSummary)) {
opt = Object.assign(rolesOrSchemaOrSummary, opt);
}
else {
var roles = utils_1.argumentResolve(rolesOrSchemaOrSummary, function (inp) { return utils_1.enjoi(inp, 'required'); }, joi_1.Joi);
if (roles instanceof Array) {
opt.roles = roles;
}
else if (typeof roles === 'string') {
opt.summary = roles;
}
else if (typeof roles === 'object' && roles) {
schema = roles;
}
}
// allow options for summary param
if (utils_1.isObject(summaryOrSchemaOrRoles)) {
opt = Object.assign(summaryOrSchemaOrRoles, opt);
}
else {
var summary = utils_1.argumentResolve(summaryOrSchemaOrRoles, function (inp) { return utils_1.enjoi(inp, 'required'); }, joi_1.Joi);
if (summary instanceof Array) {
opt.roles = summary;
}
else if (typeof summary === 'string') {
opt.summary = summary;
}
else if (typeof summary === 'object' && summary) {
schema = summary;
}
}
if (options_2)
opt = Object.assign(options_2, opt);
if (!schema && opt.schema) {
schema = utils_1.argumentResolve(opt.schema, function (inp) { return utils_1.enjoi(inp, 'required'); }, joi_1.Joi);
}
if (method === 'LIST') {
method = 'get';
opt.action = 'list';
}
else
method = method.toLowerCase();
opt = index_1.Route.parsePath(opt, this.route);
if (schema) {
if (schema.isJoi) { }
else {
// support anonymous object syntax (joi => ({my:'object'}))
schema = utils_1.enjoi(schema);
}
// treat schema as queryParam or pathParam
if (schema._type === 'object') {
// allow optional request body but default to required()
schema = schema._flags.presence === 'optional' ? schema : schema.required();
// init params
opt.pathParams = opt.pathParams || [];
opt.queryParams = opt.queryParams || [];
var i = 0;
var _loop_2 = function (attr) {
// attributes with a default value are optional
if (attr.schema._flags.default) {
attr.schema._flags.presence = 'optional';
}
// check schema attr in pathParams
if (opt.pathParams.find(function (p) { return p[0] === attr.key; })) {
// override pathParam schema with route schema in order to specify more details
opt.pathParams = opt.pathParams.map(function (p) { return p[0] === attr.key ? [p[0], attr.schema, p[2]] : p; });
// remove attr from schema
schema._inner.children = schema._inner.children.filter(function (a) { return a.key !== attr.key; });
return "continue";
}
else if (opt.queryParams.find(function (q) { return q[0] === attr.key; })) {
// override queryParam schema with route schema in order to specify more details
opt.queryParams = opt.queryParams.map(function (p) { return p[0] === attr.key ? [p[0], attr.schema, p[2]] : p; });
// remove attr from schema
schema._inner.children = schema._inner.children.filter(function (a) { return a.key !== attr.key; });
}
else {
i++;
}
if (METHODS_BODYLESS.includes(method)) {
var isRequired = attr.schema._flags.presence === 'required';
var operators = attr.schema._flags.operators;
opt.queryParams.push([
attr.key,
attr.schema,
index_1.Scalar.iconRequired(isRequired) + ' ' + (attr.schema._description ? '**' + attr.schema._description + '**' : (isRequired
? '**Required'
: '**Optional') + (" query parameter** " + (operators ? 'with operator' : '') + " \u2002`[ " + attr.key + ": " + (operators ? '[operator, value]' : attr.schema._type) + " ]`"))
+ (operators ? "\n \u3000\u2002`Operators: " + operators.join(', ') + "`" : '')
+ ("\n \u3000\u2002`Example: ?" + attr.key + "=" + (operators ? utils_1.arraySample(operators) + __1.config.paramOperatorSeparator : '') + (attr.schema._examples[0] || attr.schema._type) + "`")
]);
}
};
// loop schema keys
for (var _l = 0, _m = schema._inner.children; _l < _m.length; _l++) {
var attr = _m[_l];
_loop_2(attr);
}
if (!METHODS_BODYLESS.includes(method) && i) {
opt.body = [schema];
}
// if(i && !ROUTEmethod !== 'get' && method !== 'delete'){
// opt.body = [schema]
// }
}
}
// is MethodDecorator, replace callback with method
if (attribute) {
opt.handler = prototype[attribute];
opt.handlerName = attribute;
}
_1.getRouteForCollection(method, opt, this);
}
this.completed = true;
// this.complete()
__1.logger.info('Completed collection "%s"', this.name);
};
return Collection;
}());
exports.Collection = Collection;
//# sourceMappingURL=Collection.model.js.map