| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| |
| import app from "../../app"; |
| import FauxtonAPI from "../../core/api"; |
| import { deleteRequest } from "../../core/ajax"; |
| import PagingCollection from "../../../assets/js/plugins/cloudant.pagingcollection"; |
| |
| // defined here because this is contains the base resources used throughout the addon and outside, |
| // so it's the first code that gets run |
| var Documents = FauxtonAPI.addon(); |
| |
| |
| Documents.Doc = FauxtonAPI.Model.extend({ |
| idAttribute: "_id", |
| documentation: function () { |
| return FauxtonAPI.constants.DOC_URLS.GENERAL; |
| }, |
| |
| url: function (context) { |
| if (context === undefined) { |
| context = 'server'; |
| } |
| |
| // new without id make a POST to the DB and not a PUT on a DB |
| let id = this.safeID(); |
| if (!id) { |
| id = ''; |
| } |
| |
| const query = this.fetchConflicts ? '?conflicts=true' : ''; |
| return FauxtonAPI.urls('document', context, this.getDatabase().safeID(), id, query); |
| }, |
| |
| initialize: function (_attrs, options) { |
| if (this.collection && this.collection.database) { |
| this.database = this.collection.database; |
| } else if (options.database) { |
| this.database = options.database; |
| } |
| |
| if (options.fetchConflicts) { |
| this.fetchConflicts = true; |
| } |
| this.partitionKey = options.partitionKey; |
| }, |
| |
| // HACK: the doc needs to know about the database, but it may be |
| // set directly or indirectly in all docs |
| getDatabase: function () { |
| return this.database ? this.database : this.collection.database; |
| }, |
| |
| validate: function (attrs) { |
| if (this.id && this.id !== attrs._id && this.get('_rev')) { |
| return "Cannot change a documents id."; |
| } |
| }, |
| |
| docType: function () { |
| return app.utils.getDocTypeFromId(this.id); |
| }, |
| |
| // @deprecated, see isJSONDocBulkDeletable |
| isBulkDeletable: function () { |
| return !!this.id && !!this.get('_rev'); |
| }, |
| |
| isDeletable: function () { |
| return !!this.id; |
| }, |
| |
| isFromView: function () { |
| return !this.id; |
| }, |
| |
| isMangoDoc: function () { |
| if (!this.isDdoc()) return false; |
| if (this.get('language') === 'query') { |
| return true; |
| } |
| |
| if (this.get('doc') && this.get('doc').language === 'query') { |
| return true; |
| } |
| |
| return false; |
| }, |
| |
| isDdoc: function () { |
| return this.docType() === "design doc"; |
| }, |
| |
| setDDocPartitionedOption: function (isPartitioned) { |
| if (!this.isDdoc()) { |
| return false; |
| } |
| let options = this.get('options'); |
| if (!options) { |
| options = {}; |
| } |
| options.partitioned = isPartitioned; |
| this.set({ options }); |
| |
| return true; |
| }, |
| |
| setDdocView: function (view, map, reduce) { |
| if (!this.isDdoc()) { |
| return false; |
| } |
| |
| let views = this.get('views'); |
| // handles instances where the ddoc is empty (created manually) |
| if (!views) { |
| views = {}; |
| this.set({language: "javascript"}); |
| } |
| const tempView = views[view] || {}; |
| |
| if (reduce) { |
| tempView.reduce = reduce; |
| } else { |
| delete tempView.reduce; |
| } |
| tempView.map = map; |
| |
| views[view] = tempView; |
| this.set({views: views}); |
| |
| return true; |
| }, |
| |
| removeDdocView: function (viewName) { |
| if (!this.isDdoc()) return false; |
| var views = this.get('views'); |
| |
| delete views[viewName]; |
| this.set({views: views}); |
| }, |
| |
| dDocModel: function () { |
| if (!this.isDdoc()) return false; |
| var doc = this.get('doc'); |
| |
| if (doc) { |
| doc._rev = this.get('_rev'); |
| return new Documents.Doc(doc, {database: this.database}); |
| } |
| |
| return this; |
| }, |
| |
| safeID: function () { |
| return app.utils.getSafeIdForDoc(this.id); |
| }, |
| |
| destroy: function () { |
| const url = this.url() + "?rev=" + this.get('_rev'); |
| return deleteRequest(url).then(res => { |
| if (res.error) { |
| throw new Error(res.reason || res.error); |
| } |
| return res; |
| }); |
| }, |
| |
| parse: function (resp) { |
| if (resp.rev) { |
| resp._rev = resp.rev; |
| delete resp.rev; |
| } |
| if (resp.id) { |
| if (_.isUndefined(this.id)) { |
| resp._id = resp.id; |
| } |
| } |
| |
| if (resp.ok) { |
| delete resp.id; |
| delete resp.ok; |
| } |
| |
| return resp; |
| }, |
| |
| prettyJSON: function () { |
| var data = this.get("doc") ? this.get("doc") : this.attributes; |
| |
| return JSON.stringify(data, null, " "); |
| }, |
| |
| copy: function (copyId) { |
| const attrs = Object.assign({}, this.attributes, {_id: copyId}); |
| delete attrs._rev; |
| const clonedDoc = new this.constructor(attrs, { |
| database: this.database |
| }); |
| return clonedDoc.save(); |
| }, |
| |
| isNewDoc: function () { |
| return this.get('_rev') ? false : true; |
| } |
| }); |
| |
| |
| Documents.AllDocs = PagingCollection.extend({ |
| model: Documents.Doc, |
| documentation: function () { |
| return FauxtonAPI.constants.DOC_URLS.GENERAL; |
| }, |
| initialize: function (_models, options) { |
| this.viewMeta = options.viewMeta; |
| this.database = options.database; |
| this.params = _.clone(options.params); |
| |
| this.on("remove", this.decrementTotalRows, this); |
| this.perPageLimit = options.perPageLimit || 20; |
| |
| if (!this.params.limit) { |
| this.params.limit = this.perPageLimit; |
| } |
| }, |
| |
| isEditable: function () { |
| return true; |
| }, |
| |
| urlRef: function (context, params) { |
| var query = ""; |
| |
| if (params) { |
| if (!_.isEmpty(params)) { |
| query = "?" + app.utils.queryParams(params); |
| } else { |
| query = ''; |
| } |
| } else if (this.params) { |
| query = "?" + app.utils.queryParams(this.params); |
| } |
| if (_.isUndefined(context)) { |
| context = 'server'; |
| } |
| return FauxtonAPI.urls('allDocs', context, this.database.safeID(), query); |
| }, |
| |
| url: function () { |
| return this.urlRef.apply(this, arguments); |
| }, |
| |
| simple: function () { |
| var docs = this.map(function (item) { |
| return { |
| _id: item.id, |
| _rev: item.get('_rev'), |
| }; |
| }); |
| |
| return new Documents.AllDocs(docs, { |
| database: this.database, |
| params: this.params |
| }); |
| }, |
| |
| totalRows: function () { |
| return this.viewMeta.total_rows || "unknown"; |
| }, |
| |
| decrementTotalRows: function () { |
| if (this.viewMeta.total_rows) { |
| this.viewMeta.total_rows = this.viewMeta.total_rows - 1; |
| this.trigger('totalRows:decrement'); |
| } |
| }, |
| |
| updateSeq: function () { |
| if (!this.viewMeta) { |
| return false; |
| } |
| return this.viewMeta.update_seq || false; |
| }, |
| |
| parse: function (resp) { |
| var rows = resp.rows; |
| |
| // remove any query errors that may return without doc info |
| // important for when querying keys on all docs |
| var cleanRows = _.filter(rows, function (row) { |
| return row.value; |
| }); |
| |
| resp.rows = _.map(cleanRows, function (row) { |
| var res = { |
| _id: row.id, |
| _rev: row.value.rev, |
| value: row.value, |
| key: row.key |
| }; |
| |
| if (row.doc) { |
| res.doc = row.doc; |
| } |
| |
| return res; |
| }); |
| |
| return PagingCollection.prototype.parse.call(this, resp); |
| }, |
| |
| clone: function () { |
| return new this.constructor(this.models, { |
| database: this.database, |
| params: this.params, |
| paging: this.paging |
| }); |
| } |
| }); |
| |
| export default Documents; |