Merge pull request #706 from Budibase/bug/table-changes-fix

Bug/table changes fix
This commit is contained in:
Michael Drury 2020-10-12 17:32:59 +01:00 committed by GitHub
commit b6da9a0f83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 27 deletions

View File

@ -33,6 +33,7 @@ exports.save = async function(ctx) {
views: {}, views: {},
...rest, ...rest,
} }
let renameDocs = []
// if the model obj had an _id then it will have been retrieved // if the model obj had an _id then it will have been retrieved
const oldModel = ctx.preExisting const oldModel = ctx.preExisting
@ -49,14 +50,11 @@ exports.save = async function(ctx) {
include_docs: true, include_docs: true,
}) })
) )
renameDocs = records.rows.map(({ doc }) => {
const docs = records.rows.map(({ doc }) => {
doc[_rename.updated] = doc[_rename.old] doc[_rename.updated] = doc[_rename.old]
delete doc[_rename.old] delete doc[_rename.old]
return doc return doc
}) })
await db.bulkDocs(docs)
delete modelToSave._rename delete modelToSave._rename
} }
@ -69,9 +67,6 @@ exports.save = async function(ctx) {
modelView.schema = modelToSave.schema modelView.schema = modelToSave.schema
} }
const result = await db.post(modelToSave)
modelToSave._rev = result.rev
// update linked records // update linked records
await linkRecords.updateLinks({ await linkRecords.updateLinks({
instanceId, instanceId,
@ -82,6 +77,14 @@ exports.save = async function(ctx) {
oldModel: oldModel, oldModel: oldModel,
}) })
// don't perform any updates until relationships have been
// checked by the updateLinks function
if (renameDocs.length !== 0) {
await db.bulkDocs(renameDocs)
}
const result = await db.post(modelToSave)
modelToSave._rev = result.rev
ctx.eventEmitter && ctx.eventEmitter &&
ctx.eventEmitter.emitModel(`model:save`, instanceId, modelToSave) ctx.eventEmitter.emitModel(`model:save`, instanceId, modelToSave)
@ -105,11 +108,8 @@ exports.save = async function(ctx) {
exports.destroy = async function(ctx) { exports.destroy = async function(ctx) {
const instanceId = ctx.user.instanceId const instanceId = ctx.user.instanceId
const db = new CouchDB(instanceId) const db = new CouchDB(instanceId)
const modelToDelete = await db.get(ctx.params.modelId) const modelToDelete = await db.get(ctx.params.modelId)
await db.remove(modelToDelete)
// Delete all records for that model // Delete all records for that model
const records = await db.allDocs( const records = await db.allDocs(
getRecordParams(ctx.params.modelId, null, { getRecordParams(ctx.params.modelId, null, {
@ -117,7 +117,7 @@ exports.destroy = async function(ctx) {
}) })
) )
await db.bulkDocs( await db.bulkDocs(
records.rows.map(record => ({ _id: record.id, _deleted: true })) records.rows.map(record => ({ ...record.doc, _deleted: true }))
) )
// update linked records // update linked records
@ -127,6 +127,9 @@ exports.destroy = async function(ctx) {
model: modelToDelete, model: modelToDelete,
}) })
// don't remove the table itself until very end
await db.remove(modelToDelete)
ctx.eventEmitter && ctx.eventEmitter &&
ctx.eventEmitter.emitModel(`model:delete`, instanceId, modelToDelete) ctx.eventEmitter.emitModel(`model:delete`, instanceId, modelToDelete)
ctx.status = 200 ctx.status = 200

View File

@ -161,7 +161,7 @@ class LinkController {
}) })
// now add the docs to be deleted to the bulk operation // now add the docs to be deleted to the bulk operation
operations.push(...toDeleteDocs) operations.push(...toDeleteDocs)
// replace this field with a simple entry to denote there are links // remove the field from this row, link doc will be added to record on way out
delete record[fieldName] delete record[fieldName]
} }
} }
@ -234,8 +234,16 @@ class LinkController {
for (let fieldName of Object.keys(schema)) { for (let fieldName of Object.keys(schema)) {
const field = schema[fieldName] const field = schema[fieldName]
if (field.type === "link") { if (field.type === "link") {
// handle this in a separate try catch, want
// the put to bubble up as an error, if can't update
// table for some reason
let linkedModel
try {
linkedModel = await this._db.get(field.modelId)
} catch (err) {
continue
}
// create the link field in the other model // create the link field in the other model
const linkedModel = await this._db.get(field.modelId)
linkedModel.schema[field.fieldName] = { linkedModel.schema[field.fieldName] = {
name: field.fieldName, name: field.fieldName,
type: "link", type: "link",

View File

@ -42,6 +42,7 @@ exports.updateLinks = async function({
model, model,
oldModel, oldModel,
}) { }) {
const baseReturnObj = record == null ? model : record
if (instanceId == null) { if (instanceId == null) {
throw "Cannot operate without an instance ID." throw "Cannot operate without an instance ID."
} }
@ -50,12 +51,16 @@ exports.updateLinks = async function({
arguments[0].modelId = model._id arguments[0].modelId = model._id
} }
let linkController = new LinkController(arguments[0]) let linkController = new LinkController(arguments[0])
try {
if ( if (
!(await linkController.doesModelHaveLinkedFields()) && !(await linkController.doesModelHaveLinkedFields()) &&
(oldModel == null || (oldModel == null ||
!(await linkController.doesModelHaveLinkedFields(oldModel))) !(await linkController.doesModelHaveLinkedFields(oldModel)))
) { ) {
return record return baseReturnObj
}
} catch (err) {
return baseReturnObj
} }
switch (eventType) { switch (eventType) {
case EventType.RECORD_SAVE: case EventType.RECORD_SAVE:

View File

@ -57,21 +57,26 @@ exports.generateModelID = () => {
/** /**
* Gets the DB allDocs/query params for retrieving a record. * Gets the DB allDocs/query params for retrieving a record.
* @param {string} modelId The model in which the records have been stored. * @param {string|null} modelId The model in which the records have been stored.
* @param {string|null} recordId The ID of the record which is being specifically queried for. This can be * @param {string|null} recordId The ID of the record which is being specifically queried for. This can be
* left null to get all the records in the model. * left null to get all the records in the model.
* @param {object} otherProps Any other properties to add to the request. * @param {object} otherProps Any other properties to add to the request.
* @returns {object} Parameters which can then be used with an allDocs request. * @returns {object} Parameters which can then be used with an allDocs request.
*/ */
exports.getRecordParams = (modelId, recordId = null, otherProps = {}) => { exports.getRecordParams = (
modelId = null,
recordId = null,
otherProps = {}
) => {
if (modelId == null) { if (modelId == null) {
throw "Cannot build params for records without a model ID" return getDocParams(DocumentTypes.RECORD, null, otherProps)
} } else {
const endOfKey = const endOfKey =
recordId == null recordId == null
? `${modelId}${SEPARATOR}` ? `${modelId}${SEPARATOR}`
: `${modelId}${SEPARATOR}${recordId}` : `${modelId}${SEPARATOR}${recordId}`
return getDocParams(DocumentTypes.RECORD, endOfKey, otherProps) return getDocParams(DocumentTypes.RECORD, endOfKey, otherProps)
}
} }
/** /**