Skip to content

Commit

Permalink
persistChanges in version control should sort the folders, to avoid t…
Browse files Browse the repository at this point in the history
…rying to insert child folders before parents folders are created
  • Loading branch information
bjrmatos committed Jun 24, 2022
1 parent 607351a commit 94d1f35
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 5 deletions.
3 changes: 3 additions & 0 deletions jsreport.config.json
Expand Up @@ -20,6 +20,9 @@
"numberOfWorkers": 3
},
"authentication": {
"cookieSession": {
"secret": "a secret"
},
"admin": {
"username": "admin",
"password": "password"
Expand Down
64 changes: 60 additions & 4 deletions packages/jsreport-version-control/lib/main/versionControl.js
Expand Up @@ -111,7 +111,14 @@ module.exports = (reporter, options) => {
return folder
}))

for (const folder of existingFolders.filter((f) => !state.find((s) => s.entityId === f._id))) {
const notFoundFoldersPathSortedDesc = existingFolders.filter((f) => !state.find((s) => s.entityId === f._id)).sort((a, b) => {
const aLevel = a.__entityPath.split('/')
const bLevel = b.__entityPath.split('/')

return bLevel.length - aLevel.length
})

for (const folder of notFoundFoldersPathSortedDesc) {
// if not found we try to search by entity path, if we found it, it means that the id changed
// and we just need to update the entity later
const existsByPath = state.find((s) => s.entitySet === 'folders' && s.path === folder.__entityPath)
Expand All @@ -128,9 +135,25 @@ module.exports = (reporter, options) => {
await reporter.documentStore.collection('folders').remove({ _id: folder._id }, req)
}

const folderGroupsInState = groupFoldersStateByLevel(state.filter(e => e.entitySet === 'folders'))

if (folderGroupsInState[-1] != null && folderGroupsInState[-1].length > 0) {
throw new Error(`Inconsistency detected, folders ${folderGroupsInState[-1].length} not found in version control state`)
}

const sortedLevelsASC = Object.keys(folderGroupsInState).map((l) => parseInt(l, 10)).sort((a, b) => a - b)

const foldersInStatePathSortedAsc = []

for (const level of sortedLevelsASC) {
foldersInStatePathSortedAsc.push(...folderGroupsInState[level])
}

// folders needs go first because of validations in fs store
// we can't move entity to a folder that doesn't yet exist
for (const e of state.filter(e => e.entitySet === 'folders')) {
// we can't move entity to a folder that doesn't yet exist,
// and also the folders should be processed in order, so a child folder
// does not tried to be inserted before parent folder
for (const e of foldersInStatePathSortedAsc) {
const shouldUpdateWithStoreId = updateBecauseIdChange.find((s) => s.entityId === e.entityId && s.entitySet === e.entitySet)

const updateReq = reporter.Request(req)
Expand Down Expand Up @@ -361,7 +384,7 @@ module.exports = (reporter, options) => {

async checkout (commitId, req) {
if (!commitId) {
throw new Error('Missing commitId for version controll checkout')
throw new Error('Missing commitId for version control checkout')
}

const versionsToCheckout = await reporter.documentStore.collection('versions').find({ _id: commitId }, req)
Expand Down Expand Up @@ -393,3 +416,36 @@ module.exports = (reporter, options) => {
}
})
}

function groupFoldersStateByLevel (foldersState) {
// group folders by level
const groups = {}

foldersState.forEach((fState) => {
let level = 0
let currentFolder = fState.entity

while (currentFolder != null) {
if (currentFolder.folder != null) {
const foundFolderState = foldersState.find((f) => f.entity.shortid === currentFolder.folder.shortid)

if (foundFolderState != null) {
level++
currentFolder = foundFolderState.entity
} else {
// folders with invalid hierarchy get inserted into -1 level
level = -1
currentFolder = null
break
}
} else {
currentFolder = null
}
}

groups[level] = groups[level] || []
groups[level].push(fState)
})

return groups
}
35 changes: 34 additions & 1 deletion packages/jsreport-version-control/test/common.js
Expand Up @@ -22,7 +22,7 @@ module.exports = (jsreport, reload = () => {}) => {
templates.should.have.length(0)
})

it('revert should recover localy removed file', async () => {
it('revert should recover locally removed file', async () => {
const req = jsreport().Request({})
await jsreport().documentStore.collection('templates').insert({ name: 'foo', engine: 'none', recipe: 'html' }, req)
await jsreport().versionControl.commit('1', undefined, req)
Expand Down Expand Up @@ -81,6 +81,39 @@ module.exports = (jsreport, reload = () => {}) => {
await jsreport().versionControl.revert(req)
})

it('revert should process folders parents first and the child folders later', async () => {
const req = jsreport().Request({})

await jsreport().documentStore.collection('folders').beforeUpdateListeners.add('test', async (q, doc, res) => {
if (doc.$set.folder) {
const f = await jsreport().documentStore.collection('folders').findOne({ shortid: doc.$set.folder.shortid }, req)
if (!f) {
throw new Error('Folder not found')
}
}
})

await jsreport().documentStore.collection('templates').insert({ name: 'foo', engine: 'none', recipe: 'html' }, req)
await jsreport().versionControl.commit('1', undefined, req)
await jsreport().documentStore.collection('folders').insert({ name: 'a', shortid: 'a' }, req)
await jsreport().documentStore.collection('templates').update({ name: 'foo' }, { $set: { folder: { shortid: 'a' } } }, req)
await jsreport().versionControl.commit('2', undefined, req)

await jsreport().documentStore.collection('folders').insert({ name: 'd', shortid: 'd' }, req)
await jsreport().documentStore.collection('folders').insert({ name: 'c', shortid: 'c', folder: { shortid: 'd' } }, req)
await jsreport().documentStore.collection('folders').insert({ name: 'b', shortid: 'b', folder: { shortid: 'c' } }, req)
await jsreport().documentStore.collection('folders').update({ name: 'a' }, { $set: { folder: { shortid: 'b' } } }, req)

await jsreport().versionControl.commit('3', undefined, req)

await jsreport().documentStore.collection('folders').remove({ name: 'a' }, req)
await jsreport().documentStore.collection('folders').remove({ name: 'b' }, req)
await jsreport().documentStore.collection('folders').remove({ name: 'c' }, req)
await jsreport().documentStore.collection('folders').remove({ name: 'd' }, req)

await jsreport().versionControl.revert(req)
})

it('revert should not change modificationDate of entities', async () => {
const req = jsreport().Request({})

Expand Down

0 comments on commit 94d1f35

Please sign in to comment.