import stampit from 'stampit'; import {Meta, Model} from './base'; import Promise from 'bluebird'; import _ from 'lodash'; import QuerySet, {Filter} from '../querySet'; const DataObjectQuerySet = stampit().compose(QuerySet, Filter).methods({ /** * Orders DataObject by field. * @memberOf QuerySet * @instance * @param {String} field * @returns {QuerySet} * @example {@lang javascript} * DataObject.please().list({ instanceName: 'test-instace', className: 'test-class' }).orderBy('author').then(function(dataobjects) {}); * DataObject.please().list({ instanceName: 'test-instace', className: 'test-class' }).orderBy('-author').then(function(dataobjects) {}); */ orderBy(field) { this.query['order_by'] = field; return this; }, /** * Adds an array to an array field. * @memberOf QuerySet * @instance * @param {Object} properties lookup properties used for path resolving * @param {Object} field to add to. * @returns {QuerySet} * @example {@lang javascript} * DataObject.please().add({instanceName: 'my-instance', className: 'my-class', id: 1}, {array_field: [1,2]}) */ add(properties = {}, object = {}) { const payload = {}; payload[_.keys(object)[0]] = { _add: object[_.keys(object)[0]] }; this.properties = _.assign({}, this.properties, properties); this.payload = JSON.stringify(payload); this.method = 'PATCH'; this.endpoint = 'detail'; return this; }, /** * Adds an array to an array field without duplicate values. * @memberOf QuerySet * @instance * @param {Object} properties lookup properties used for path resolving * @param {Object} field to add to. * @returns {QuerySet} * @example {@lang javascript} * DataObject.please().add({instanceName: 'my-instance', className: 'my-class', id: 1}, {array_field: [1,2]}) */ addUnique(properties = {}, object = {}) { const payload = {}; payload[_.keys(object)[0]] = { _addunique: object[_.keys(object)[0]] }; this.properties = _.assign({}, this.properties, properties); this.payload = JSON.stringify(payload); this.method = 'PATCH'; this.endpoint = 'detail'; return this; }, /** * Filters DataObjects using _is. * @memberOf QuerySet * @instance * @param {String} field name * @param {Object} filters * @returns {QuerySet} * @example {@lang javascript} * DataObject.please().list({instanceName: 'my-instance', className: 'books'}).is('authors', { name: { _eq: 'Stephen King'}}) */ is(field, object = {}) { const query = {}; query[field] = { _is: object}; return this.filter(query); }, /** * Filters DataObjects using _contains. * @memberOf QuerySet * @instance * @param {String} field name * @param {Array} array of ids * @returns {QuerySet} * @example {@lang javascript} * DataObject.please().list({instanceName: 'my-instance', className: 'books'}).contains('authors', [1, 2, 3]) */ contains(field, array = []) { const query = {}; query[field] = { _contains: array}; return this.filter(query); }, /** * Subtracts an array from an array field. * @memberOf QuerySet * @instance * @param {Object} properties lookup properties used for path resolving * @param {Object} field to subtract from. * @returns {QuerySet} * @example {@lang javascript} * DataObject.please().remove({instanceName: 'my-instance', className: 'my-class', id: 1}, {array_field: [1,2]}) */ remove(properties = {}, object = {}) { const payload = {}; payload[_.keys(object)[0]] = { _remove: object[_.keys(object)[0]] }; this.properties = _.assign({}, this.properties, properties); this.payload = JSON.stringify(payload); this.method = 'PATCH'; this.endpoint = 'detail'; return this; }, /** * Increments single object based on provided arguments * @memberOf QuerySet * @instance * @param {Object} properties lookup properties used for path resolving * @param {Object} field to increment. * @returns {QuerySet} * @example {@lang javascript} * DataObject.please().increment({instanceName: 'my-instance', className: 'my-class', id: 1}, {views: 1}) */ increment(properties = {}, object = {}) { const payload = {}; payload[_.keys(object)[0]] = { _increment: object[_.keys(object)[0]] }; this.properties = _.assign({}, this.properties, properties); this.payload = JSON.stringify(payload); this.method = 'PATCH'; this.endpoint = 'detail'; return this; }, /** * Filters dataobjects by a geopoint field. * @memberOf QuerySet * @instance * @param {Object} coordinates * @returns {QuerySet} * @example {@lang javascript} * DataObject.please().list({ instanceName: 'test-instace', className: 'test-class' }).near({ geopoint_field_name: { latitude: POINT_LATITUDE, longitude: POINT_LONGITUDE }}).then(function(dataobjects) {}); * @example {@lang javascript} * DataObject.please().list({ instanceName: 'test-instace', className: 'test-class' }).near({ geopoint_field_name: { latitude: POINT_LATITUDE, longitude: POINT_LONGITUDE, distance_in_kilometers: DISTANCE_IN_KILOMETERS }}).then(function(dataobjects) {}); * @example {@lang javascript} * DataObject.please().list({ instanceName: 'test-instace', className: 'test-class' }).near({ geopoint_field_name: { latitude: POINT_LATITUDE, longitude: POINT_LONGITUDE, distance_in_miles: DISTANCE_IN_MILES }}).then(function(dataobjects) {}); */ near(object = {}) { const query = {}; query[_.keys(object)[0]] = { _near: object[_.keys(object)[0]]}; return this.filter(query); }, /** * Returns DataObject count. * @memberOf QuerySet * @instance * @returns {QuerySet} * @example {@lang javascript} * DataObject.please().list({ instanceName: 'test-instace', className: 'test-class' }).count().then(function(response) {}); */ count() { this.query['include_count'] = true; this.raw(); return this; } }); const DataObjectMeta = Meta({ name: 'dataobject', pluralName: 'dataobjects', endpoints: { 'detail': { 'methods': ['delete', 'patch', 'post', 'get'], 'path': '/v1.1/instances/{instanceName}/classes/{className}/objects/{id}/' }, 'list': { 'methods': ['post', 'get'], 'path': '/v1.1/instances/{instanceName}/classes/{className}/objects/' } } }); const DataobjectConstraints = { instanceName: { presence: true, length: { minimum: 5 } }, className: { presence: true, string: true }, owner: { numericality: true }, owner_permissions: { inclusion: ['none', 'read', 'write', 'full'] }, group: { numericality: true }, group_permissions: { inclusion: ['none', 'read', 'write', 'full'] }, other_permissions: { inclusion: ['none', 'read', 'write', 'full'] }, channel: { string: true }, channel_room: { string: true } }; /** * OO wrapper around instance data objects {@link http://docs.syncano.com/v4.0/docs/view-data-objects endpoint}. * This model is special because each instance will be **dynamically populated** with fields defined in related {@link Class} schema attribute. * @constructor * @type {DataObject} * @property {Number} id * @property {String} instanceName * @property {String} className * @property {Number} revision * @property {Number} [owner = null] * @property {String} [owner_permissions = null] * @property {Number} [group = null] * @property {String} [group_permissions = null] * @property {String} [other_permissions = null] * @property {String} [channel = null] * @property {String} [channel_room = null] * @property {String} [description = null] * @property {String} [links = {}] * @property {Date} [created_at = null] * @property {Date} [updated_at = null] */ const DataObject = stampit() .compose(Model) .setMeta(DataObjectMeta) .methods({ /** * Gets related objects via relation field name. * @memberOf QuerySet * @instance * @param {String} field name. * @returns {QuerySet} * @example {@lang javascript} * Object.getRelatedObjects('authors'); */ getRelatedObjects(field) { if(!_.has(this, field)) return Promise.reject(new Error(`The ${field} field does not exist.`)); if(!_.has(this[field], 'value') || !_.isArray(this[field].value)) return Promise.reject(new Error(`The ${field} is not a relation.`)); const {DataObject} = this.getConfig(); return DataObject.please().list({instanceName: this.instanceName, className: this[field].target }).filter({ id: { _in: this[field].value }}); }, /** * Increments single object field based on provided arguments. * @memberOf QuerySet * @instance * @param {String} field name. * @param {Number} value to increment the field by, * @returns {QuerySet} * @example {@lang javascript} * Object.increment('views', 1); */ increment(field, by) { if(!_.isNumber(this[field])) return Promise.reject(new Error(`The ${field} is not numeric.`)); if(!_.isNumber(by)) return Promise.reject(new Error('The provided value is not numeric.')); this[field] += _.add(this[field], by); return this.save(); }, /** * Adds an array to an array field. * @memberOf QuerySet * @instance * @param {String} field name. * @param {Array} array to add to the field. * @returns {QuerySet} * @example {@lang javascript} * Object.add('authors', [1,2,3]); */ add(field, array) { if((_.has(this[field], 'value') && !_.isArray(this[field].value)) || (!_.has(this[field], 'value') && !_.isArray(this[field]))) return Promise.reject(new Error(`The ${field} is not an array.`)); if(!_.isArray(array)) return Promise.reject(new Error('The provided value is not an array.')); this[field] = _.has(this[field], 'value') ? _.concat(this[field].value, array) : _.concat(this[field], array); return this.save(); }, /** * Adds an array to an array field without duplicate values. * @memberOf QuerySet * @instance * @param {String} field name. * @param {Array} array to add to the field. * @returns {QuerySet} * @example {@lang javascript} * Object.add('authors', [1,2,3]); */ addUnique(field, array) { if(!_.isArray(this[field])) return Promise.reject(new Error(`The ${field} is not an array.`)); if(!_.isArray(array)) return Promise.reject(new Error('The provided value is not an array.')); this[field] = _.union(this[field], array); return this.save(); }, /** * Subtracts an array from an array field. * @memberOf QuerySet * @instance * @param {String} field name. * @param {Array} array to subtract from the field. * @returns {QuerySet} * @example {@lang javascript} * Object.remove('authors', [1]); */ remove(field, array) { if((_.has(this[field], 'value') && !_.isArray(this[field].value)) || (!_.has(this[field], 'value') && !_.isArray(this[field]))) return Promise.reject(new Error(`The ${field} is not an array.`)); if(!_.isArray(array)) return Promise.reject(new Error('The provided value is not an array.')); this[field] = _.has(this[field], 'value') ? _.difference(this[field].value, array) : _.difference(this[field], array); return this.save(); } }) .setQuerySet(DataObjectQuerySet) .setConstraints(DataobjectConstraints); export default DataObject;