search-gold 0.9.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -39
- package/package.json +4 -1
- package/src/search.ts +17 -4
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
Your page displays a list columnar information, based on the
|
|
5
|
+
Your web page displays a list of columnar information, based on the common data stucture:
|
|
6
6
|
|
|
7
7
|
`array of objects`
|
|
8
8
|
|
|
@@ -22,25 +22,30 @@ $ bun i search-gold
|
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
24
24
|
|
|
25
|
-
The following should provide enough to get
|
|
25
|
+
The following should provide enough to get local search up and running and keep your users in a happy place!
|
|
26
26
|
|
|
27
|
-
`my-data-list-component.ts
|
|
27
|
+
Provide the following in your component, e.g., `my-data-list-component.ts`.
|
|
28
|
+
|
|
29
|
+
### 1. Import the two types and methods.
|
|
28
30
|
```javascript
|
|
29
|
-
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
30
|
-
// 1. Import the two types and methods.
|
|
31
|
-
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
32
31
|
import {
|
|
33
32
|
ConfigParams,
|
|
34
33
|
ItemRecord,
|
|
35
34
|
searchHandler,
|
|
36
35
|
searchSetConfig,
|
|
37
36
|
} from 'search-gold'
|
|
37
|
+
````
|
|
38
|
+
|
|
39
|
+
### 2. Create a method to set search configuration.
|
|
40
|
+
|
|
41
|
+
This wrapper method only needs to be called in the following two cases:
|
|
42
|
+
|
|
43
|
+
* when component is initialized and when data is ready
|
|
44
|
+
* when data changes (record has been created, edited, deleted)
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// The configuration will be custom for your data.
|
|
43
|
-
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
46
|
+
You can name this wrapper method anything you want.
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
44
49
|
const initSearchConfig = () => {
|
|
45
50
|
const config: ConfigParams = {
|
|
46
51
|
// required: items must reference an array of
|
|
@@ -57,50 +62,63 @@ const initSearchConfig = () => {
|
|
|
57
62
|
|
|
58
63
|
// optional: default is false
|
|
59
64
|
caseSensitive: true,
|
|
65
|
+
|
|
66
|
+
// optional: default is true
|
|
67
|
+
//
|
|
68
|
+
// You should only ever consider disabling
|
|
69
|
+
// memoization if you observe browser memory
|
|
70
|
+
// limitations with cached search results.
|
|
71
|
+
enableMemoize: false
|
|
60
72
|
},
|
|
61
73
|
|
|
74
|
+
// Call the imported method with config arg.
|
|
62
75
|
searchSetConfig(config)
|
|
63
76
|
|
|
64
|
-
//
|
|
65
|
-
//
|
|
77
|
+
// After setting the config, you can call searchHandler()
|
|
78
|
+
// as many times as necessary without having to set the
|
|
79
|
+
// config again.
|
|
66
80
|
//
|
|
67
|
-
//
|
|
68
|
-
// the
|
|
69
|
-
//
|
|
70
|
-
//
|
|
81
|
+
// Passing an empty string effectively returns the
|
|
82
|
+
// the unfiltered set of records, the same as MyData.
|
|
83
|
+
//
|
|
84
|
+
// How you set up your component to display the filtered
|
|
85
|
+
// data is up to you and how your component is structured.
|
|
86
|
+
// This is just an example.
|
|
71
87
|
myFilteredData = <ItemRecord[]>searchHandler('')
|
|
72
88
|
}
|
|
89
|
+
````
|
|
90
|
+
|
|
91
|
+
### 3. Initialize the search engine.
|
|
92
|
+
|
|
93
|
+
This method (from Step 2.) should be called when your component has been
|
|
94
|
+
initialized and your data is ready.
|
|
95
|
+
|
|
96
|
+
Also, this `initSearchConfig()` method should be called whenever your
|
|
97
|
+
data changes after a record has been created, edited, or deleted.
|
|
73
98
|
|
|
74
|
-
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
// This method (from step 2.) should be called when
|
|
78
|
-
// your module is initialized and your data is ready.
|
|
79
|
-
//
|
|
80
|
-
// Also, it should be called whenever your data
|
|
81
|
-
// changes via record create, edit, or delete.
|
|
82
|
-
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
99
|
+
```javascript
|
|
100
|
+
// For this example we chose this method name; you
|
|
101
|
+
// can name this wrapper method anything you want.
|
|
83
102
|
initSearchConfig()
|
|
103
|
+
````
|
|
104
|
+
|
|
105
|
+
### 4. Execute search queries and get results.
|
|
84
106
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
// Presumably, a method is binded to the UI's
|
|
89
|
-
// search field (in this example it's called
|
|
90
|
-
// 'searchMyData') and is called on every keystroke.
|
|
91
|
-
//
|
|
92
|
-
// You can optionally add a debounce in your component.
|
|
93
|
-
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
107
|
+
Presumably, a method is binded to the UI's search field (in this example it's called
|
|
108
|
+
`searchMyData`) and is called on every keystroke, debounced keystrokes, or an explicit and separate submit event. Ultimately, the UX is left up to the front end developer.
|
|
109
|
+
```javascript
|
|
94
110
|
const searchMyData = (query: string) => {
|
|
111
|
+
// Call the imported method and get results.
|
|
95
112
|
myFilteredData = searchHandler(query)
|
|
96
113
|
}
|
|
97
114
|
```
|
|
98
115
|
|
|
99
|
-
|
|
100
|
-
|
|
116
|
+
## Author's Development
|
|
117
|
+
|
|
118
|
+
During development of the `search-gold` package, I integrated it
|
|
119
|
+
into a several apps I had built with Vue using its Composition API.
|
|
101
120
|
|
|
102
|
-
I tried to keep the Usage code
|
|
103
|
-
neutral.
|
|
121
|
+
In this documentation I tried to keep the Usage code snippets framework neutral.
|
|
104
122
|
|
|
105
123
|
# Credits
|
|
106
124
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "search-gold",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"description": "speedy search engine targeting an array of objects",
|
|
6
6
|
"author": "gold",
|
|
7
7
|
"main": "./src/search.ts",
|
|
@@ -30,6 +30,9 @@
|
|
|
30
30
|
"keywords": [
|
|
31
31
|
"data search",
|
|
32
32
|
"search",
|
|
33
|
+
"local search",
|
|
34
|
+
"search for gold",
|
|
35
|
+
"search for 金",
|
|
33
36
|
"data filter",
|
|
34
37
|
"simple search",
|
|
35
38
|
"fast search"
|
package/src/search.ts
CHANGED
|
@@ -4,13 +4,14 @@ export interface ConfigParams {
|
|
|
4
4
|
items: ItemRecord[]
|
|
5
5
|
keys: string[]
|
|
6
6
|
caseSensitive?: boolean
|
|
7
|
+
enableMemoize?: boolean
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
interface Config {
|
|
10
11
|
Items: ItemRecord[]
|
|
11
12
|
Keys: string[]
|
|
12
|
-
CaseSensitive: boolean
|
|
13
13
|
RegexFlag: 'i' | undefined
|
|
14
|
+
EnableMemoize: boolean
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
|
|
@@ -21,18 +22,22 @@ const escapeRegExp = (str: string): string => {
|
|
|
21
22
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
const cache = new Map()
|
|
26
|
+
|
|
24
27
|
const Conf: Config = {
|
|
25
28
|
Items: [],
|
|
26
29
|
Keys: [],
|
|
27
|
-
CaseSensitive: false,
|
|
28
30
|
RegexFlag: 'i',
|
|
31
|
+
EnableMemoize: true,
|
|
29
32
|
}
|
|
30
33
|
export const searchSetConfig = (params: ConfigParams): void => {
|
|
31
|
-
const { items, keys, caseSensitive = false } = params
|
|
34
|
+
const { items, keys, caseSensitive = false, enableMemoize = true } = params
|
|
32
35
|
Conf.Items = items
|
|
33
36
|
Conf.Keys = keys
|
|
34
|
-
Conf.CaseSensitive = caseSensitive
|
|
35
37
|
Conf.RegexFlag = caseSensitive ? undefined : 'i'
|
|
38
|
+
Conf.EnableMemoize = enableMemoize
|
|
39
|
+
|
|
40
|
+
cache.clear()
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
// Since (if no debounce) every search input keystroke calls this
|
|
@@ -52,6 +57,10 @@ export const searchHandler = (query: string): ItemRecord[] => {
|
|
|
52
57
|
return Conf.Items
|
|
53
58
|
}
|
|
54
59
|
|
|
60
|
+
if (Conf.EnableMemoize && cache.has(qTrimmed)) {
|
|
61
|
+
return cache.get(qTrimmed)
|
|
62
|
+
}
|
|
63
|
+
|
|
55
64
|
const rx = new RegExp(qTrimmed, Conf.RegexFlag)
|
|
56
65
|
|
|
57
66
|
// All the dirty work is done here...
|
|
@@ -62,5 +71,9 @@ export const searchHandler = (query: string): ItemRecord[] => {
|
|
|
62
71
|
}
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
if (Conf.EnableMemoize && qTrimmed.length >= 3) {
|
|
75
|
+
cache.set(qTrimmed, results)
|
|
76
|
+
}
|
|
77
|
+
|
|
65
78
|
return results
|
|
66
79
|
}
|