firestore-meilisearch 0.1.11 → 0.3.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/.eslintrc.js +11 -0
- package/README.md +7 -2
- package/__tests__/__snapshots__/config.test.ts.snap +27 -0
- package/__tests__/__snapshots__/util.test.ts.snap +3 -0
- package/__tests__/adapter.test.ts +40 -17
- package/__tests__/functions.test.ts +3 -2
- package/__tests__/util.test.ts +16 -12
- package/jest.config.js +7 -4
- package/lib/import/index.js +2 -2
- package/lib/index.js +10 -8
- package/lib/meilisearch-adapter.js +90 -0
- package/lib/util.js +1 -34
- package/lib/version.js +1 -1
- package/package.json +9 -8
- package/src/import/index.ts +3 -3
- package/src/index.ts +12 -12
- package/src/meilisearch-adapter.ts +120 -0
- package/src/util.ts +1 -38
- package/src/version.ts +1 -1
- package/lib/adapter.js +0 -53
- package/lib/meilisearch-index.js +0 -17
- package/src/adapter.ts +0 -95
package/.eslintrc.js
CHANGED
|
@@ -51,4 +51,15 @@ module.exports = {
|
|
|
51
51
|
},
|
|
52
52
|
],
|
|
53
53
|
},
|
|
54
|
+
settings: {
|
|
55
|
+
'import/parsers': {
|
|
56
|
+
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
|
57
|
+
},
|
|
58
|
+
'import/resolver': {
|
|
59
|
+
typescript: {
|
|
60
|
+
alwaysTryTypes: true, // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
|
|
61
|
+
project: './tsconfig.json',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
54
65
|
}
|
package/README.md
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
<h4 align="center">
|
|
10
10
|
<a href="https://github.com/meilisearch/meilisearch">Meilisearch</a> |
|
|
11
|
+
<a href="https://www.meilisearch.com/cloud?utm_campaign=oss&utm_source=github&utm_medium=firestore-meilisearch">Meilisearch Cloud</a> |
|
|
11
12
|
<a href="https://docs.meilisearch.com">Documentation</a> |
|
|
12
|
-
<a href="https://
|
|
13
|
+
<a href="https://discord.meilisearch.com">Discord</a> |
|
|
13
14
|
<a href="https://roadmap.meilisearch.com/tabs/1-under-consideration">Roadmap</a> |
|
|
14
15
|
<a href="https://www.meilisearch.com">Website</a> |
|
|
15
16
|
<a href="https://docs.meilisearch.com/faq">FAQ</a>
|
|
@@ -35,6 +36,10 @@ This extension listens to each creation, update, or deletion of your documents t
|
|
|
35
36
|
|
|
36
37
|
Note that this extension only listens for changes to _documents_ in a specific collection, but not changes in any _subcollection_. However, you can install additional instances of this extension to listen to other collections in your Firestore database.
|
|
37
38
|
|
|
39
|
+
## ⚡ Supercharge your Meilisearch experience
|
|
40
|
+
|
|
41
|
+
Say goodbye to server deployment and manual updates with [Meilisearch Cloud](https://www.meilisearch.com/cloud?utm_campaign=oss&utm_source=github&utm_medium=firestore-meilisearch). Get started with a 14-day free trial! No credit card required.
|
|
42
|
+
|
|
38
43
|
#### Additional setup
|
|
39
44
|
|
|
40
45
|
Before installing this extension, you'll need to:
|
|
@@ -118,7 +123,7 @@ firebase ext:install meilisearch/firestore-meilisearch --project=[your-project-i
|
|
|
118
123
|
|
|
119
124
|
## 🤖 Compatibility with Meilisearch
|
|
120
125
|
|
|
121
|
-
This package
|
|
126
|
+
This package guarantees compatibility with [version v1.x of Meilisearch](https://github.com/meilisearch/meilisearch/releases/latest), but some features may not be present. Please check the [issues](https://github.com/meilisearch/firestore-meilisearch/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22+label%3Aenhancement) for more info.
|
|
122
127
|
|
|
123
128
|
## ⚙️ Development Workflow and Contributing
|
|
124
129
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`extensions config Test MeilisearchIndex parameters param exists 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"description": "What Meilisearch index do you want to index your data in?",
|
|
6
|
+
"example": "example: my_index",
|
|
7
|
+
"label": "Meilisearch Index Name",
|
|
8
|
+
"param": "MEILISEARCH_INDEX_NAME",
|
|
9
|
+
"required": true,
|
|
10
|
+
"type": "string",
|
|
11
|
+
"validationErrorMessage": "Must be a valid Index format. Index uid can be of type integer or string only composed of alphanumeric characters, hyphens (-) and underscores (_). Check out our guide on [index creation](https://docs.meilisearch.com/learn/core_concepts/indexes.html#index-creation).",
|
|
12
|
+
"validationRegex": "^[0-9A-Za-z_-]+$",
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
exports[`extensions config Test fieldsToIndex parameter param exists 1`] = `
|
|
17
|
+
{
|
|
18
|
+
"default": "",
|
|
19
|
+
"description": "What fields do you want to index in Meilisearch? Create a comma-separated list of the field names, or leave it blank to include all fields. The id field is always indexed even when omitted from the list.",
|
|
20
|
+
"example": "example: name,description,...",
|
|
21
|
+
"label": "Fields to index in Meilisearch",
|
|
22
|
+
"param": "MEILISEARCH_FIELDS_TO_INDEX",
|
|
23
|
+
"required": false,
|
|
24
|
+
"validationErrorMessage": "Fields must be given through a comma-separated list.",
|
|
25
|
+
"validationRegex": "^[^,]?[a-zA-Z-_0-9,]*[^,]$",
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import * as firebaseFunctionsTestInit from 'firebase-functions-test'
|
|
2
2
|
import { mockConsoleInfo } from './__mocks__/console'
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import * as firestore from 'firebase-admin/firestore'
|
|
4
|
+
import {
|
|
5
|
+
adaptDocumentForMeilisearch,
|
|
6
|
+
adaptFieldsForMeilisearch,
|
|
7
|
+
} from '../src/meilisearch-adapter'
|
|
5
8
|
import defaultDocument from './data/document'
|
|
6
9
|
|
|
7
10
|
// Mocking of Firebase functions
|
|
@@ -15,7 +18,9 @@ describe('extensions process', () => {
|
|
|
15
18
|
`docs/${defaultDocument.id}`
|
|
16
19
|
)
|
|
17
20
|
|
|
18
|
-
expect(
|
|
21
|
+
expect(
|
|
22
|
+
adaptDocumentForMeilisearch(defaultDocument.id, snapshot, '')
|
|
23
|
+
).toStrictEqual({
|
|
19
24
|
_firestore_id: defaultDocument.id,
|
|
20
25
|
...defaultDocument.document,
|
|
21
26
|
})
|
|
@@ -27,7 +32,9 @@ describe('extensions process', () => {
|
|
|
27
32
|
`docs/${defaultDocument.id}`
|
|
28
33
|
)
|
|
29
34
|
|
|
30
|
-
expect(
|
|
35
|
+
expect(
|
|
36
|
+
adaptDocumentForMeilisearch(defaultDocument.id, snapshot, '')
|
|
37
|
+
).toStrictEqual({
|
|
31
38
|
_firestore_id: defaultDocument.id,
|
|
32
39
|
id: '12345',
|
|
33
40
|
...defaultDocument.document,
|
|
@@ -41,7 +48,7 @@ describe('extensions process', () => {
|
|
|
41
48
|
)
|
|
42
49
|
|
|
43
50
|
expect(
|
|
44
|
-
|
|
51
|
+
adaptDocumentForMeilisearch(
|
|
45
52
|
defaultDocument.id,
|
|
46
53
|
snapshot,
|
|
47
54
|
'title,overview,release_date'
|
|
@@ -57,21 +64,27 @@ describe('extensions process', () => {
|
|
|
57
64
|
|
|
58
65
|
describe('adaptValues', () => {
|
|
59
66
|
test('adaptValues an id value', () => {
|
|
60
|
-
expect(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
expect(
|
|
68
|
+
adaptFieldsForMeilisearch(
|
|
69
|
+
{ id: defaultDocument.id } as firestore.DocumentData,
|
|
70
|
+
'id'
|
|
71
|
+
)
|
|
72
|
+
).toStrictEqual({ id: defaultDocument.id })
|
|
64
73
|
})
|
|
65
74
|
test('adaptValues a geo point value', () => {
|
|
66
75
|
const geoPoint = new firestore.GeoPoint(48.866667, 2.333333)
|
|
67
76
|
|
|
68
|
-
expect(
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
expect(
|
|
78
|
+
adaptFieldsForMeilisearch(
|
|
79
|
+
{ _geo: geoPoint } as firestore.DocumentData,
|
|
80
|
+
'_geo'
|
|
81
|
+
)
|
|
82
|
+
).toStrictEqual({
|
|
83
|
+
_geo: {
|
|
71
84
|
lat: 48.866667,
|
|
72
85
|
lng: 2.333333,
|
|
73
86
|
},
|
|
74
|
-
|
|
87
|
+
})
|
|
75
88
|
expect(mockConsoleInfo).toBeCalledWith(
|
|
76
89
|
`A GeoPoint was found with the field name '_geo' for compatibility with Meilisearch the field 'latitude' was renamed to 'lat' and the field 'longitude' to 'lng'`
|
|
77
90
|
)
|
|
@@ -79,13 +92,23 @@ describe('extensions process', () => {
|
|
|
79
92
|
test('adaptValues a wrong geo point value', () => {
|
|
80
93
|
const geoPoint = new firestore.GeoPoint(48.866667, 2.333333)
|
|
81
94
|
|
|
82
|
-
expect(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
95
|
+
expect(
|
|
96
|
+
adaptFieldsForMeilisearch(
|
|
97
|
+
{ wrong_geo: geoPoint } as firestore.DocumentData,
|
|
98
|
+
'wrong_geo'
|
|
99
|
+
)
|
|
100
|
+
).toStrictEqual({ wrong_geo: geoPoint })
|
|
86
101
|
expect(mockConsoleInfo).toBeCalledWith(
|
|
87
102
|
`A GeoPoint was found without the field name '_geo' if you want to use the geoSearch with Meilisearch rename it to '_geo'`
|
|
88
103
|
)
|
|
89
104
|
})
|
|
105
|
+
test('adaptValues with a _geo field at null', () => {
|
|
106
|
+
expect(
|
|
107
|
+
adaptFieldsForMeilisearch(
|
|
108
|
+
{ _geo: null } as firestore.DocumentData,
|
|
109
|
+
'_geo'
|
|
110
|
+
)
|
|
111
|
+
).toStrictEqual({})
|
|
112
|
+
})
|
|
90
113
|
})
|
|
91
114
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as firebaseFunctionsTestInit from 'firebase-functions-test'
|
|
2
2
|
import mockedEnv from 'mocked-env'
|
|
3
|
-
import { mocked } from '
|
|
3
|
+
import { mocked } from 'jest-mock'
|
|
4
4
|
import {
|
|
5
5
|
mockConsoleLog,
|
|
6
6
|
mockConsoleInfo,
|
|
@@ -21,7 +21,7 @@ describe('extension', () => {
|
|
|
21
21
|
let restoreEnv
|
|
22
22
|
|
|
23
23
|
// Mocking of Meilisearch package
|
|
24
|
-
const mockedMeilisearch = mocked(MeiliSearch
|
|
24
|
+
const mockedMeilisearch = mocked(MeiliSearch)
|
|
25
25
|
const mockedAddDocuments = jest.fn()
|
|
26
26
|
const mockedDeleteDocument = jest.fn()
|
|
27
27
|
const mockedIndex = jest.fn(() => ({
|
|
@@ -42,6 +42,7 @@ describe('extension', () => {
|
|
|
42
42
|
beforeEach(() => {
|
|
43
43
|
restoreEnv = mockedEnv(defaultEnvironment)
|
|
44
44
|
config = require('../src/config').config
|
|
45
|
+
config.collectionPath = 'collection'
|
|
45
46
|
})
|
|
46
47
|
afterEach(() => restoreEnv())
|
|
47
48
|
|
package/__tests__/util.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as firebaseFunctionsTestInit from 'firebase-functions-test'
|
|
2
2
|
import mockedEnv from 'mocked-env'
|
|
3
|
-
import {
|
|
3
|
+
import { ChangeType, getChangedDocumentId, getChangeType } from '../src/util'
|
|
4
4
|
import defaultEnvironment from './data/environment'
|
|
5
5
|
|
|
6
6
|
describe('getChangeType', () => {
|
|
@@ -132,7 +132,7 @@ describe('getChangedDocumentId', () => {
|
|
|
132
132
|
})
|
|
133
133
|
|
|
134
134
|
describe('getFieldsToIndex', () => {
|
|
135
|
-
let
|
|
135
|
+
let adapter
|
|
136
136
|
let restoreEnv
|
|
137
137
|
let mockParseFieldsToIndex
|
|
138
138
|
const config = global.config
|
|
@@ -149,32 +149,36 @@ describe('getFieldsToIndex', () => {
|
|
|
149
149
|
})
|
|
150
150
|
|
|
151
151
|
test('return empty list', () => {
|
|
152
|
-
|
|
153
|
-
mockParseFieldsToIndex =
|
|
152
|
+
adapter = require('../src/meilisearch-adapter')
|
|
153
|
+
mockParseFieldsToIndex = adapter.parseFieldsToIndex()
|
|
154
154
|
expect(mockParseFieldsToIndex).toMatchObject([])
|
|
155
155
|
})
|
|
156
156
|
|
|
157
157
|
test('return list with one field', () => {
|
|
158
|
-
|
|
159
|
-
mockParseFieldsToIndex =
|
|
158
|
+
adapter = require('../src/meilisearch-adapter')
|
|
159
|
+
mockParseFieldsToIndex = adapter.parseFieldsToIndex('field')
|
|
160
160
|
expect(mockParseFieldsToIndex).toMatchObject(['field'])
|
|
161
161
|
})
|
|
162
162
|
|
|
163
163
|
test('return list with multiple fields', () => {
|
|
164
|
-
|
|
165
|
-
mockParseFieldsToIndex =
|
|
164
|
+
adapter = require('../src/meilisearch-adapter')
|
|
165
|
+
mockParseFieldsToIndex = adapter.parseFieldsToIndex('field1,field2,field3')
|
|
166
166
|
expect(mockParseFieldsToIndex).toMatchObject(['field1', 'field2', 'field3'])
|
|
167
167
|
})
|
|
168
168
|
|
|
169
169
|
test('return list with multiple fields and spaces', () => {
|
|
170
|
-
|
|
171
|
-
mockParseFieldsToIndex =
|
|
170
|
+
adapter = require('../src/meilisearch-adapter')
|
|
171
|
+
mockParseFieldsToIndex = adapter.parseFieldsToIndex(
|
|
172
|
+
'field1, field2, field3'
|
|
173
|
+
)
|
|
172
174
|
expect(mockParseFieldsToIndex).toMatchObject(['field1', 'field2', 'field3'])
|
|
173
175
|
})
|
|
174
176
|
|
|
175
177
|
test('return list of fiels with underscore', () => {
|
|
176
|
-
|
|
177
|
-
mockParseFieldsToIndex =
|
|
178
|
+
adapter = require('../src/meilisearch-adapter')
|
|
179
|
+
mockParseFieldsToIndex = adapter.parseFieldsToIndex(
|
|
180
|
+
'field_1,field_2,field_3'
|
|
181
|
+
)
|
|
178
182
|
expect(mockParseFieldsToIndex).toMatchObject([
|
|
179
183
|
'field_1',
|
|
180
184
|
'field_2',
|
package/jest.config.js
CHANGED
|
@@ -3,10 +3,13 @@ process.env.FIREBASE_CONFIG = '{}'
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
rootDir: './',
|
|
5
5
|
preset: 'ts-jest',
|
|
6
|
-
|
|
7
|
-
'
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
transform: {
|
|
7
|
+
'^.+\\.[tj]sx?$': [
|
|
8
|
+
'ts-jest',
|
|
9
|
+
{
|
|
10
|
+
tsconfig: '<rootDir>/__tests__/tsconfig.json',
|
|
11
|
+
},
|
|
12
|
+
],
|
|
10
13
|
},
|
|
11
14
|
testEnvironment: 'node',
|
|
12
15
|
testMatch: ['**/__tests__/*.test.ts'],
|
package/lib/import/index.js
CHANGED
|
@@ -19,7 +19,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
19
19
|
const admin = require("firebase-admin");
|
|
20
20
|
const config_1 = require("./config");
|
|
21
21
|
const logs = require("../logs");
|
|
22
|
-
const
|
|
22
|
+
const meilisearch_adapter_1 = require("../meilisearch-adapter");
|
|
23
23
|
const create_index_1 = require("../meilisearch/create-index");
|
|
24
24
|
const run = async () => {
|
|
25
25
|
// Retrieve all arguments from the commande line.
|
|
@@ -80,7 +80,7 @@ async function retrieveCollectionFromFirestore(database, config, index) {
|
|
|
80
80
|
*/
|
|
81
81
|
async function sendDocumentsToMeilisearch(docs, index, fieldsToIndex) {
|
|
82
82
|
const document = docs.map(snapshot => {
|
|
83
|
-
return (0,
|
|
83
|
+
return (0, meilisearch_adapter_1.adaptDocumentForMeilisearch)(snapshot.id, snapshot, fieldsToIndex);
|
|
84
84
|
});
|
|
85
85
|
try {
|
|
86
86
|
await index.addDocuments(document, { primaryKey: '_firestore_id' });
|
package/lib/index.js
CHANGED
|
@@ -21,7 +21,7 @@ const firebase_functions_1 = require("firebase-functions");
|
|
|
21
21
|
const create_index_1 = require("./meilisearch/create-index");
|
|
22
22
|
const util_1 = require("./util");
|
|
23
23
|
const logs = require("./logs");
|
|
24
|
-
const
|
|
24
|
+
const meilisearch_adapter_1 = require("./meilisearch-adapter");
|
|
25
25
|
const config_1 = require("./config");
|
|
26
26
|
const validate_1 = require("./validate");
|
|
27
27
|
const index = (0, create_index_1.initMeilisearchIndex)(config_1.config.meilisearch);
|
|
@@ -30,19 +30,21 @@ logs.init();
|
|
|
30
30
|
* IndexingWorker is responsible for aggregating a defined field from a Firestore collection into a Meilisearch index.
|
|
31
31
|
* It is controlled by a Firestore handler.
|
|
32
32
|
*/
|
|
33
|
-
exports.indexingWorker = functions.
|
|
33
|
+
exports.indexingWorker = functions.firestore
|
|
34
|
+
.document(config_1.config.collectionPath + '/{documentId}')
|
|
35
|
+
.onWrite(async (snapshot) => {
|
|
34
36
|
logs.start();
|
|
35
|
-
const changeType = (0, util_1.getChangeType)(
|
|
36
|
-
const documentId = (0, util_1.getChangedDocumentId)(
|
|
37
|
+
const changeType = (0, util_1.getChangeType)(snapshot);
|
|
38
|
+
const documentId = (0, util_1.getChangedDocumentId)(snapshot);
|
|
37
39
|
switch (changeType) {
|
|
38
40
|
case util_1.ChangeType.CREATE:
|
|
39
|
-
await handleAddDocument(documentId,
|
|
41
|
+
await handleAddDocument(documentId, snapshot.after);
|
|
40
42
|
break;
|
|
41
43
|
case util_1.ChangeType.DELETE:
|
|
42
44
|
await handleDeleteDocument(documentId);
|
|
43
45
|
break;
|
|
44
46
|
case util_1.ChangeType.UPDATE:
|
|
45
|
-
await handleUpdateDocument(documentId,
|
|
47
|
+
await handleUpdateDocument(documentId, snapshot.after);
|
|
46
48
|
break;
|
|
47
49
|
}
|
|
48
50
|
logs.complete();
|
|
@@ -56,7 +58,7 @@ async function handleAddDocument(documentId, snapshot) {
|
|
|
56
58
|
try {
|
|
57
59
|
logs.addDocument(documentId);
|
|
58
60
|
if ((0, validate_1.validateDocumentId)(documentId)) {
|
|
59
|
-
const document = (0,
|
|
61
|
+
const document = (0, meilisearch_adapter_1.adaptDocumentForMeilisearch)(documentId, snapshot, config_1.config.meilisearch.fieldsToIndex || '');
|
|
60
62
|
const { taskUid } = await index.addDocuments([document], {
|
|
61
63
|
primaryKey: '_firestore_id',
|
|
62
64
|
});
|
|
@@ -98,7 +100,7 @@ async function handleUpdateDocument(documentId, after) {
|
|
|
98
100
|
try {
|
|
99
101
|
logs.updateDocument(documentId);
|
|
100
102
|
if ((0, validate_1.validateDocumentId)(documentId)) {
|
|
101
|
-
const document = (0,
|
|
103
|
+
const document = (0, meilisearch_adapter_1.adaptDocumentForMeilisearch)(documentId, after, config_1.config.meilisearch.fieldsToIndex || '');
|
|
102
104
|
const { taskUid } = await index.addDocuments([document]);
|
|
103
105
|
firebase_functions_1.logger.info(`Document update request for document with ID ${documentId} added to task list (task ID ${taskUid}).`);
|
|
104
106
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.adaptDocumentForMeilisearch = exports.adaptFieldsForMeilisearch = exports.parseFieldsToIndex = exports.isAFieldToIndex = void 0;
|
|
4
|
+
const firestore = require("firebase-admin/firestore");
|
|
5
|
+
const logs_1 = require("./logs");
|
|
6
|
+
/**
|
|
7
|
+
* Adapts GeoPoint Firestore instance to fit with Meilisearch geo point.
|
|
8
|
+
* @param {firestore.GeoPoint} geoPoint GeoPoint Firestore object.
|
|
9
|
+
* @return {MeilisearchGeoPoint} A properly formatted geo point for Meilisearch.
|
|
10
|
+
*/
|
|
11
|
+
function adaptGeoPoint(geoPoint) {
|
|
12
|
+
return {
|
|
13
|
+
lat: geoPoint.latitude,
|
|
14
|
+
lng: geoPoint.longitude,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if the field is added to the document send to Meilisearch.
|
|
19
|
+
*
|
|
20
|
+
* @param {string[]} fieldsToIndex
|
|
21
|
+
* @param {string} key
|
|
22
|
+
* @return {boolean} true if it is a field that should be indexed in Meilisearch
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
function isAFieldToIndex(fieldsToIndex, key) {
|
|
26
|
+
if (fieldsToIndex.length === 0 ||
|
|
27
|
+
fieldsToIndex.includes('*') ||
|
|
28
|
+
fieldsToIndex.includes(key)) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
exports.isAFieldToIndex = isAFieldToIndex;
|
|
34
|
+
/**
|
|
35
|
+
* Parse the fieldsToIndex string into an array.
|
|
36
|
+
*
|
|
37
|
+
* @param {string} fieldsToIndex
|
|
38
|
+
* @return {string[]} An array of fields.
|
|
39
|
+
*/
|
|
40
|
+
function parseFieldsToIndex(fieldsToIndex) {
|
|
41
|
+
return fieldsToIndex ? fieldsToIndex.split(/[ ,]+/) : [];
|
|
42
|
+
}
|
|
43
|
+
exports.parseFieldsToIndex = parseFieldsToIndex;
|
|
44
|
+
/**
|
|
45
|
+
* Update special fields to Meilisearch compatible format
|
|
46
|
+
* @param {firestore.DocumentData} document
|
|
47
|
+
* @param {string[]} rawFieldsToIndex
|
|
48
|
+
* @return {firestore.DocumentData} A properly formatted array of field and value.
|
|
49
|
+
*/
|
|
50
|
+
function adaptFieldsForMeilisearch(document, rawFieldsToIndex) {
|
|
51
|
+
const fieldsToIndex = parseFieldsToIndex(rawFieldsToIndex);
|
|
52
|
+
return Object.keys(document).reduce((doc, currentField) => {
|
|
53
|
+
const value = document[currentField];
|
|
54
|
+
if (!isAFieldToIndex(fieldsToIndex, currentField))
|
|
55
|
+
return doc;
|
|
56
|
+
if (value instanceof firestore.GeoPoint) {
|
|
57
|
+
if (currentField === '_geo') {
|
|
58
|
+
(0, logs_1.infoGeoPoint)(true);
|
|
59
|
+
return {
|
|
60
|
+
...doc,
|
|
61
|
+
_geo: adaptGeoPoint(value),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
(0, logs_1.infoGeoPoint)(false);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (currentField === '_geo') {
|
|
69
|
+
return doc;
|
|
70
|
+
}
|
|
71
|
+
return { ...doc, [currentField]: value };
|
|
72
|
+
}, {});
|
|
73
|
+
}
|
|
74
|
+
exports.adaptFieldsForMeilisearch = adaptFieldsForMeilisearch;
|
|
75
|
+
/**
|
|
76
|
+
* Adapts documents from the Firestore database to Meilisearch compatible documents.
|
|
77
|
+
* @param {string} documentId Document id.
|
|
78
|
+
* @param {DocumentSnapshot} snapshot Snapshot of the data contained in the document read from your Firestore database.
|
|
79
|
+
* @param {string} rawFieldsToIndex Value of the setting `FIELDS_TO_INDEX`
|
|
80
|
+
* @return {Record<string, any>} A properly formatted document to be added or updated in Meilisearch.
|
|
81
|
+
*/
|
|
82
|
+
function adaptDocumentForMeilisearch(documentId, snapshot, rawFieldsToIndex) {
|
|
83
|
+
const data = snapshot.data() || {};
|
|
84
|
+
if ('_firestore_id' in data) {
|
|
85
|
+
delete data.id;
|
|
86
|
+
}
|
|
87
|
+
const adaptedDoc = adaptFieldsForMeilisearch(data, rawFieldsToIndex);
|
|
88
|
+
return { _firestore_id: documentId, ...adaptedDoc };
|
|
89
|
+
}
|
|
90
|
+
exports.adaptDocumentForMeilisearch = adaptDocumentForMeilisearch;
|
package/lib/util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getChangedDocumentId = exports.getChangeType = exports.ChangeType = void 0;
|
|
4
4
|
var ChangeType;
|
|
5
5
|
(function (ChangeType) {
|
|
6
6
|
ChangeType[ChangeType["CREATE"] = 0] = "CREATE";
|
|
@@ -34,36 +34,3 @@ function getChangedDocumentId(change) {
|
|
|
34
34
|
return change.before.id;
|
|
35
35
|
}
|
|
36
36
|
exports.getChangedDocumentId = getChangedDocumentId;
|
|
37
|
-
/**
|
|
38
|
-
* Parse the fieldsToIndex string into an array.
|
|
39
|
-
*
|
|
40
|
-
* @param {string} fieldsToIndex
|
|
41
|
-
* @return {string[]} An array of fields.
|
|
42
|
-
*/
|
|
43
|
-
function parseFieldsToIndex(fieldsToIndex) {
|
|
44
|
-
return fieldsToIndex ? fieldsToIndex.split(/[ ,]+/) : [];
|
|
45
|
-
}
|
|
46
|
-
exports.parseFieldsToIndex = parseFieldsToIndex;
|
|
47
|
-
/**
|
|
48
|
-
* Remove unwanted fields from the document before it is send to Meilisearch.
|
|
49
|
-
*
|
|
50
|
-
* @param {string[]} fieldsToIndex
|
|
51
|
-
* @param {Record<string, any>} document
|
|
52
|
-
* @return {Record<string, any>} sanitized document
|
|
53
|
-
*
|
|
54
|
-
*/
|
|
55
|
-
function sanitizeDocuments(fieldsToIndex, document) {
|
|
56
|
-
if (fieldsToIndex.length === 0) {
|
|
57
|
-
return document;
|
|
58
|
-
}
|
|
59
|
-
if (fieldsToIndex.includes('*')) {
|
|
60
|
-
return document;
|
|
61
|
-
}
|
|
62
|
-
for (const key in document) {
|
|
63
|
-
if (!fieldsToIndex.includes(key)) {
|
|
64
|
-
delete document[key];
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return document;
|
|
68
|
-
}
|
|
69
|
-
exports.sanitizeDocuments = sanitizeDocuments;
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firestore-meilisearch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"lint": "eslint .",
|
|
6
6
|
"lint:fix": "eslint . --fix",
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
"test:coverage": "jest --coverage"
|
|
18
18
|
},
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
20
|
+
"node": ">=20.0.0"
|
|
21
21
|
},
|
|
22
22
|
"main": "lib/index.js",
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"commander": "^9.1.0",
|
|
25
|
-
"firebase-admin": "^
|
|
26
|
-
"firebase-functions": "^
|
|
25
|
+
"firebase-admin": "^11.5.0",
|
|
26
|
+
"firebase-functions": "^4.2.1",
|
|
27
27
|
"inquirer": "^8.2.2",
|
|
28
28
|
"meilisearch": "^0.30.0"
|
|
29
29
|
},
|
|
@@ -35,16 +35,17 @@
|
|
|
35
35
|
"eslint": "^7.6.0",
|
|
36
36
|
"eslint-config-google": "^0.14.0",
|
|
37
37
|
"eslint-config-prettier": "^8.3.0",
|
|
38
|
+
"eslint-import-resolver-typescript": "^3.5.3",
|
|
38
39
|
"eslint-plugin-import": "^2.24.2",
|
|
39
40
|
"eslint-plugin-jest": "^24.4.2",
|
|
40
41
|
"eslint-plugin-prettier": "^4.0.0",
|
|
41
|
-
"firebase-functions-test": "^0.
|
|
42
|
-
"jest": "^
|
|
43
|
-
"jest-mock": "^
|
|
42
|
+
"firebase-functions-test": "^3.0.0",
|
|
43
|
+
"jest": "^29.4.3",
|
|
44
|
+
"jest-mock": "^29.4.3",
|
|
44
45
|
"js-yaml": "^4.1.0",
|
|
45
46
|
"mocked-env": "^1.3.5",
|
|
46
47
|
"prettier": "^2.4.1",
|
|
47
|
-
"ts-jest": "^
|
|
48
|
+
"ts-jest": "^29.0.5",
|
|
48
49
|
"ts-node": "^10.2.1",
|
|
49
50
|
"typescript": "^4.4.3"
|
|
50
51
|
},
|
package/src/import/index.ts
CHANGED
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import * as admin from 'firebase-admin'
|
|
20
|
-
import { DocumentSnapshot } from 'firebase-functions/lib/providers/firestore'
|
|
20
|
+
import { DocumentSnapshot } from 'firebase-functions/lib/v1/providers/firestore'
|
|
21
21
|
import { CLIConfig, parseConfig } from './config'
|
|
22
22
|
import * as logs from '../logs'
|
|
23
|
-
import {
|
|
23
|
+
import { adaptDocumentForMeilisearch } from '../meilisearch-adapter'
|
|
24
24
|
import { initMeilisearchIndex } from '../meilisearch/create-index'
|
|
25
25
|
import { Index } from '../types'
|
|
26
26
|
|
|
@@ -106,7 +106,7 @@ async function sendDocumentsToMeilisearch(
|
|
|
106
106
|
fieldsToIndex: string
|
|
107
107
|
): Promise<number> {
|
|
108
108
|
const document = docs.map(snapshot => {
|
|
109
|
-
return
|
|
109
|
+
return adaptDocumentForMeilisearch(snapshot.id, snapshot, fieldsToIndex)
|
|
110
110
|
})
|
|
111
111
|
try {
|
|
112
112
|
await index.addDocuments(document, { primaryKey: '_firestore_id' })
|
package/src/index.ts
CHANGED
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
|
|
18
18
|
import * as functions from 'firebase-functions'
|
|
19
19
|
import { Change, logger } from 'firebase-functions'
|
|
20
|
-
import { DocumentSnapshot } from 'firebase-functions/lib/providers/firestore'
|
|
20
|
+
import { DocumentSnapshot } from 'firebase-functions/lib/v1/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
|
-
import {
|
|
24
|
+
import { adaptDocumentForMeilisearch } from './meilisearch-adapter'
|
|
25
25
|
import { config } from './config'
|
|
26
26
|
import { validateDocumentId } from './validate'
|
|
27
27
|
|
|
@@ -33,26 +33,26 @@ logs.init()
|
|
|
33
33
|
* IndexingWorker is responsible for aggregating a defined field from a Firestore collection into a Meilisearch index.
|
|
34
34
|
* It is controlled by a Firestore handler.
|
|
35
35
|
*/
|
|
36
|
-
export const indexingWorker = functions.
|
|
37
|
-
|
|
36
|
+
export const indexingWorker = functions.firestore
|
|
37
|
+
.document(config.collectionPath + '/{documentId}')
|
|
38
|
+
.onWrite(async (snapshot: Change<DocumentSnapshot>): Promise<void> => {
|
|
38
39
|
logs.start()
|
|
39
|
-
const changeType = getChangeType(
|
|
40
|
-
const documentId = getChangedDocumentId(
|
|
40
|
+
const changeType = getChangeType(snapshot)
|
|
41
|
+
const documentId = getChangedDocumentId(snapshot)
|
|
41
42
|
|
|
42
43
|
switch (changeType) {
|
|
43
44
|
case ChangeType.CREATE:
|
|
44
|
-
await handleAddDocument(documentId,
|
|
45
|
+
await handleAddDocument(documentId, snapshot.after)
|
|
45
46
|
break
|
|
46
47
|
case ChangeType.DELETE:
|
|
47
48
|
await handleDeleteDocument(documentId)
|
|
48
49
|
break
|
|
49
50
|
case ChangeType.UPDATE:
|
|
50
|
-
await handleUpdateDocument(documentId,
|
|
51
|
+
await handleUpdateDocument(documentId, snapshot.after)
|
|
51
52
|
break
|
|
52
53
|
}
|
|
53
54
|
logs.complete()
|
|
54
|
-
}
|
|
55
|
-
)
|
|
55
|
+
})
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Handle addition of a document in the Meilisearch index.
|
|
@@ -66,7 +66,7 @@ async function handleAddDocument(
|
|
|
66
66
|
try {
|
|
67
67
|
logs.addDocument(documentId)
|
|
68
68
|
if (validateDocumentId(documentId)) {
|
|
69
|
-
const document =
|
|
69
|
+
const document = adaptDocumentForMeilisearch(
|
|
70
70
|
documentId,
|
|
71
71
|
snapshot,
|
|
72
72
|
config.meilisearch.fieldsToIndex || ''
|
|
@@ -123,7 +123,7 @@ async function handleUpdateDocument(
|
|
|
123
123
|
try {
|
|
124
124
|
logs.updateDocument(documentId)
|
|
125
125
|
if (validateDocumentId(documentId)) {
|
|
126
|
-
const document =
|
|
126
|
+
const document = adaptDocumentForMeilisearch(
|
|
127
127
|
documentId,
|
|
128
128
|
after,
|
|
129
129
|
config.meilisearch.fieldsToIndex || ''
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2022 Meilisearch
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { DocumentSnapshot } from 'firebase-functions/lib/v1/providers/firestore'
|
|
19
|
+
import * as firestore from 'firebase-admin/firestore'
|
|
20
|
+
import { infoGeoPoint } from './logs'
|
|
21
|
+
|
|
22
|
+
type MeilisearchGeoPoint = {
|
|
23
|
+
lat: number
|
|
24
|
+
lng: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Adapts GeoPoint Firestore instance to fit with Meilisearch geo point.
|
|
29
|
+
* @param {firestore.GeoPoint} geoPoint GeoPoint Firestore object.
|
|
30
|
+
* @return {MeilisearchGeoPoint} A properly formatted geo point for Meilisearch.
|
|
31
|
+
*/
|
|
32
|
+
function adaptGeoPoint(geoPoint: firestore.GeoPoint): MeilisearchGeoPoint {
|
|
33
|
+
return {
|
|
34
|
+
lat: geoPoint.latitude,
|
|
35
|
+
lng: geoPoint.longitude,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if the field is added to the document send to Meilisearch.
|
|
41
|
+
*
|
|
42
|
+
* @param {string[]} fieldsToIndex
|
|
43
|
+
* @param {string} key
|
|
44
|
+
* @return {boolean} true if it is a field that should be indexed in Meilisearch
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
export function isAFieldToIndex(fieldsToIndex: string[], key: string): boolean {
|
|
48
|
+
if (
|
|
49
|
+
fieldsToIndex.length === 0 ||
|
|
50
|
+
fieldsToIndex.includes('*') ||
|
|
51
|
+
fieldsToIndex.includes(key)
|
|
52
|
+
) {
|
|
53
|
+
return true
|
|
54
|
+
}
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Parse the fieldsToIndex string into an array.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} fieldsToIndex
|
|
62
|
+
* @return {string[]} An array of fields.
|
|
63
|
+
*/
|
|
64
|
+
export function parseFieldsToIndex(fieldsToIndex: string): string[] {
|
|
65
|
+
return fieldsToIndex ? fieldsToIndex.split(/[ ,]+/) : []
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Update special fields to Meilisearch compatible format
|
|
70
|
+
* @param {firestore.DocumentData} document
|
|
71
|
+
* @param {string[]} rawFieldsToIndex
|
|
72
|
+
* @return {firestore.DocumentData} A properly formatted array of field and value.
|
|
73
|
+
*/
|
|
74
|
+
export function adaptFieldsForMeilisearch(
|
|
75
|
+
document: firestore.DocumentData,
|
|
76
|
+
rawFieldsToIndex: string
|
|
77
|
+
): firestore.DocumentData {
|
|
78
|
+
const fieldsToIndex = parseFieldsToIndex(rawFieldsToIndex)
|
|
79
|
+
|
|
80
|
+
return Object.keys(document).reduce((doc, currentField) => {
|
|
81
|
+
const value = document[currentField]
|
|
82
|
+
|
|
83
|
+
if (!isAFieldToIndex(fieldsToIndex, currentField)) return doc
|
|
84
|
+
if (value instanceof firestore.GeoPoint) {
|
|
85
|
+
if (currentField === '_geo') {
|
|
86
|
+
infoGeoPoint(true)
|
|
87
|
+
return {
|
|
88
|
+
...doc,
|
|
89
|
+
_geo: adaptGeoPoint(value),
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
infoGeoPoint(false)
|
|
93
|
+
}
|
|
94
|
+
} else if (currentField === '_geo') {
|
|
95
|
+
return doc
|
|
96
|
+
}
|
|
97
|
+
return { ...doc, [currentField]: value }
|
|
98
|
+
}, {})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Adapts documents from the Firestore database to Meilisearch compatible documents.
|
|
103
|
+
* @param {string} documentId Document id.
|
|
104
|
+
* @param {DocumentSnapshot} snapshot Snapshot of the data contained in the document read from your Firestore database.
|
|
105
|
+
* @param {string} rawFieldsToIndex Value of the setting `FIELDS_TO_INDEX`
|
|
106
|
+
* @return {Record<string, any>} A properly formatted document to be added or updated in Meilisearch.
|
|
107
|
+
*/
|
|
108
|
+
export function adaptDocumentForMeilisearch(
|
|
109
|
+
documentId: string,
|
|
110
|
+
snapshot: DocumentSnapshot,
|
|
111
|
+
rawFieldsToIndex: string
|
|
112
|
+
): Record<string, any> {
|
|
113
|
+
const data = snapshot.data() || {}
|
|
114
|
+
if ('_firestore_id' in data) {
|
|
115
|
+
delete data.id
|
|
116
|
+
}
|
|
117
|
+
const adaptedDoc = adaptFieldsForMeilisearch(data, rawFieldsToIndex)
|
|
118
|
+
|
|
119
|
+
return { _firestore_id: documentId, ...adaptedDoc }
|
|
120
|
+
}
|
package/src/util.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { DocumentSnapshot } from 'firebase-functions/lib/providers/firestore'
|
|
18
|
+
import { DocumentSnapshot } from 'firebase-functions/lib/v1/providers/firestore'
|
|
19
19
|
import { Change } from 'firebase-functions'
|
|
20
20
|
|
|
21
21
|
export enum ChangeType {
|
|
@@ -50,40 +50,3 @@ export function getChangedDocumentId(change: Change<DocumentSnapshot>): string {
|
|
|
50
50
|
}
|
|
51
51
|
return change.before.id
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Parse the fieldsToIndex string into an array.
|
|
56
|
-
*
|
|
57
|
-
* @param {string} fieldsToIndex
|
|
58
|
-
* @return {string[]} An array of fields.
|
|
59
|
-
*/
|
|
60
|
-
export function parseFieldsToIndex(fieldsToIndex: string): string[] {
|
|
61
|
-
return fieldsToIndex ? fieldsToIndex.split(/[ ,]+/) : []
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Remove unwanted fields from the document before it is send to Meilisearch.
|
|
66
|
-
*
|
|
67
|
-
* @param {string[]} fieldsToIndex
|
|
68
|
-
* @param {Record<string, any>} document
|
|
69
|
-
* @return {Record<string, any>} sanitized document
|
|
70
|
-
*
|
|
71
|
-
*/
|
|
72
|
-
export function sanitizeDocuments(
|
|
73
|
-
fieldsToIndex: string[],
|
|
74
|
-
document: Record<string, any>
|
|
75
|
-
): Record<string, any> {
|
|
76
|
-
if (fieldsToIndex.length === 0) {
|
|
77
|
-
return document
|
|
78
|
-
}
|
|
79
|
-
if (fieldsToIndex.includes('*')) {
|
|
80
|
-
return document
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
for (const key in document) {
|
|
84
|
-
if (!fieldsToIndex.includes(key)) {
|
|
85
|
-
delete document[key]
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return document
|
|
89
|
-
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '0.
|
|
1
|
+
export const version = '0.3.0'
|
package/lib/adapter.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.adaptValues = exports.adaptDocument = void 0;
|
|
4
|
-
const firestore_1 = require("firebase-admin/lib/firestore");
|
|
5
|
-
const util_1 = require("./util");
|
|
6
|
-
const logs = require("./logs");
|
|
7
|
-
/**
|
|
8
|
-
* Adapts documents from the Firestore database to Meilisearch compatible documents.
|
|
9
|
-
* @param {string} documentId Document id.
|
|
10
|
-
* @param {DocumentSnapshot} snapshot Snapshot of the data contained in the document read from your Firestore database.
|
|
11
|
-
* @param {string} fieldsToIndex list of fields added in the document send to Meilisearch.
|
|
12
|
-
* @return {Record<string, any>} A properly formatted document to be added or updated in Meilisearch.
|
|
13
|
-
*/
|
|
14
|
-
function adaptDocument(documentId, snapshot, fieldsToIndex) {
|
|
15
|
-
const fields = (0, util_1.parseFieldsToIndex)(fieldsToIndex);
|
|
16
|
-
const data = snapshot.data() || {};
|
|
17
|
-
if ('_firestore_id' in data) {
|
|
18
|
-
delete data.id;
|
|
19
|
-
}
|
|
20
|
-
const document = (0, util_1.sanitizeDocuments)(fields, data);
|
|
21
|
-
return { _firestore_id: documentId, ...document };
|
|
22
|
-
}
|
|
23
|
-
exports.adaptDocument = adaptDocument;
|
|
24
|
-
/**
|
|
25
|
-
* Checks and adapts each values to be compatible with Meilisearch documents.
|
|
26
|
-
* @param {string} field
|
|
27
|
-
* @param {FirestoreRow} value
|
|
28
|
-
* @return {[string,FirestoreRow]} A properly formatted array of field and value.
|
|
29
|
-
*/
|
|
30
|
-
function adaptValues(field, value) {
|
|
31
|
-
if (value instanceof firestore_1.firestore.GeoPoint) {
|
|
32
|
-
if (field === '_geo') {
|
|
33
|
-
logs.infoGeoPoint(true);
|
|
34
|
-
return [field, adaptGeoPoint(value)];
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
logs.infoGeoPoint(false);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return [field, value];
|
|
41
|
-
}
|
|
42
|
-
exports.adaptValues = adaptValues;
|
|
43
|
-
/**
|
|
44
|
-
* Adapts GeoPoint Firestore instance to fit with Meilisearch geo point.
|
|
45
|
-
* @param {firestore.GeoPoint} geoPoint GeoPoint Firestore object.
|
|
46
|
-
* @return {MeilisearchGeoPoint} A properly formatted geo point for Meilisearch.
|
|
47
|
-
*/
|
|
48
|
-
const adaptGeoPoint = (geoPoint) => {
|
|
49
|
-
return {
|
|
50
|
-
lat: geoPoint.latitude,
|
|
51
|
-
lng: geoPoint.longitude,
|
|
52
|
-
};
|
|
53
|
-
};
|
package/lib/meilisearch-index.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createMeiliSearchIndex = void 0;
|
|
4
|
-
const meilisearch_1 = require("meilisearch");
|
|
5
|
-
/**
|
|
6
|
-
* createMeiliSearchIndex
|
|
7
|
-
* @param {MeiliSearchConfig}
|
|
8
|
-
* @return {Index}
|
|
9
|
-
*/
|
|
10
|
-
function createMeiliSearchIndex({ host, apiKey, indexUid, }) {
|
|
11
|
-
const client = new meilisearch_1.MeiliSearch({
|
|
12
|
-
host,
|
|
13
|
-
apiKey,
|
|
14
|
-
});
|
|
15
|
-
return client.index(indexUid);
|
|
16
|
-
}
|
|
17
|
-
exports.createMeiliSearchIndex = createMeiliSearchIndex;
|
package/src/adapter.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
/*
|
|
3
|
-
* Copyright 2022 Meilisearch
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* https://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import { DocumentSnapshot } from 'firebase-functions/lib/providers/firestore'
|
|
19
|
-
import { firestore } from 'firebase-admin/lib/firestore'
|
|
20
|
-
import { parseFieldsToIndex, sanitizeDocuments } from './util'
|
|
21
|
-
import * as logs from './logs'
|
|
22
|
-
|
|
23
|
-
type MeilisearchGeoPoint = {
|
|
24
|
-
lat: number
|
|
25
|
-
lng: number
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
type FirestoreRow =
|
|
29
|
-
| null
|
|
30
|
-
| boolean
|
|
31
|
-
| number
|
|
32
|
-
| string
|
|
33
|
-
| firestore.DocumentReference
|
|
34
|
-
| firestore.GeoPoint
|
|
35
|
-
| firestore.Timestamp
|
|
36
|
-
| Array<any>
|
|
37
|
-
| Map<any, any>
|
|
38
|
-
| MeilisearchGeoPoint
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Adapts documents from the Firestore database to Meilisearch compatible documents.
|
|
42
|
-
* @param {string} documentId Document id.
|
|
43
|
-
* @param {DocumentSnapshot} snapshot Snapshot of the data contained in the document read from your Firestore database.
|
|
44
|
-
* @param {string} fieldsToIndex list of fields added in the document send to Meilisearch.
|
|
45
|
-
* @return {Record<string, any>} A properly formatted document to be added or updated in Meilisearch.
|
|
46
|
-
*/
|
|
47
|
-
export function adaptDocument(
|
|
48
|
-
documentId: string,
|
|
49
|
-
snapshot: DocumentSnapshot,
|
|
50
|
-
fieldsToIndex: string
|
|
51
|
-
): Record<string, any> {
|
|
52
|
-
const fields = parseFieldsToIndex(fieldsToIndex)
|
|
53
|
-
|
|
54
|
-
const data = snapshot.data() || {}
|
|
55
|
-
if ('_firestore_id' in data) {
|
|
56
|
-
delete data.id
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const document = sanitizeDocuments(fields, data)
|
|
60
|
-
|
|
61
|
-
return { _firestore_id: documentId, ...document }
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Checks and adapts each values to be compatible with Meilisearch documents.
|
|
66
|
-
* @param {string} field
|
|
67
|
-
* @param {FirestoreRow} value
|
|
68
|
-
* @return {[string,FirestoreRow]} A properly formatted array of field and value.
|
|
69
|
-
*/
|
|
70
|
-
export function adaptValues(
|
|
71
|
-
field: string,
|
|
72
|
-
value: FirestoreRow
|
|
73
|
-
): [string, FirestoreRow | MeilisearchGeoPoint] {
|
|
74
|
-
if (value instanceof firestore.GeoPoint) {
|
|
75
|
-
if (field === '_geo') {
|
|
76
|
-
logs.infoGeoPoint(true)
|
|
77
|
-
return [field, adaptGeoPoint(value)]
|
|
78
|
-
} else {
|
|
79
|
-
logs.infoGeoPoint(false)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return [field, value]
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Adapts GeoPoint Firestore instance to fit with Meilisearch geo point.
|
|
87
|
-
* @param {firestore.GeoPoint} geoPoint GeoPoint Firestore object.
|
|
88
|
-
* @return {MeilisearchGeoPoint} A properly formatted geo point for Meilisearch.
|
|
89
|
-
*/
|
|
90
|
-
const adaptGeoPoint = (geoPoint: firestore.GeoPoint): MeilisearchGeoPoint => {
|
|
91
|
-
return {
|
|
92
|
-
lat: geoPoint.latitude,
|
|
93
|
-
lng: geoPoint.longitude,
|
|
94
|
-
}
|
|
95
|
-
}
|