Skip to content

Commit

Permalink
feat: add text manipulators (#10)
Browse files Browse the repository at this point in the history
* feat: add text setters

* fix: add text manipulators
  • Loading branch information
jaulz authored Jun 26, 2020
1 parent 26e5b2c commit e86db00
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 36 deletions.
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ $ yarn add advanced-search-query
import parseAdvancedSearchQuery from 'advanced-search-query'

// Perform parsing
const str = 'to:me -from:[email protected] foobar1 -foobar2'
const parsedSearchQuery = parseAdvancedSearchQuery(str)
const input = 'to:me -from:[email protected] foobar1 -foobar2'
const parsedSearchQuery = parseAdvancedSearchQuery(input)

// [ { text: 'foorbar1', isNegated: false }, { text: 'foobar2', isNegated: true } ]
parsedSearchQuery.getTexts()
Expand All @@ -46,12 +46,16 @@ parsedSearchQuery.toString()
parsedSearchQuery.removeKeyword('from', true).toString()

// `to:me from:[email protected] foobar1 -foobar2`
parsedSearchQuery.addEntry('from', '[email protected]', false).toString()
parsedSearchQuery.addKeyword('from', '[email protected]', false).toString()

// `from:[email protected] foobar1 -foobar2`
parsedSearchQuery.removeEntry('to', 'me', false).toString()
parsedSearchQuery.removeKeyword('to', 'me', false).toString()

/* clone operation instantiates a new version by copying over data. */
// `from:[email protected] -foobar2`
parsedSearchQuery.removeText('foobar1').toString()

// `from:[email protected] foobar1 -foobar2`
parsedSearchQuery.addText('foobar1', false).toString()

// `from:[email protected] foobar1 -foobar2`
parsedSearchQuery.clone().toString()
Expand Down
48 changes: 46 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class AdvancedSearchQuery {
}

getKeywords(): Record<string, Omit<Keyword, 'name'>[]> {
const keywords = groupBy(this.keywords, 'name')
const keywords: Record<string, Keyword[]> = groupBy(this.keywords, 'name')

return Object.entries(keywords)
.map(([name, keywords]): [string, Omit<Keyword, 'name'>[]] => {
Expand Down Expand Up @@ -122,13 +122,22 @@ export class AdvancedSearchQuery {
return parsedQuery
}

addKeyword(name: string, value: Value, isNegated: boolean) {
addKeyword(name: string, value: Value, isNegated: boolean = false) {
this.keywords.push({
name,
value,
isNegated,
})
this.isDirty = true

return this
}

removeKeywords() {
this.keywords = []
this.isDirty = true

return this
}

removeKeyword(name: string, value?: Value, isNegated?: boolean) {
Expand All @@ -153,6 +162,41 @@ export class AdvancedSearchQuery {
return this
}

addText(value: Value, isNegated: boolean = false) {
this.texts.push({
value,
isNegated,
})
this.isDirty = true

return this
}

removeText(value: Value, isNegated?: boolean) {
const texts = this.texts.filter((text) => {
if (value !== text.value) {
return true
}

if (typeof isNegated !== 'undefined' && isNegated !== text.isNegated) {
return true
}

return false
})
this.isDirty = texts.length !== this.texts.length
this.texts = texts

return this
}

removeTexts() {
this.texts = []
this.isDirty = true

return this
}

clone() {
return new AdvancedSearchQuery(this.keywords.slice(0), this.texts.slice(0))
}
Expand Down
71 changes: 61 additions & 10 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('searchString', () => {
])
})

test('multiple getText() segments', () => {
test('multiple texts', () => {
const input = 'to:me foobar zoobar'
const parsed = parseAdvancedSearchQuery(input)

Expand Down Expand Up @@ -104,7 +104,7 @@ describe('searchString', () => {
])
})

test('isNegated getText()', () => {
test('negated texts', () => {
const input = 'hello -big -fat is:condition world'
const parsed = parseAdvancedSearchQuery(input)

Expand All @@ -122,13 +122,13 @@ describe('searchString', () => {

test('complex use case', () => {
const input =
'op1:value op1:value2 op2:"multi, \'word\', value" sometext -op3:value more text'
'op1:value op1:value2 op2:"multi, \'word\', value" sometext -op3:value more -text'
const parsed = parseAdvancedSearchQuery(input)

expect(parsed.getTexts()).toEqual([
{ value: 'sometext', isNegated: false },
{ value: 'more', isNegated: false },
{ value: 'text', isNegated: false },
{ value: 'text', isNegated: true },
])
expect(getNumberOfKeywords(parsed)).toEqual(3)
expect(parsed.getKeyword('op1')).toEqual([
Expand Down Expand Up @@ -162,24 +162,34 @@ describe('searchString', () => {
op3: [{ value: 'value', isNegated: true }],
})
expect(parsed.toString()).toEqual(
'op1:value,value2 op2:"multi, \'word\', value" -op3:value sometext more text'
'op1:value,value2 op2:"multi, \'word\', value" -op3:value sometext more -text'
)
parsed.removeKeyword('op1')
expect(parsed.toString()).toEqual(
'op2:"multi, \'word\', value" -op3:value sometext more text'
'op2:"multi, \'word\', value" -op3:value sometext more -text'
)
// Check once more to see if cached copy returns correctly.
expect(parsed.toString()).toEqual(
'op2:"multi, \'word\', value" -op3:value sometext more text'
'op2:"multi, \'word\', value" -op3:value sometext more -text'
)
parsed.removeKeyword('op3', undefined, false)
expect(parsed.toString()).toEqual(
'op2:"multi, \'word\', value" -op3:value sometext more text'
'op2:"multi, \'word\', value" -op3:value sometext more -text'
)
parsed.removeKeyword('op3', 'value')
expect(parsed.toString()).toEqual(
'op2:"multi, \'word\', value" sometext more text'
'op2:"multi, \'word\', value" sometext more -text'
)
parsed.removeText('sometext')
expect(parsed.toString()).toEqual('op2:"multi, \'word\', value" more -text')
parsed.removeText('text', false)
expect(parsed.toString()).toEqual('op2:"multi, \'word\', value" more -text')
parsed.removeText('text', true)
expect(parsed.toString()).toEqual('op2:"multi, \'word\', value" more')
parsed.removeTexts()
expect(parsed.toString()).toEqual('op2:"multi, \'word\', value"')
parsed.removeKeywords()
expect(parsed.toString()).toEqual('')
})

test('several quoted strings', () => {
Expand Down Expand Up @@ -358,7 +368,7 @@ describe('searchString', () => {
expect(parsed.toObject().keywords.foo.include).toEqual(['bar'])
})

test('removeKeyword should remove only one case', () => {
test('removeKeyword should remove all occurences', () => {
const input = '-foo:bar,baz,bar,bar,bar'
const parsed = parseAdvancedSearchQuery(input)

Expand Down Expand Up @@ -388,4 +398,45 @@ describe('searchString', () => {
expect(parsed.toObject().keywords.foo.include).toEqual(['bar'])
expect(parsed.isDirty).toEqual(false)
})

test('removeText simple case', () => {
const input = 'bar baz'
const parsed = parseAdvancedSearchQuery(input)

expect(parsed.toObject().text.include).toEqual(['bar', 'baz'])
parsed.removeText('baz')
expect(parsed.toObject().text.include).toEqual(['bar'])
})

test('removeText should remove all occurences', () => {
const input = 'bar baz bar bar bar'
const parsed = parseAdvancedSearchQuery(input)

expect(parsed.toObject().text.include).toEqual([
'bar',
'baz',
'bar',
'bar',
'bar',
])

parsed.removeText('bar')

expect(parsed.toObject().text.include).toEqual(['baz'])
})

test('removeText should be noop if entry is not found', () => {
const input = 'test -notest'
const parsed = parseAdvancedSearchQuery(input)

expect(parsed.toObject().text.include).toEqual(['test'])
expect(parsed.toObject().text.exclude).toEqual(['notest'])
expect(parsed.toString()).toEqual('test -notest')
expect(parsed.isDirty).toEqual(false)

parsed.removeText('test', true)

expect(parsed.toObject().text.include).toEqual(['test'])
expect(parsed.isDirty).toEqual(false)
})
})
39 changes: 20 additions & 19 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"strict": true,
"outDir": "dist/node/",
"sourceMap": true,
"declaration": true,
"types": ["jest"],
"skipLibCheck": true,
"esModuleInterop": true
},
"include": [
"*.ts",
"./src/**/*",
"./tests/**/*",
"./node_modules/@types/**/*"
]
}
{
"compilerOptions": {
"lib": ["es2019"],
"target": "es6",
"module": "commonjs",
"strict": true,
"outDir": "dist/node/",
"sourceMap": true,
"declaration": true,
"types": ["jest"],
"skipLibCheck": true,
"esModuleInterop": true
},
"include": [
"*.ts",
"./src/**/*",
"./tests/**/*",
"./node_modules/@types/**/*"
]
}

0 comments on commit e86db00

Please sign in to comment.