Implemented function search

This commit is contained in:
jos 2016-11-19 21:21:09 +01:00
parent 96186b836a
commit e5e61b71e3
2 changed files with 257 additions and 59 deletions

View File

@ -461,7 +461,7 @@ export function expand (data, callback, expanded) {
// console.log('expand', callback, expand)
if (typeof callback === 'function') {
return transform (data, function (value, path, root) {
return transform (data, function (value, path) {
if (value.type === 'Array' || value.type === 'Object') {
if (callback(path)) {
return setIn(value, ['expanded'], expanded)
@ -503,18 +503,51 @@ export function addErrors (data, errors) {
}
/**
* Merge one or multiple errors (for example JSON schema errors)
* into the data
* Search some text in all properties and values
*
* @param {JSONData} data
* @param {string} search
* @param {string} text
* @return {JSONData} Returns an updated `data` object containing the search results
*/
export function setSearch (data, search) {
let updatedData = data
export function search (data, text) {
return transform(data, function (value) {
// search in values
if (value.type === 'value') {
if (containsCaseInsensitive(value.value, text)) {
return setIn(value, ['search'], true)
}
else {
return deleteIn(value, ['search'])
}
}
// TODO: traverse over the data, add a field search: 'field'|'value' to all matching fields/values
// search object property names
if (value.type === 'Object') {
let updatedProps = value.props
updatedProps.forEach((prop, index) => {
if (containsCaseInsensitive(prop.name, text)) {
updatedProps = setIn(updatedProps, [index, 'search'], true)
}
else {
updatedProps = deleteIn(updatedProps, [index, 'search'])
}
})
return updatedData
return setIn(value, ['props'], updatedProps)
}
return value
})
}
/**
* Do a case insensitive search for a search text in a text
* @param {String} text
* @param {String} search
* @return {boolean} Returns true if `search` is found in `text`
*/
export function containsCaseInsensitive (text, search) {
return String(text).toLowerCase().indexOf(search.toLowerCase()) !== -1
}
/**
@ -543,8 +576,8 @@ function recurseTransform (value, path, root, callback) {
let updatedItems = updatedValue.items
updatedValue.items.forEach((item, index) => {
updatedItems = setIn(updatedItems, [index],
recurseTransform(item, path.concat(String(index)), root, callback))
const updatedItem = recurseTransform(item, path.concat(String(index)), root, callback)
updatedItems = setIn(updatedItems, [index], updatedItem)
})
updatedValue = setIn(updatedValue, ['items'], updatedItems)
@ -556,8 +589,8 @@ function recurseTransform (value, path, root, callback) {
let updatedProps = updatedValue.props
updatedValue.props.forEach((prop, index) => {
updatedProps = setIn(updatedProps, [index, 'value'],
recurseTransform(prop.value, path.concat(prop.name), root, callback))
const updatedItem = recurseTransform(prop.value, path.concat(prop.name), root, callback)
updatedProps = setIn(updatedProps, [index, 'value'], updatedItem)
})
updatedValue = setIn(updatedValue, ['props'], updatedProps)

View File

@ -1,6 +1,6 @@
import test from 'ava';
import {
jsonToData, dataToJson, patchData, pathExists, transform,
jsonToData, dataToJson, patchData, pathExists, transform, search,
parseJSONPointer, compileJSONPointer,
expand, addErrors
} from '../src/jsonData'
@ -237,6 +237,194 @@ const JSON_DATA_EXAMPLE_COLLAPSED_2 = {
]
}
// after search for 'O' (case insensitive)
const JSON_DATA_EXAMPLE_SEARCH_1 = {
type: 'Object',
expanded: true,
props: [
{
name: 'obj',
search: true,
value: {
type: 'Object',
expanded: true,
props: [
{
name: 'arr',
value: {
type: 'Array',
expanded: true,
items: [
{
type: 'value',
value: 1
},
{
type: 'value',
value: 2
},
{
type: 'Object',
expanded: true,
props: [
{
name: 'a',
value: {
type: 'value',
value: 3
}
},
{
name: 'b',
value: {
type: 'value',
value: 4
}
}
]
},
]
}
}
]
}
},
{
name: 'str',
value: {
type: 'value',
value: 'hello world',
search: true
}
},
{
name: 'nill',
value: {
type: 'value',
value: null
}
},
{
name: 'bool',
search: true,
value: {
type: 'value',
value: false
}
}
]
}
// after search for '2'
const JSON_DATA_EXAMPLE_SEARCH_2 = {
type: 'Object',
expanded: true,
props: [
{
name: 'obj',
value: {
type: 'Object',
expanded: true,
props: [
{
name: 'arr',
value: {
type: 'Array',
expanded: true,
items: [
{
type: 'value',
value: 1
},
{
type: 'value',
value: 2,
search: true
},
{
type: 'Object',
expanded: true,
props: [
{
name: 'a',
value: {
type: 'value',
value: 3
}
},
{
name: 'b',
value: {
type: 'value',
value: 4
}
}
]
},
]
}
}
]
}
},
{
name: 'str',
value: {
type: 'value',
value: 'hello world'
}
},
{
name: 'nill',
value: {
type: 'value',
value: null
}
},
{
name: 'bool',
value: {
type: 'value',
value: false
}
}
]
}
const JSON_DATA_SMALL = {
type: 'Object',
props: [
{
name: 'obj',
value: {
type: 'Object',
props: [
{
name: 'a',
value: {
type: 'value',
value: 2
}
}
]
}
},
{
name: 'arr',
value: {
type: 'Array',
items: [
{
type: 'value',
value: 3
}
]
}
}
]
}
const JSON_SCHEMA_ERRORS = [
{dataPath: '/obj/arr/2/b', message: 'String expected'},
{dataPath: '/nill', message: 'Null expected'}
@ -740,43 +928,10 @@ test('add and remove errors', t => {
test('transform', t => {
// {obj: {a: 2}, arr: [3]}
const data = {
type: 'Object',
props: [
{
name: 'obj',
value: {
type: 'Object',
props: [
{
name: 'a',
value: {
type: 'value',
value: 2
}
}
]
}
},
{
name: 'arr',
value: {
type: 'Array',
items: [
{
type: 'value',
value: 3
}
]
}
}
]
}
let log = []
const transformed = transform(data, function (value, path, root) {
t.truthy(root === data)
const transformed = transform(JSON_DATA_SMALL, function (value, path, root) {
t.truthy(root === JSON_DATA_SMALL)
log.push([value, path, root])
@ -792,21 +947,31 @@ test('transform', t => {
// console.log('transformed', JSON.stringify(transformed, null, 2))
const EXPECTED_LOG = [
[data, [], data],
[data.props[0].value, ['obj'], data],
[data.props[0].value.props[0].value, ['obj', 'a'], data],
[data.props[1].value, ['arr'], data],
[data.props[1].value.items[0], ['arr', '0'], data],
[JSON_DATA_SMALL, [], JSON_DATA_SMALL],
[JSON_DATA_SMALL.props[0].value, ['obj'], JSON_DATA_SMALL],
[JSON_DATA_SMALL.props[0].value.props[0].value, ['obj', 'a'], JSON_DATA_SMALL],
[JSON_DATA_SMALL.props[1].value, ['arr'], JSON_DATA_SMALL],
[JSON_DATA_SMALL.props[1].value.items[0], ['arr', '0'], JSON_DATA_SMALL],
]
// log.forEach((row, index) => {
// t.deepEqual(log[index], EXPECTED_LOG[index], 'should have equal log at index ' + index )
// })
t.deepEqual(log, EXPECTED_LOG)
t.truthy(transformed !== data)
t.truthy(transformed.props[0].value !== data.props[0].value)
t.truthy(transformed.props[0].value.props[0].value !== data.props[0].value.props[0].value)
t.truthy(data.props[1].value === data.props[1].value)
t.truthy(data.props[1].value.items[0] === data.props[1].value.items[0])
t.truthy(transformed !== JSON_DATA_SMALL)
t.truthy(transformed.props[0].value !== JSON_DATA_SMALL.props[0].value)
t.truthy(transformed.props[0].value.props[0].value !== JSON_DATA_SMALL.props[0].value.props[0].value)
t.truthy(JSON_DATA_SMALL.props[1].value === JSON_DATA_SMALL.props[1].value)
t.truthy(JSON_DATA_SMALL.props[1].value.items[0] === JSON_DATA_SMALL.props[1].value.items[0])
})
test('search', t => {
const result1 = search(JSON_DATA_EXAMPLE, 'O')
t.deepEqual(result1, JSON_DATA_EXAMPLE_SEARCH_1)
// search for something else. Should clean up earlier search results
const result2 = search(result1, '2')
t.deepEqual(result2, JSON_DATA_EXAMPLE_SEARCH_2)
})