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.
Files changed (3) hide show
  1. package/README.md +57 -39
  2. package/package.json +4 -1
  3. 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 ubiquitous data stucture:
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 things up and running.
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
- // 2. Create a method to set search configuration.
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
- // Passing an empty string effectively returns
65
- // the unfiltered set, the same as MyData.
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
- // How you set up your component to display
68
- // the filtered data is up to you and how
69
- // your component is structured. This is just
70
- // an example.
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
- // 3. Initialize the search engine.
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
- // 4. Perform search queries (finally!)
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
- During development, I integrated this `search-gold` package
100
- in a couple of apps I had built using Vue and its Composition API.
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 examples framework
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.9.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
  }