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) // console.log('expand', callback, expand)
if (typeof callback === 'function') { 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 (value.type === 'Array' || value.type === 'Object') {
if (callback(path)) { if (callback(path)) {
return setIn(value, ['expanded'], expanded) return setIn(value, ['expanded'], expanded)
@ -503,18 +503,51 @@ export function addErrors (data, errors) {
} }
/** /**
* Merge one or multiple errors (for example JSON schema errors) * Search some text in all properties and values
* into the data
* *
* @param {JSONData} data * @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) { export function search (data, text) {
let updatedData = data 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 let updatedItems = updatedValue.items
updatedValue.items.forEach((item, index) => { updatedValue.items.forEach((item, index) => {
updatedItems = setIn(updatedItems, [index], const updatedItem = recurseTransform(item, path.concat(String(index)), root, callback)
recurseTransform(item, path.concat(String(index)), root, callback)) updatedItems = setIn(updatedItems, [index], updatedItem)
}) })
updatedValue = setIn(updatedValue, ['items'], updatedItems) updatedValue = setIn(updatedValue, ['items'], updatedItems)
@ -556,8 +589,8 @@ function recurseTransform (value, path, root, callback) {
let updatedProps = updatedValue.props let updatedProps = updatedValue.props
updatedValue.props.forEach((prop, index) => { updatedValue.props.forEach((prop, index) => {
updatedProps = setIn(updatedProps, [index, 'value'], const updatedItem = recurseTransform(prop.value, path.concat(prop.name), root, callback)
recurseTransform(prop.value, path.concat(prop.name), root, callback)) updatedProps = setIn(updatedProps, [index, 'value'], updatedItem)
}) })
updatedValue = setIn(updatedValue, ['props'], updatedProps) updatedValue = setIn(updatedValue, ['props'], updatedProps)

View File

@ -1,6 +1,6 @@
import test from 'ava'; import test from 'ava';
import { import {
jsonToData, dataToJson, patchData, pathExists, transform, jsonToData, dataToJson, patchData, pathExists, transform, search,
parseJSONPointer, compileJSONPointer, parseJSONPointer, compileJSONPointer,
expand, addErrors expand, addErrors
} from '../src/jsonData' } 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 = [ const JSON_SCHEMA_ERRORS = [
{dataPath: '/obj/arr/2/b', message: 'String expected'}, {dataPath: '/obj/arr/2/b', message: 'String expected'},
{dataPath: '/nill', message: 'Null expected'} {dataPath: '/nill', message: 'Null expected'}
@ -740,43 +928,10 @@ test('add and remove errors', t => {
test('transform', t => { test('transform', t => {
// {obj: {a: 2}, arr: [3]} // {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 = [] let log = []
const transformed = transform(data, function (value, path, root) { const transformed = transform(JSON_DATA_SMALL, function (value, path, root) {
t.truthy(root === data) t.truthy(root === JSON_DATA_SMALL)
log.push([value, path, root]) log.push([value, path, root])
@ -792,21 +947,31 @@ test('transform', t => {
// console.log('transformed', JSON.stringify(transformed, null, 2)) // console.log('transformed', JSON.stringify(transformed, null, 2))
const EXPECTED_LOG = [ const EXPECTED_LOG = [
[data, [], data], [JSON_DATA_SMALL, [], JSON_DATA_SMALL],
[data.props[0].value, ['obj'], data], [JSON_DATA_SMALL.props[0].value, ['obj'], JSON_DATA_SMALL],
[data.props[0].value.props[0].value, ['obj', 'a'], data], [JSON_DATA_SMALL.props[0].value.props[0].value, ['obj', 'a'], JSON_DATA_SMALL],
[data.props[1].value, ['arr'], data], [JSON_DATA_SMALL.props[1].value, ['arr'], JSON_DATA_SMALL],
[data.props[1].value.items[0], ['arr', '0'], data], [JSON_DATA_SMALL.props[1].value.items[0], ['arr', '0'], JSON_DATA_SMALL],
] ]
// log.forEach((row, index) => { // log.forEach((row, index) => {
// t.deepEqual(log[index], EXPECTED_LOG[index], 'should have equal log at index ' + index ) // t.deepEqual(log[index], EXPECTED_LOG[index], 'should have equal log at index ' + index )
// }) // })
t.deepEqual(log, EXPECTED_LOG) t.deepEqual(log, EXPECTED_LOG)
t.truthy(transformed !== data) t.truthy(transformed !== JSON_DATA_SMALL)
t.truthy(transformed.props[0].value !== data.props[0].value) t.truthy(transformed.props[0].value !== JSON_DATA_SMALL.props[0].value)
t.truthy(transformed.props[0].value.props[0].value !== data.props[0].value.props[0].value) t.truthy(transformed.props[0].value.props[0].value !== JSON_DATA_SMALL.props[0].value.props[0].value)
t.truthy(data.props[1].value === data.props[1].value) t.truthy(JSON_DATA_SMALL.props[1].value === JSON_DATA_SMALL.props[1].value)
t.truthy(data.props[1].value.items[0] === data.props[1].value.items[0]) 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)
})