Some fixes and refactoring in sorting objects

This commit is contained in:
jos 2017-12-20 09:00:27 +01:00
parent 346517b947
commit b011b196e1
2 changed files with 42 additions and 18 deletions

View File

@ -302,26 +302,24 @@ export function removeAll (paths) {
* @return {Array}
*/
export function sort (eson, path, order = null) {
// console.log('sort', path, order)
const compare = order === 'desc' ? compareDesc : compareAsc
const reverseCompare = (a, b) => -compare(a, b)
const object = getIn(eson, path)
if (object[META].type === 'Array') {
const items = object.map(item => item[META].value)
const createAction = (value, fromIndex, toIndex, array) => ({
const createAction = ({item, fromIndex, toIndex}) => ({
op: 'move',
from: compileJSONPointer(path.concat(String(fromIndex))),
path: compileJSONPointer(path.concat(String(toIndex)))
})
const actions = sortWithComparator(items, compare, createAction)
const actions = sortWithComparator(items, compare).map(createAction)
// when no order is provided, test whether ordering ascending
// changed anything. If not, sort descending
if (!order && isEmpty(actions)) {
return sortWithComparator(items, reverseCompare, createAction)
return sortWithComparator(items, reverseCompare).map(createAction)
}
return actions
@ -329,32 +327,45 @@ export function sort (eson, path, order = null) {
else { // object[META].type === 'Object'
const props = object[META].props
const createAction = (value, fromIndex, toIndex, objectProps) => ({
const createAction = ({item, beforeItem, fromIndex, toIndex}) => ({
op: 'move',
from: compileJSONPointer(path.concat(value)),
path: compileJSONPointer(path.concat(value)),
from: compileJSONPointer(path.concat(item)),
path: compileJSONPointer(path.concat(item)),
meta: {
before: props[toIndex]
before: beforeItem
}
})
const actions = sortWithComparator(props, compare, createAction)
const actions = sortWithComparator(props, compare).map(createAction)
// when no order is provided, test whether ordering ascending
// changed anything. If not, sort descending
if (!order && isEmpty(actions)) {
return sortWithComparator(props, reverseCompare, createAction)
return sortWithComparator(props, reverseCompare).map(createAction)
}
return actions
}
}
// TODO: comment
function sortWithComparator (items, comparator, createAction) {
/**
* Sort an array with items using given comparator, and generate move actions
* (json patch) to apply the ordering.
*
* @param {Array} items
* @param {function (a, b)} comparator Accepts to values,
* returns 1 when a is larger than b
* returns 0 when a is equal to b
* returns -1 when a is smaller than b
* @return {Array.<{item: *, beforeItem: *, fromIndex: number, toIndex: number}>}
* Returns an array with move actions that need to be
* performed to order the items of the array.
* This can be turned into json-patch actions
*/
function sortWithComparator (items, comparator) {
const orderedItems = items.slice()
let actions = []
let moveActions = []
for (let i = 0; i < orderedItems.length; i++) {
let firstIndex = i
for (let j = i; j < orderedItems.length; j++) {
@ -364,15 +375,21 @@ function sortWithComparator (items, comparator, createAction) {
}
if (i !== firstIndex) {
const firstItem = orderedItems[firstIndex]
const item = orderedItems[firstIndex]
const beforeItem = orderedItems[i]
orderedItems.splice(firstIndex, 1)
orderedItems.unshift(firstItem)
orderedItems.unshift(item)
actions.push(createAction(firstItem, firstIndex, i))
moveActions.push({
item,
fromIndex: firstIndex,
toIndex: i,
beforeItem
})
}
}
return actions
return moveActions
}
/**

View File

@ -75,3 +75,10 @@ test('sort nested Object', t => {
t.deepEqual(patchEson(eson, sort(eson, ['obj'], 'asc')).data.obj[META].props, ['a', 'b', 'c'])
t.deepEqual(patchEson(eson, sort(eson, ['obj'], 'desc')).data.obj[META].props, ['c', 'b', 'a'])
})
test('sort nested Object (larger)', t => {
const eson = jsonToEson({obj: {h:1, c:1, e:1, d:1, g:1, b:1, a:1, f:1}})
const actual = patchEson(eson, sort(eson, ['obj'])).data
t.deepEqual(actual.obj[META].props, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
})