firestore-meilisearch 0.1.5 → 0.1.7

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 CHANGED
@@ -40,7 +40,7 @@ Note that this extension only listens for changes to _documents_ in a specific c
40
40
  Before installing this extension, you'll need to:
41
41
 
42
42
  - [Set up Cloud Firestore in your Firebase project](https://firebase.google.com/docs/firestore/quickstart)
43
- - Run a Meilisearch instance. There are many easy ways [to download and run a Meilisearch instance](https://docs.meilisearch.com/learn/getting_started/installation.html#download-and-launch)
43
+ - Run a Meilisearch instance. [Learn more about Meilisearch cloud](https://www.meilisearch.com/pricing). Alternatively there are many other easy ways [to download and run a Meilisearch instance](https://docs.meilisearch.com/learn/getting_started/installation.html#download-and-launch)
44
44
 
45
45
  #### Data import format
46
46
 
@@ -119,7 +119,7 @@ firebase ext:install meilisearch/firestore-meilisearch --project=[your-project-i
119
119
 
120
120
  ## 🤖 Compatibility with Meilisearch
121
121
 
122
- This package only guarantees the compatibility with the [version v0.28.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.28.0).
122
+ This package only guarantees the compatibility with the [version v0.29.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.29.0).
123
123
 
124
124
  ## ⚙️ Development Workflow and Contributing
125
125
 
@@ -1,7 +1,11 @@
1
1
  import * as firebaseFunctionsTestInit from 'firebase-functions-test'
2
2
  import mockedEnv from 'mocked-env'
3
3
  import { mocked } from 'ts-jest/utils'
4
- import { mockConsoleLog, mockConsoleInfo } from './__mocks__/console'
4
+ import {
5
+ mockConsoleLog,
6
+ mockConsoleInfo,
7
+ mockConsoleError,
8
+ } from './__mocks__/console'
5
9
  import { MeiliSearch } from 'meilisearch'
6
10
  import defaultEnvironment from './data/environment'
7
11
  import defaultDocument from './data/document'
@@ -19,11 +23,9 @@ describe('extension', () => {
19
23
  // Mocking of Meilisearch package
20
24
  const mockedMeilisearch = mocked(MeiliSearch, true)
21
25
  const mockedAddDocuments = jest.fn()
22
- const mockedUpdateDocuments = jest.fn()
23
26
  const mockedDeleteDocument = jest.fn()
24
27
  const mockedIndex = jest.fn(() => ({
25
28
  addDocuments: mockedAddDocuments,
26
- updateDocuments: mockedUpdateDocuments,
27
29
  deleteDocument: mockedDeleteDocument,
28
30
  }))
29
31
  mockedMeilisearch.mockReturnValue({
@@ -107,8 +109,7 @@ describe('extension', () => {
107
109
  expect(mockConsoleInfo).toBeCalledWith(
108
110
  `Creating new document ${
109
111
  afterSnapshot.id as string
110
- } in Meilisearch index ${defaultEnvironment.MEILISEARCH_INDEX_NAME}`,
111
- { _firestore_id: defaultDocument.id, ...afterSnapshot.data() }
112
+ } in Meilisearch index: ${defaultEnvironment.MEILISEARCH_INDEX_NAME}`
112
113
  )
113
114
  expect(mockedAddDocuments).toHaveBeenCalledWith(
114
115
  [
@@ -150,8 +151,7 @@ describe('extension', () => {
150
151
  expect(mockConsoleInfo).toBeCalledWith(
151
152
  `Creating new document ${
152
153
  afterSnapshot.id as string
153
- } in Meilisearch index ${defaultEnvironment.MEILISEARCH_INDEX_NAME}`,
154
- { _firestore_id: defaultDocument.id, ...afterSnapshot.data() }
154
+ } in Meilisearch index: ${defaultEnvironment.MEILISEARCH_INDEX_NAME}`
155
155
  )
156
156
  expect(mockedAddDocuments).toHaveBeenCalledWith(
157
157
  [
@@ -165,6 +165,37 @@ describe('extension', () => {
165
165
  )
166
166
  })
167
167
 
168
+ test('function run on creating document with unauthorized chars in document id', async () => {
169
+ const badId = '@@ !#'
170
+ const beforeSnapshot = firebaseMock.firestore.makeDocumentSnapshot(
171
+ {},
172
+ `collection/{}`
173
+ )
174
+ const afterSnapshot = firebaseMock.firestore.makeDocumentSnapshot(
175
+ { id: badId },
176
+ `collection/${badId}`
177
+ )
178
+ const documentChange = firebaseMock.makeChange(
179
+ beforeSnapshot,
180
+ afterSnapshot
181
+ )
182
+
183
+ await mockExport(documentChange, {
184
+ resource: {
185
+ name: 'test',
186
+ },
187
+ })
188
+
189
+ expect(mockConsoleInfo).toBeCalledWith(
190
+ `Creating new document ${
191
+ afterSnapshot.id as string
192
+ } in Meilisearch index: ${defaultEnvironment.MEILISEARCH_INDEX_NAME}`
193
+ )
194
+ expect(mockConsoleError).toBeCalledWith(
195
+ `Could not create document with id: ${badId}. The document id can only contain case-insensitive alphanumeric characters (abcDEF), hyphens (-) or underscores(_).`
196
+ )
197
+ })
198
+
168
199
  test('function runs with updated data', async () => {
169
200
  const beforeSnapshot = firebaseMock.firestore.makeDocumentSnapshot(
170
201
  { foo: 'bar' },
@@ -191,13 +222,12 @@ describe('extension', () => {
191
222
  config
192
223
  )
193
224
  expect(mockConsoleInfo).toBeCalledWith(
194
- `Updating document ${afterSnapshot.id as string} in Meilisearch index ${
195
- defaultEnvironment.MEILISEARCH_INDEX_NAME
196
- }`,
197
- { _firestore_id: defaultDocument.id, ...afterSnapshot.data() }
225
+ `Updating document ${
226
+ afterSnapshot.id as string
227
+ } in Meilisearch index: ${defaultEnvironment.MEILISEARCH_INDEX_NAME}`
198
228
  )
199
229
  expect(mockConsoleLog).toBeCalledWith('Completed execution of extension')
200
- expect(mockedUpdateDocuments).toHaveBeenCalledWith([
230
+ expect(mockedAddDocuments).toHaveBeenCalledWith([
201
231
  {
202
232
  _firestore_id: defaultDocument.id,
203
233
  ...defaultDocument.document,
@@ -231,17 +261,12 @@ describe('extension', () => {
231
261
  config
232
262
  )
233
263
  expect(mockConsoleInfo).toBeCalledWith(
234
- `Updating document ${afterSnapshot.id as string} in Meilisearch index ${
235
- defaultEnvironment.MEILISEARCH_INDEX_NAME
236
- }`,
237
- {
238
- _firestore_id: defaultDocument.id,
239
- id: '12345',
240
- ...afterSnapshot.data(),
241
- }
264
+ `Updating document ${
265
+ afterSnapshot.id as string
266
+ } in Meilisearch index: ${defaultEnvironment.MEILISEARCH_INDEX_NAME}`
242
267
  )
243
268
  expect(mockConsoleLog).toBeCalledWith('Completed execution of extension')
244
- expect(mockedUpdateDocuments).toHaveBeenCalledWith([
269
+ expect(mockedAddDocuments).toHaveBeenCalledWith([
245
270
  {
246
271
  _firestore_id: defaultDocument.id,
247
272
  id: '12345',
@@ -273,7 +298,7 @@ describe('extension', () => {
273
298
  config
274
299
  )
275
300
  expect(mockConsoleInfo).toBeCalledWith(
276
- `Deleting document ${defaultDocument.id} in Meilisearch index ${defaultEnvironment.MEILISEARCH_INDEX_NAME}`
301
+ `Deleting document ${defaultDocument.id} in Meilisearch index: ${defaultEnvironment.MEILISEARCH_INDEX_NAME}`
277
302
  )
278
303
  expect(mockConsoleLog).toBeCalledWith('Completed execution of extension')
279
304
  expect(mockedDeleteDocument).toHaveBeenCalledWith(defaultDocument.id)
package/lib/index.js CHANGED
@@ -17,11 +17,13 @@ exports.indexingWorker = void 0;
17
17
  * limitations under the License.
18
18
  */
19
19
  const functions = require("firebase-functions");
20
+ const firebase_functions_1 = require("firebase-functions");
20
21
  const create_index_1 = require("./meilisearch/create-index");
21
22
  const util_1 = require("./util");
22
23
  const logs = require("./logs");
23
24
  const adapter_1 = require("./adapter");
24
25
  const config_1 = require("./config");
26
+ const validate_1 = require("./validate");
25
27
  const index = (0, create_index_1.initMeilisearchIndex)(config_1.config.meilisearch);
26
28
  logs.init();
27
29
  /**
@@ -52,9 +54,14 @@ exports.indexingWorker = functions.handler.firestore.document.onWrite(async (cha
52
54
  */
53
55
  async function handleAddDocument(documentId, snapshot) {
54
56
  try {
55
- const document = (0, adapter_1.adaptDocument)(documentId, snapshot);
56
- await index.addDocuments([document], { primaryKey: '_firestore_id' });
57
- logs.addDocument(documentId, document);
57
+ logs.addDocument(documentId);
58
+ if ((0, validate_1.validateDocumentId)(documentId)) {
59
+ const document = (0, adapter_1.adaptDocument)(documentId, snapshot);
60
+ await index.addDocuments([document], { primaryKey: '_firestore_id' });
61
+ }
62
+ else {
63
+ firebase_functions_1.logger.error(`Could not create document with id: ${documentId}. The document id can only contain case-insensitive alphanumeric characters (abcDEF), hyphens (-) or underscores(_).`);
64
+ }
58
65
  }
59
66
  catch (e) {
60
67
  logs.error(e);
@@ -66,8 +73,13 @@ async function handleAddDocument(documentId, snapshot) {
66
73
  */
67
74
  async function handleDeleteDocument(documentId) {
68
75
  try {
69
- await index.deleteDocument(documentId);
70
76
  logs.deleteDocument(documentId);
77
+ if ((0, validate_1.validateDocumentId)(documentId)) {
78
+ await index.deleteDocument(documentId);
79
+ }
80
+ else {
81
+ firebase_functions_1.logger.error(`Could not delete document with id: ${documentId}. The document id can only contain case-insensitive alphanumeric characters (abcDEF), hyphens (-) or underscores(_).`);
82
+ }
71
83
  }
72
84
  catch (e) {
73
85
  logs.error(e);
@@ -80,9 +92,14 @@ async function handleDeleteDocument(documentId) {
80
92
  */
81
93
  async function handleUpdateDocument(documentId, after) {
82
94
  try {
83
- const document = (0, adapter_1.adaptDocument)(documentId, after);
84
- await index.updateDocuments([document]);
85
- logs.updateDocument(documentId, document);
95
+ logs.updateDocument(documentId);
96
+ if ((0, validate_1.validateDocumentId)(documentId)) {
97
+ const document = (0, adapter_1.adaptDocument)(documentId, after);
98
+ await index.addDocuments([document]);
99
+ }
100
+ else {
101
+ firebase_functions_1.logger.error(`Could not update document with id: ${documentId}.The document id can only contain case-insensitive alphanumeric characters (abcDEF), hyphens (-) or underscores(_).`);
102
+ }
86
103
  }
87
104
  catch (e) {
88
105
  logs.error(e);
package/lib/logs.js CHANGED
@@ -50,19 +50,17 @@ exports.complete = complete;
50
50
  /**
51
51
  * Log an addition of a document.
52
52
  * @param {string} id Document id added.
53
- * @param {object} data Data contained in the document.
54
53
  */
55
- function addDocument(id, data) {
56
- firebase_functions_1.logger.info(`Creating new document ${id} in Meilisearch index ${config_1.config.meilisearch.indexUid}`, data);
54
+ function addDocument(id) {
55
+ firebase_functions_1.logger.info(`Creating new document ${id} in Meilisearch index: ${config_1.config.meilisearch.indexUid}`);
57
56
  }
58
57
  exports.addDocument = addDocument;
59
58
  /**
60
59
  * Log an update of a document.
61
60
  * @param {string} id Document id updated.
62
- * @param {object} data Data contained in the document.
63
61
  */
64
- function updateDocument(id, data) {
65
- firebase_functions_1.logger.info(`Updating document ${id} in Meilisearch index ${config_1.config.meilisearch.indexUid}`, data);
62
+ function updateDocument(id) {
63
+ firebase_functions_1.logger.info(`Updating document ${id} in Meilisearch index: ${config_1.config.meilisearch.indexUid}`);
66
64
  }
67
65
  exports.updateDocument = updateDocument;
68
66
  /**
@@ -70,7 +68,7 @@ exports.updateDocument = updateDocument;
70
68
  * @param {string} id Document id deleted.
71
69
  */
72
70
  function deleteDocument(id) {
73
- firebase_functions_1.logger.info(`Deleting document ${id} in Meilisearch index ${config_1.config.meilisearch.indexUid}`);
71
+ firebase_functions_1.logger.info(`Deleting document ${id} in Meilisearch index: ${config_1.config.meilisearch.indexUid}`);
74
72
  }
75
73
  exports.deleteDocument = deleteDocument;
76
74
  /**
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateDocumentId = void 0;
4
+ /**
5
+ * Validate if the format of the document id is compliant with Meilisearch.
6
+ * Based on this documentation: https://docs.meilisearch.com/learn/core_concepts/primary_key.html#formatting-the-document-id
7
+ *
8
+ * @param {string} documentId Document id.
9
+ *
10
+ * @return {boolean} - Wether the document id is properly formatted (true) or not.
11
+ */
12
+ function validateDocumentId(documentId) {
13
+ const wrongChars = documentId.search(/([^a-zA-Z0-9-_]+)/);
14
+ return wrongChars === -1;
15
+ }
16
+ exports.validateDocumentId = validateDocumentId;
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.version = void 0;
4
- exports.version = '0.1.5';
4
+ exports.version = '0.1.7';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firestore-meilisearch",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "scripts": {
5
5
  "lint": "eslint .",
6
6
  "lint:fix": "eslint . --fix",
@@ -25,7 +25,7 @@
25
25
  "firebase-admin": "^9.8.0",
26
26
  "firebase-functions": "^3.16.0",
27
27
  "inquirer": "^8.2.2",
28
- "meilisearch": "^0.27.0"
28
+ "meilisearch": "^0.28.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@babel/preset-typescript": "^7.15.0",
package/src/index.ts CHANGED
@@ -16,13 +16,14 @@
16
16
  */
17
17
 
18
18
  import * as functions from 'firebase-functions'
19
- import { Change } from 'firebase-functions'
19
+ import { Change, logger } from 'firebase-functions'
20
20
  import { DocumentSnapshot } from 'firebase-functions/lib/providers/firestore'
21
21
  import { initMeilisearchIndex } from './meilisearch/create-index'
22
22
  import { getChangeType, getChangedDocumentId, ChangeType } from './util'
23
23
  import * as logs from './logs'
24
24
  import { adaptDocument } from './adapter'
25
25
  import { config } from './config'
26
+ import { validateDocumentId } from './validate'
26
27
 
27
28
  const index = initMeilisearchIndex(config.meilisearch)
28
29
 
@@ -63,9 +64,15 @@ async function handleAddDocument(
63
64
  snapshot: DocumentSnapshot
64
65
  ): Promise<void> {
65
66
  try {
66
- const document = adaptDocument(documentId, snapshot)
67
- await index.addDocuments([document], { primaryKey: '_firestore_id' })
68
- logs.addDocument(documentId, document)
67
+ logs.addDocument(documentId)
68
+ if (validateDocumentId(documentId)) {
69
+ const document = adaptDocument(documentId, snapshot)
70
+ await index.addDocuments([document], { primaryKey: '_firestore_id' })
71
+ } else {
72
+ logger.error(
73
+ `Could not create document with id: ${documentId}. The document id can only contain case-insensitive alphanumeric characters (abcDEF), hyphens (-) or underscores(_).`
74
+ )
75
+ }
69
76
  } catch (e) {
70
77
  logs.error(e as Error)
71
78
  }
@@ -77,8 +84,14 @@ async function handleAddDocument(
77
84
  */
78
85
  async function handleDeleteDocument(documentId: string): Promise<void> {
79
86
  try {
80
- await index.deleteDocument(documentId)
81
87
  logs.deleteDocument(documentId)
88
+ if (validateDocumentId(documentId)) {
89
+ await index.deleteDocument(documentId)
90
+ } else {
91
+ logger.error(
92
+ `Could not delete document with id: ${documentId}. The document id can only contain case-insensitive alphanumeric characters (abcDEF), hyphens (-) or underscores(_).`
93
+ )
94
+ }
82
95
  } catch (e) {
83
96
  logs.error(e as Error)
84
97
  }
@@ -94,9 +107,15 @@ async function handleUpdateDocument(
94
107
  after: DocumentSnapshot
95
108
  ): Promise<void> {
96
109
  try {
97
- const document = adaptDocument(documentId, after)
98
- await index.updateDocuments([document])
99
- logs.updateDocument(documentId, document)
110
+ logs.updateDocument(documentId)
111
+ if (validateDocumentId(documentId)) {
112
+ const document = adaptDocument(documentId, after)
113
+ await index.addDocuments([document])
114
+ } else {
115
+ logger.error(
116
+ `Could not update document with id: ${documentId}.The document id can only contain case-insensitive alphanumeric characters (abcDEF), hyphens (-) or underscores(_).`
117
+ )
118
+ }
100
119
  } catch (e) {
101
120
  logs.error(e as Error)
102
121
  }
package/src/logs.ts CHANGED
@@ -50,24 +50,20 @@ export function complete() {
50
50
  /**
51
51
  * Log an addition of a document.
52
52
  * @param {string} id Document id added.
53
- * @param {object} data Data contained in the document.
54
53
  */
55
- export function addDocument(id: string, data: Record<string, any>) {
54
+ export function addDocument(id: string) {
56
55
  logger.info(
57
- `Creating new document ${id} in Meilisearch index ${config.meilisearch.indexUid}`,
58
- data
56
+ `Creating new document ${id} in Meilisearch index: ${config.meilisearch.indexUid}`
59
57
  )
60
58
  }
61
59
 
62
60
  /**
63
61
  * Log an update of a document.
64
62
  * @param {string} id Document id updated.
65
- * @param {object} data Data contained in the document.
66
63
  */
67
- export function updateDocument(id: string, data: Record<string, any>) {
64
+ export function updateDocument(id: string) {
68
65
  logger.info(
69
- `Updating document ${id} in Meilisearch index ${config.meilisearch.indexUid}`,
70
- data
66
+ `Updating document ${id} in Meilisearch index: ${config.meilisearch.indexUid}`
71
67
  )
72
68
  }
73
69
 
@@ -77,7 +73,7 @@ export function updateDocument(id: string, data: Record<string, any>) {
77
73
  */
78
74
  export function deleteDocument(id: string) {
79
75
  logger.info(
80
- `Deleting document ${id} in Meilisearch index ${config.meilisearch.indexUid}`
76
+ `Deleting document ${id} in Meilisearch index: ${config.meilisearch.indexUid}`
81
77
  )
82
78
  }
83
79
 
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Validate if the format of the document id is compliant with Meilisearch.
3
+ * Based on this documentation: https://docs.meilisearch.com/learn/core_concepts/primary_key.html#formatting-the-document-id
4
+ *
5
+ * @param {string} documentId Document id.
6
+ *
7
+ * @return {boolean} - Wether the document id is properly formatted (true) or not.
8
+ */
9
+ export function validateDocumentId(documentId: string) {
10
+ const wrongChars = documentId.search(/([^a-zA-Z0-9-_]+)/)
11
+
12
+ return wrongChars === -1
13
+ }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '0.1.5'
1
+ export const version = '0.1.7'