Skip to content

Commit

Permalink
feat(find): Add find feature
Browse files Browse the repository at this point in the history
We can now search from a specific root to find the first element matching the callback.

It can search in array and objects.

Fixes #17
  • Loading branch information
Antoine Aflalo committed Sep 4, 2018
1 parent f73aea2 commit bd7ab4c
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 11 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ db.getData("/arraytest/lastItemArray[-1]");
|Can't merge an Array with an Object |DataError |Same idea as the previous message. You have an array as current data and ask to merge it with an Object. |
|DataPath: /XXX. YYY is not an array. |DataError |When trying to access an object as an array. |
|DataPath: /XXX. Can't find index INDEX in array YYY |DataError |When trying to access a non-existent index in the array. |
|Only numerical values accepted for array index |DataError |An array can only use number for its indexes. For this use the normal object. |
|Only numerical values accepted for array index |DataError |An array can only use number for its indexes. For this use the normal object. |
|The entry at the path (/XXX) needs to be either an Object or an Array |DataError |When using the find method, the rootPath need to point to an object or an array to search into it for the wanted value. |
|Can't Load Database: XXXX |DatabaseError |JsonDB can't load the database for "err" reason. You can find the nested error in **error.inner** |
|Can't save the database: XXX |DatabaseError |JsonDB can't save the database for "err" reason. You can find the nested error in **error.inner** |
|DataBase not loaded. Can't write |DatabaseError |Since the database hasn't been loaded correctly, the module won't let you save the data to avoid erasing your database. |
Expand Down
43 changes: 37 additions & 6 deletions src/JsonDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {ArrayInfo} from "./lib/ArrayInfo"

type DataPath = Array<string>


export type FindCallback = (entry: any, index: number | string) => boolean

export default class JsonDB {
readonly filename: string
private loaded: boolean = false
Expand All @@ -16,15 +19,21 @@ export default class JsonDB {
readonly humanReadable: boolean


constructor(filename: string, saveOnPush?: boolean, humanReadable?: boolean) {
/**
* JSONDB Constructor
* @param filename where to save the "DB"
* @param saveOnPush save the database at each push command into the json file
* @param humanReadable the JSON file will be readable easily by a human
*/
constructor(filename: string, saveOnPush: boolean = true, humanReadable: boolean = false) {
this.filename = filename

if (!filename.endsWith(".json")) {
this.filename += ".json"
}

this.saveOnPush = typeof(saveOnPush) == "boolean" ? saveOnPush : true
this.humanReadable = typeof(humanReadable) == "boolean" ? humanReadable : false
this.saveOnPush = saveOnPush
this.humanReadable = humanReadable

if (!FS.existsSync(this.filename)) {
const dirname = path.dirname(this.filename)
Expand Down Expand Up @@ -150,14 +159,36 @@ export default class JsonDB {
}
}

/**
* Find a specific entry in an array/object
* @param rootPath base dataPath from where to start searching
* @param callback method to filter the result and find the wanted entry. Receive the entry and it's index.
*/
public find<T>(rootPath: string, callback: FindCallback): T | undefined {
const result = this.getData(rootPath)
if (Array.isArray(result)) {
return result.find(callback) as T
}
if (result instanceof Object) {
const entries = Object.entries(result)
const found = entries.find((entry: Array<any>) => {
return callback(entry[1], entry[0])
})
if (!found || found.length < 2) {
return undefined
}
return found[1] as T
}
throw new DataError("The entry at the path (" + rootPath + ") needs to be either an Object or an Array", 12)
}

/**
* Pushing data into the database
* @param dataPath path leading to the data
* @param data data to push
* @param override overriding or not the data, if not, it will merge them
*/
public push(dataPath: string, data: any, override?: boolean): void {
override = override === undefined ? true : override
public push(dataPath: string, data: any, override: boolean = true): void {
const dbData = this.getParentData(dataPath, true)
if (!dbData) {
throw new Error("Data not found")
Expand All @@ -175,7 +206,7 @@ export default class JsonDB {
toSet = storedData.concat(data)
} else if (data === Object(data)) {
if (Array.isArray(dbData.getData())) {
throw new DataError("Can't merge an Array with an Object", 4)
throw new DataError("Can't merge an Array with an Object", 4)
}
toSet = merge(dbData.getData(), data)
}
Expand Down
5 changes: 1 addition & 4 deletions src/lib/DBParentData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ export class DBParentData {
* Check if it's an array
* @param deletion
*/
private checkArray(deletion?: boolean): ArrayInfo | null {
if (typeof deletion === undefined) {
deletion = false
}
private checkArray(deletion: boolean = false): ArrayInfo | null {
const arrayInfo = ArrayInfo.processArray(this.parent)
if (arrayInfo && (!arrayInfo.append || deletion) && !arrayInfo.isValid(this.data)) {
throw new DataError("DataPath: /" + this.dataPath + ". Can't find index " + arrayInfo.index + " in array " + arrayInfo.property, 10)
Expand Down
25 changes: 25 additions & 0 deletions test/02-jsondb.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,31 @@ describe('JsonDB', () => {
}
)
})
describe('Find Info', () => {
const db = new JsonDB(testFile6, true)

test('should be able to find the wanted info in object',
() => {
db.push('/find/id-0', {test: 'hello'})
db.push('/find/id-1', {test: 'hey'})
db.push('/find/id-2', {test: 'echo'})
const result = db.find<string>('/find', entry => entry.test === 'echo')
expect(result).toBeInstanceOf(Object)
expect(result).toHaveProperty('test', 'echo')
})
test('should be able to find the wanted info in array',
() => {
db.push('/find/data', [{test: 'echo'}, {test: 'hey'}, {test: 'hello'}])
const result = db.find<string>('/find/data', entry => entry.test === 'hello')
expect(result).toBeInstanceOf(Object)
expect(result).toHaveProperty('test', 'hello')
})
test('shouldn\'t be able to find a data in anything else than Object or Array',
() => {
db.push('/find/number', 1)
expect(() => db.find<string>('/find/number', entry => entry.test === 'hello')).toThrow(DataError)
})
})

describe('Cleanup', () => {
test('should remove the test files', () => {
Expand Down

0 comments on commit bd7ab4c

Please sign in to comment.