Major update to linked record backend, now handling adding info about record links to all responses.
This commit is contained in:
parent
c425ec4d2f
commit
dee763a952
|
@ -1,6 +1,7 @@
|
|||
const CouchDB = require("../../db")
|
||||
const client = require("../../db/clientDb")
|
||||
const newid = require("../../db/newid")
|
||||
const { createLinkView } = require("../../db/linkedRecords")
|
||||
|
||||
exports.create = async function(ctx) {
|
||||
const instanceName = ctx.request.body.name
|
||||
|
@ -33,22 +34,6 @@ exports.create = async function(ctx) {
|
|||
emit([doc.type], doc._id)
|
||||
}.toString(),
|
||||
},
|
||||
by_link: {
|
||||
map: function(doc) {
|
||||
if (doc.type === "link") {
|
||||
let doc1 = doc.doc1
|
||||
let doc2 = doc.doc2
|
||||
emit([doc1.modelId, 1, doc1.fieldName, doc1.recordId], {
|
||||
_id: doc2.recordId,
|
||||
})
|
||||
emit([doc2.modelId, 1, doc2.fieldName, doc2.recordId], {
|
||||
_id: doc1.recordId,
|
||||
})
|
||||
emit([doc1.modelId, 2, doc1.recordId], { _id: doc2.recordId })
|
||||
emit([doc2.modelId, 2, doc2.recordId], { _id: doc1.recordId })
|
||||
}
|
||||
}.toString(),
|
||||
},
|
||||
by_automation_trigger: {
|
||||
map: function(doc) {
|
||||
if (doc.type === "automation") {
|
||||
|
@ -61,6 +46,8 @@ exports.create = async function(ctx) {
|
|||
},
|
||||
},
|
||||
})
|
||||
// add view for linked records
|
||||
await createLinkView(instanceId)
|
||||
|
||||
// Add the new instance under the app clientDB
|
||||
const clientDb = new CouchDB(client.name(clientId))
|
||||
|
|
|
@ -65,13 +65,13 @@ exports.save = async function(ctx) {
|
|||
}`,
|
||||
},
|
||||
}
|
||||
await db.put(designDoc)
|
||||
// update linked records
|
||||
await updateLinksForModel({
|
||||
instanceId,
|
||||
eventType: EventType.MODEL_SAVE,
|
||||
model: modelToSave,
|
||||
})
|
||||
await db.put(designDoc)
|
||||
|
||||
// syntactic sugar for event emission
|
||||
modelToSave.modelId = modelToSave._id
|
||||
|
@ -98,16 +98,16 @@ exports.destroy = async function(ctx) {
|
|||
records.rows.map(record => ({ _id: record.id, _deleted: true }))
|
||||
)
|
||||
|
||||
// delete the "all" view
|
||||
const designDoc = await db.get("_design/database")
|
||||
delete designDoc.views[modelViewId]
|
||||
await db.put(designDoc)
|
||||
// update linked records
|
||||
await updateLinksForModel({
|
||||
instanceId,
|
||||
eventType: EventType.MODEL_DELETE,
|
||||
model: modelToDelete,
|
||||
})
|
||||
// delete the "all" view
|
||||
const designDoc = await db.get("_design/database")
|
||||
delete designDoc.views[modelViewId]
|
||||
await db.put(designDoc)
|
||||
|
||||
// syntactic sugar for event emission
|
||||
modelToDelete.modelId = modelToDelete._id
|
||||
|
|
|
@ -5,6 +5,8 @@ const {
|
|||
EventType,
|
||||
updateLinksForRecord,
|
||||
getLinkDocuments,
|
||||
attachLinkInfoToRecord,
|
||||
attachLinkInfoToRecords,
|
||||
} = require("../../db/linkedRecords")
|
||||
|
||||
validateJs.extend(validateJs.validators.datetime, {
|
||||
|
@ -20,11 +22,11 @@ validateJs.extend(validateJs.validators.datetime, {
|
|||
exports.patch = async function(ctx) {
|
||||
const instanceId = ctx.user.instanceId
|
||||
const db = new CouchDB(instanceId)
|
||||
const record = await db.get(ctx.params.id)
|
||||
const model = await db.get(record.modelId)
|
||||
let record = await db.get(ctx.params.id)
|
||||
const patchfields = ctx.request.body
|
||||
|
||||
for (let key in patchfields) {
|
||||
for (let key of Object.keys(patchfields)) {
|
||||
if (!model.schema[key]) continue
|
||||
record[key] = patchfields[key]
|
||||
}
|
||||
|
@ -43,16 +45,17 @@ exports.patch = async function(ctx) {
|
|||
return
|
||||
}
|
||||
|
||||
const response = await db.put(record)
|
||||
record._rev = response.rev
|
||||
record.type = "record"
|
||||
await updateLinksForRecord({
|
||||
// returned record is cleaned and prepared for writing to DB
|
||||
record = await updateLinksForRecord({
|
||||
instanceId,
|
||||
eventType: EventType.RECORD_UPDATE,
|
||||
record,
|
||||
modelId: record.modelId,
|
||||
model,
|
||||
})
|
||||
const response = await db.put(record)
|
||||
record._rev = response.rev
|
||||
record.type = "record"
|
||||
|
||||
ctx.eventEmitter &&
|
||||
ctx.eventEmitter.emitRecord(`record:update`, instanceId, record, model)
|
||||
|
@ -64,7 +67,7 @@ exports.patch = async function(ctx) {
|
|||
exports.save = async function(ctx) {
|
||||
const instanceId = ctx.user.instanceId
|
||||
const db = new CouchDB(instanceId)
|
||||
const record = ctx.request.body
|
||||
let record = ctx.request.body
|
||||
record.modelId = ctx.params.modelId
|
||||
|
||||
if (!record._rev && !record._id) {
|
||||
|
@ -99,16 +102,16 @@ exports.save = async function(ctx) {
|
|||
return
|
||||
}
|
||||
|
||||
record.type = "record"
|
||||
const response = await db.post(record)
|
||||
record._rev = response.rev
|
||||
await updateLinksForRecord({
|
||||
record = await updateLinksForRecord({
|
||||
instanceId,
|
||||
eventType: EventType.RECORD_SAVE,
|
||||
record,
|
||||
modelId: record.modelId,
|
||||
model,
|
||||
})
|
||||
record.type = "record"
|
||||
const response = await db.post(record)
|
||||
record._rev = response.rev
|
||||
|
||||
ctx.eventEmitter &&
|
||||
ctx.eventEmitter.emitRecord(`record:save`, instanceId, record, model)
|
||||
|
@ -118,7 +121,8 @@ exports.save = async function(ctx) {
|
|||
}
|
||||
|
||||
exports.fetchView = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.instanceId)
|
||||
const instanceId = ctx.user.instanceId
|
||||
const db = new CouchDB(instanceId)
|
||||
const { stats, group, field } = ctx.query
|
||||
const response = await db.query(`database/${ctx.params.viewName}`, {
|
||||
include_docs: !stats,
|
||||
|
@ -136,52 +140,61 @@ exports.fetchView = async function(ctx) {
|
|||
response.rows = response.rows.map(row => row.doc)
|
||||
}
|
||||
|
||||
ctx.body = response.rows
|
||||
ctx.body = await attachLinkInfoToRecords(instanceId, response.rows)
|
||||
}
|
||||
|
||||
exports.fetchModelRecords = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.instanceId)
|
||||
const instanceId = ctx.user.instanceId
|
||||
const db = new CouchDB(instanceId)
|
||||
const response = await db.query(`database/all_${ctx.params.modelId}`, {
|
||||
include_docs: true,
|
||||
})
|
||||
ctx.body = response.rows.map(row => row.doc)
|
||||
ctx.body = await attachLinkInfoToRecords(
|
||||
instanceId,
|
||||
response.rows.map(row => row.doc)
|
||||
)
|
||||
}
|
||||
|
||||
exports.search = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.instanceId)
|
||||
const instanceId = ctx.user.instanceId
|
||||
const db = new CouchDB(instanceId)
|
||||
const response = await db.allDocs({
|
||||
include_docs: true,
|
||||
...ctx.request.body,
|
||||
})
|
||||
ctx.body = response.rows.map(row => row.doc)
|
||||
ctx.body = await attachLinkInfoToRecords(
|
||||
instanceId,
|
||||
response.rows.map(row => row.doc)
|
||||
)
|
||||
}
|
||||
|
||||
exports.find = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.instanceId)
|
||||
const instanceId = ctx.user.instanceId
|
||||
const db = new CouchDB(instanceId)
|
||||
const record = await db.get(ctx.params.recordId)
|
||||
if (record.modelId !== ctx.params.modelId) {
|
||||
ctx.throw(400, "Supplied modelId does not match the records modelId")
|
||||
return
|
||||
}
|
||||
ctx.body = record
|
||||
ctx.body = await attachLinkInfoToRecord(instanceId, record)
|
||||
}
|
||||
|
||||
exports.destroy = async function(ctx) {
|
||||
const instanceId = ctx.user.instanceId
|
||||
const db = new CouchDB()
|
||||
const db = new CouchDB(instanceId)
|
||||
const record = await db.get(ctx.params.recordId)
|
||||
if (record.modelId !== ctx.params.modelId) {
|
||||
ctx.throw(400, "Supplied modelId doesn't match the record's modelId")
|
||||
return
|
||||
}
|
||||
ctx.body = await db.remove(ctx.params.recordId, ctx.params.revId)
|
||||
ctx.status = 200
|
||||
await updateLinksForRecord({
|
||||
instanceId,
|
||||
eventType: EventType.RECORD_DELETE,
|
||||
record,
|
||||
modelId: record.modelId,
|
||||
})
|
||||
ctx.body = await db.remove(ctx.params.recordId, ctx.params.revId)
|
||||
ctx.status = 200
|
||||
|
||||
// for automations include the record that was deleted
|
||||
ctx.record = record
|
||||
|
@ -217,6 +230,7 @@ async function validate({ instanceId, modelId, record, model }) {
|
|||
|
||||
exports.fetchLinkedRecords = async function(ctx) {
|
||||
const instanceId = ctx.user.instanceId
|
||||
const db = new CouchDB(instanceId)
|
||||
const modelId = ctx.params.modelId
|
||||
const fieldName = ctx.params.fieldName
|
||||
const recordId = ctx.params.recordId
|
||||
|
@ -229,13 +243,18 @@ exports.fetchLinkedRecords = async function(ctx) {
|
|||
}
|
||||
return
|
||||
}
|
||||
let records = await getLinkDocuments({
|
||||
// get the link docs
|
||||
const linkDocIds = await getLinkDocuments({
|
||||
instanceId,
|
||||
modelId,
|
||||
fieldName,
|
||||
recordId,
|
||||
includeDoc: true,
|
||||
})
|
||||
// now get the docs from the all docs index
|
||||
const response = await db.query(`database/_all_docs`, {
|
||||
include_docs: true,
|
||||
keys: linkDocIds,
|
||||
})
|
||||
ctx.body = response.rows.map(row => row.doc)
|
||||
ctx.status = 200
|
||||
ctx.body = { records: records }
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ class LinkController {
|
|||
*/
|
||||
async doesModelHaveLinkedFields() {
|
||||
const model = await this.model()
|
||||
for (const fieldName of Object.keys(model.schema)) {
|
||||
for (let fieldName of Object.keys(model.schema)) {
|
||||
const { type } = model.schema[fieldName]
|
||||
if (type === "link") {
|
||||
return true
|
||||
|
@ -79,12 +79,13 @@ class LinkController {
|
|||
/**
|
||||
* Utility function for main getLinkDocuments function - refer to it for functionality.
|
||||
*/
|
||||
getLinkDocs(fieldName, recordId) {
|
||||
getLinkDocs(includeDocs, fieldName = null, recordId = null) {
|
||||
return linkedRecords.getLinkDocuments({
|
||||
instanceId: this._instanceId,
|
||||
modelId: this._modelId,
|
||||
fieldName,
|
||||
recordId,
|
||||
includeDocs,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -93,22 +94,23 @@ class LinkController {
|
|||
/**
|
||||
* When a record is saved this will carry out the necessary operations to make sure
|
||||
* the link has been created/updated.
|
||||
* @returns {Promise<null>} The operation has been completed and the link documents should now
|
||||
* be accurate.
|
||||
* @returns {Promise<object>} returns the record that has been cleaned and prepared to be written to the DB - links
|
||||
* have also been created.
|
||||
*/
|
||||
async recordSaved() {
|
||||
const model = await this.model()
|
||||
const record = this._record
|
||||
let operations = []
|
||||
const operations = []
|
||||
for (let fieldName of Object.keys(model.schema)) {
|
||||
const field = model.schema[fieldName]
|
||||
if (field.type === "link") {
|
||||
// get link docs to compare against
|
||||
let linkDocs = await this.getLinkDocs(fieldName, record._id)
|
||||
let currentLinkIds = linkDocs.map(doc => doc._id)
|
||||
let toLinkIds = record[fieldName]
|
||||
const linkDocIds = await this.getLinkDocs(false, fieldName, record._id)
|
||||
// get the links this record wants to make
|
||||
const toLinkIds = record[fieldName]
|
||||
// iterate through them and find any which don't exist, create them
|
||||
for (let linkId of toLinkIds) {
|
||||
if (currentLinkIds.indexOf(linkId) === -1) {
|
||||
if (linkDocIds.indexOf(linkId) === -1) {
|
||||
operations.push(
|
||||
new LinkDocument(
|
||||
model._id,
|
||||
|
@ -120,96 +122,104 @@ class LinkController {
|
|||
)
|
||||
)
|
||||
}
|
||||
const toDeleteIds = currentLinkIds.filter(
|
||||
// work out any that need to be deleted
|
||||
const toDeleteIds = linkDocIds.filter(
|
||||
id => toLinkIds.indexOf(id) === -1
|
||||
)
|
||||
operations.concat(
|
||||
toDeleteIds.map(id => ({ _id: id, _deleted: true }))
|
||||
)
|
||||
}
|
||||
// remove the field from the record, shouldn't store it
|
||||
delete record[fieldName]
|
||||
}
|
||||
}
|
||||
await this._db.bulkDocs(operations)
|
||||
return record
|
||||
}
|
||||
|
||||
/**
|
||||
* When a record is deleted this will carry out the necessary operations to make sure
|
||||
* any links that existed have been removed.
|
||||
* @returns {Promise<null>} The operation has been completed and the link documents should now
|
||||
* be accurate.
|
||||
* @returns {Promise<object>} The operation has been completed and the link documents should now
|
||||
* be accurate. This also returns the record that was deleted.
|
||||
*/
|
||||
async recordDeleted() {
|
||||
const record = this._record
|
||||
// get link docs to compare against
|
||||
let linkDocs = await this.getLinkDocs(null, record._id)
|
||||
// need to get the full link docs to be be able to delete it
|
||||
const linkDocs = await this.getLinkDocs(true, null, record._id)
|
||||
if (linkDocs.length === 0) {
|
||||
return null
|
||||
}
|
||||
let toDelete = linkDocs.map(doc => {
|
||||
const toDelete = linkDocs.map(doc => {
|
||||
return {
|
||||
...doc,
|
||||
_deleted: true,
|
||||
}
|
||||
})
|
||||
await this._db.bulkDocs(toDelete)
|
||||
return record
|
||||
}
|
||||
|
||||
/**
|
||||
* When a model is saved this will carry out the necessary operations to make sure
|
||||
* any linked models are notified and updated correctly.
|
||||
* @returns {Promise<null>} The operation has been completed and the link documents should now
|
||||
* be accurate.
|
||||
* @returns {Promise<object>} The operation has been completed and the link documents should now
|
||||
* be accurate. Also returns the model that was operated on.
|
||||
*/
|
||||
async modelSaved() {
|
||||
const model = await this.model()
|
||||
const schema = model.schema
|
||||
for (const fieldName of Object.keys(schema)) {
|
||||
for (let fieldName of Object.keys(schema)) {
|
||||
const field = schema[fieldName]
|
||||
if (field.type === "link") {
|
||||
// create the link field in the other model
|
||||
const linkedModel = await this._db.get(field.modelId)
|
||||
linkedModel.schema[field.fieldName] = {
|
||||
name: model.name,
|
||||
name: field.fieldName,
|
||||
type: "link",
|
||||
// these are the props of the table that initiated the link
|
||||
modelId: model._id,
|
||||
fieldName: fieldName,
|
||||
}
|
||||
await this._db.put(linkedModel)
|
||||
}
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
/**
|
||||
* When a model is deleted this will carry out the necessary operations to make sure
|
||||
* any linked models have the joining column correctly removed as well as removing any
|
||||
* now stale linking documents.
|
||||
* @returns {Promise<null>} The operation has been completed and the link documents should now
|
||||
* be accurate.
|
||||
* @returns {Promise<object>} The operation has been completed and the link documents should now
|
||||
* be accurate. Also returns the model that was operated on.
|
||||
*/
|
||||
async modelDeleted() {
|
||||
const model = await this.model()
|
||||
const schema = model.schema
|
||||
for (const fieldName of Object.keys(schema)) {
|
||||
let field = schema[fieldName]
|
||||
for (let fieldName of Object.keys(schema)) {
|
||||
const field = schema[fieldName]
|
||||
if (field.type === "link") {
|
||||
const linkedModel = await this._db.get(field.modelId)
|
||||
delete linkedModel.schema[model.name]
|
||||
await this._db.put(linkedModel)
|
||||
}
|
||||
}
|
||||
// get link docs to compare against
|
||||
let linkDocs = await this.getLinkDocs()
|
||||
// need to get the full link docs to delete them
|
||||
const linkDocs = await this.getLinkDocs(true)
|
||||
if (linkDocs.length === 0) {
|
||||
return null
|
||||
}
|
||||
// get link docs for this model and configure for deletion
|
||||
let toDelete = linkDocs.map(doc => {
|
||||
const toDelete = linkDocs.map(doc => {
|
||||
return {
|
||||
...doc,
|
||||
_deleted: true,
|
||||
}
|
||||
})
|
||||
await this._db.bulkDocs(toDelete)
|
||||
return model
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ const EventType = {
|
|||
MODEL_DELETE: "model:delete",
|
||||
}
|
||||
|
||||
module.exports.EventType = EventType
|
||||
exports.EventType = EventType
|
||||
|
||||
/**
|
||||
* Update link documents for a model - this is to be called by the model controller when a model is being changed.
|
||||
|
@ -22,16 +22,13 @@ module.exports.EventType = EventType
|
|||
* future quite easily (all updates go through one function).
|
||||
* @param {string} instanceId The ID of the instance in which the model change is occurring.
|
||||
* @param {object} model The model which is changing, whether it is being deleted, created or updated.
|
||||
* @returns {Promise<null>} When the update is complete this will respond successfully.
|
||||
* @returns {Promise<object>} When the update is complete this will respond successfully. Returns the model that was
|
||||
* operated upon.
|
||||
*/
|
||||
module.exports.updateLinksForModel = async ({
|
||||
eventType,
|
||||
instanceId,
|
||||
model,
|
||||
}) => {
|
||||
exports.updateLinksForModel = async ({ eventType, instanceId, model }) => {
|
||||
// can't operate without these properties
|
||||
if (instanceId == null || model == null) {
|
||||
return null
|
||||
return model
|
||||
}
|
||||
let linkController = new LinkController({
|
||||
instanceId,
|
||||
|
@ -39,15 +36,13 @@ module.exports.updateLinksForModel = async ({
|
|||
model,
|
||||
})
|
||||
if (!(await linkController.doesModelHaveLinkedFields())) {
|
||||
return null
|
||||
return model
|
||||
}
|
||||
switch (eventType) {
|
||||
case EventType.MODEL_SAVE:
|
||||
await linkController.modelSaved()
|
||||
break
|
||||
return await linkController.modelSaved()
|
||||
case EventType.MODEL_DELETE:
|
||||
await linkController.modelDeleted()
|
||||
break
|
||||
return await linkController.modelDeleted()
|
||||
default:
|
||||
throw "Type of event is not known, linked record handler requires update."
|
||||
}
|
||||
|
@ -61,9 +56,10 @@ module.exports.updateLinksForModel = async ({
|
|||
* @param {object} record The record which is changing, e.g. created, updated or deleted.
|
||||
* @param {string} modelId The ID of the of the model which is being updated.
|
||||
* @param {object|null} model If the model has already been retrieved this can be used to reduce database gets.
|
||||
* @returns {Promise<null>} When the update is complete this will respond successfully.
|
||||
* @returns {Promise<object>} When the update is complete this will respond successfully. Returns the record that was
|
||||
* operated upon, cleaned up and prepared for writing to DB.
|
||||
*/
|
||||
module.exports.updateLinksForRecord = async ({
|
||||
exports.updateLinksForRecord = async ({
|
||||
eventType,
|
||||
instanceId,
|
||||
record,
|
||||
|
@ -71,8 +67,8 @@ module.exports.updateLinksForRecord = async ({
|
|||
model,
|
||||
}) => {
|
||||
// can't operate without these properties
|
||||
if (instanceId == null || modelId == null) {
|
||||
return null
|
||||
if (instanceId == null || modelId == null || record == null) {
|
||||
return record
|
||||
}
|
||||
let linkController = new LinkController({
|
||||
instanceId,
|
||||
|
@ -81,7 +77,7 @@ module.exports.updateLinksForRecord = async ({
|
|||
record,
|
||||
})
|
||||
if (!(await linkController.doesModelHaveLinkedFields())) {
|
||||
return null
|
||||
return record
|
||||
}
|
||||
switch (eventType) {
|
||||
case EventType.RECORD_SAVE:
|
||||
|
@ -94,6 +90,73 @@ module.exports.updateLinksForRecord = async ({
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to in parallel up a list of records with link info.
|
||||
* @param {string} instanceId The instance in which this record has been created.
|
||||
* @param {object[]} records A list records to be updated with link info.
|
||||
* @returns {Promise<object[]>} The updated records (this may be the same if no links were found).
|
||||
*/
|
||||
exports.attachLinkInfoToRecords = async (instanceId, records) => {
|
||||
let recordPromises = []
|
||||
for (let record of records) {
|
||||
recordPromises.push(exports.attachLinkInfoToRecord(instanceId, record))
|
||||
}
|
||||
return await Promise.all(recordPromises)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a record with information about the links that pertain to it.
|
||||
* @param {string} instanceId The instance in which this record has been created.
|
||||
* @param {object} record The record itself which is to be updated with info (if applicable).
|
||||
* @returns {Promise<object>} The updated record (this may be the same if no links were found).
|
||||
*/
|
||||
exports.attachLinkInfoToRecord = async (instanceId, record) => {
|
||||
const recordId = record._id
|
||||
const modelId = record.modelId
|
||||
// get all links for record, ignore fieldName for now
|
||||
const linkDocs = await exports.getLinkDocuments({
|
||||
instanceId,
|
||||
modelId,
|
||||
recordId,
|
||||
includeDocs: true,
|
||||
})
|
||||
if (linkDocs == null || linkDocs.length === 0) {
|
||||
return record
|
||||
}
|
||||
for (let linkDoc of linkDocs) {
|
||||
// work out which link pertains to this record
|
||||
const doc = linkDoc.doc1.recordId === recordId ? linkDoc.doc1 : linkDoc.doc2
|
||||
if (record[doc.fieldName] == null || record[doc.fieldName].count == null) {
|
||||
record[doc.fieldName] = { type: "link", count: 1 }
|
||||
} else {
|
||||
record[doc.fieldName].count++
|
||||
}
|
||||
}
|
||||
return record
|
||||
}
|
||||
|
||||
exports.createLinkView = async instanceId => {
|
||||
const db = new CouchDB(instanceId)
|
||||
const designDoc = await db.get("_design/database")
|
||||
const view = {
|
||||
map: function(doc) {
|
||||
if (doc.type === "link") {
|
||||
let doc1 = doc.doc1
|
||||
let doc2 = doc.doc2
|
||||
emit([doc1.modelId, 1, doc1.fieldName, doc1.recordId], doc2.recordId)
|
||||
emit([doc2.modelId, 1, doc2.fieldName, doc2.recordId], doc1.recordId)
|
||||
emit([doc1.modelId, 2, doc1.recordId], doc2.recordId)
|
||||
emit([doc2.modelId, 2, doc2.recordId], doc1.recordId)
|
||||
}
|
||||
}.toString(),
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
by_link: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the linking documents, not the linked documents themselves.
|
||||
* @param {string} instanceId The instance in which we are searching for linked records.
|
||||
|
@ -103,17 +166,17 @@ module.exports.updateLinksForRecord = async ({
|
|||
* @param {string|null} recordId The ID of the record which we want to find linking documents for -
|
||||
* if this is not specified then it will assume model or field level depending on whether the
|
||||
* field name has been specified.
|
||||
* @param {boolean|null} includeDoc whether to include docs in the response call, this is considerably slower so only
|
||||
* @param {boolean|null} includeDocs whether to include docs in the response call, this is considerably slower so only
|
||||
* use this if actually interested in the docs themselves.
|
||||
* @returns {Promise<object[]>} This will return an array of the linking documents that were found
|
||||
* (if any).
|
||||
*/
|
||||
module.exports.getLinkDocuments = async ({
|
||||
exports.getLinkDocuments = async ({
|
||||
instanceId,
|
||||
modelId,
|
||||
fieldName,
|
||||
recordId,
|
||||
includeDoc,
|
||||
includeDocs,
|
||||
}) => {
|
||||
const db = new CouchDB(instanceId)
|
||||
let params
|
||||
|
@ -131,11 +194,16 @@ module.exports.getLinkDocuments = async ({
|
|||
else {
|
||||
params = { startKey: [modelId, 1], endKey: [modelId, 1, {}] }
|
||||
}
|
||||
params.include_docs = !!includeDoc
|
||||
params.include_docs = !!includeDocs
|
||||
try {
|
||||
const response = await db.query("database/by_link", params)
|
||||
return response.rows.map(row => row.doc)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
// check if the view doesn't exist, it should for all new instances
|
||||
if (err != null && err.name === "not_found") {
|
||||
await exports.createLinkView(instanceId)
|
||||
} else {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue