firestore-meilisearch 0.1.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/.editorconfig +20 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +26 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +18 -0
- package/.github/ISSUE_TEMPLATE/other.md +7 -0
- package/.github/dependatbot.yml +23 -0
- package/.github/release-draft-template.yml +33 -0
- package/.github/scripts/check-release.sh +42 -0
- package/.github/workflows/publish.yml +30 -0
- package/.github/workflows/release-drafter.yml +16 -0
- package/.github/workflows/test.yml +42 -0
- package/CHANGELOG.md +3 -0
- package/CONTRIBUTING.md +236 -0
- package/LICENSE +201 -0
- package/POSTINSTALL.md +40 -0
- package/PREINSTALL.md +42 -0
- package/README.md +128 -0
- package/bors.toml +8 -0
- package/dataset/firebase-export-metadata.json +8 -0
- package/dataset/firestore_export/all_namespaces/all_kinds/all_namespaces_all_kinds.export_metadata +0 -0
- package/dataset/firestore_export/all_namespaces/all_kinds/output-0 +0 -0
- package/dataset/firestore_export/firestore_export.overall_export_metadata +0 -0
- package/extension.yaml +176 -0
- package/firebase.json +20 -0
- package/functions/.eslintignore +2 -0
- package/functions/.eslintrc.js +54 -0
- package/functions/__tests__/__mocks__/console.ts +7 -0
- package/functions/__tests__/adapter.test.ts +98 -0
- package/functions/__tests__/config.test.ts +130 -0
- package/functions/__tests__/data/document.ts +11 -0
- package/functions/__tests__/data/environment.ts +9 -0
- package/functions/__tests__/functions.test.ts +280 -0
- package/functions/__tests__/jest.setup.ts +1 -0
- package/functions/__tests__/test.types.d.ts +5 -0
- package/functions/__tests__/tsconfig.json +5 -0
- package/functions/__tests__/util.test.ts +200 -0
- package/functions/jest.config.js +12 -0
- package/functions/lib/adapter.js +61 -0
- package/functions/lib/config.js +13 -0
- package/functions/lib/import/config.js +127 -0
- package/functions/lib/import/index.js +93 -0
- package/functions/lib/index.js +90 -0
- package/functions/lib/logs.js +97 -0
- package/functions/lib/meilisearch/create-index.js +17 -0
- package/functions/lib/meilisearch-index.js +17 -0
- package/functions/lib/types.js +2 -0
- package/functions/lib/util.js +47 -0
- package/functions/lib/version.js +4 -0
- package/functions/package.json +53 -0
- package/functions/src/adapter.ts +106 -0
- package/functions/src/config.ts +34 -0
- package/functions/src/import/config.ts +207 -0
- package/functions/src/import/index.ts +115 -0
- package/functions/src/index.ts +103 -0
- package/functions/src/logs.ts +107 -0
- package/functions/src/meilisearch/create-index.ts +20 -0
- package/functions/src/types.ts +8 -0
- package/functions/src/util.ts +63 -0
- package/functions/src/version.ts +1 -0
- package/functions/tsconfig.eslint.json +13 -0
- package/functions/tsconfig.json +23 -0
- package/functions/yarn.lock +5306 -0
- package/guides/IMPORT_EXISTING_DOCUMENTS.md +74 -0
- package/package.json +21 -0
- package/script/version.sh +51 -0
- package/test-params-example.env +9 -0
|
@@ -0,0 +1,103 @@
|
|
|
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 * as functions from 'firebase-functions'
|
|
19
|
+
import { Change } from 'firebase-functions'
|
|
20
|
+
import { DocumentSnapshot } from 'firebase-functions/lib/providers/firestore'
|
|
21
|
+
import { initMeilisearchIndex } from './meilisearch/create-index'
|
|
22
|
+
import { getChangeType, getChangedDocumentId, ChangeType } from './util'
|
|
23
|
+
import * as logs from './logs'
|
|
24
|
+
import { adaptDocument } from './adapter'
|
|
25
|
+
import { config } from './config'
|
|
26
|
+
|
|
27
|
+
const index = initMeilisearchIndex(config.meilisearch)
|
|
28
|
+
|
|
29
|
+
logs.init()
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* IndexingWorker is responsible for aggregating a defined field from a Firestore collection into a Meilisearch index.
|
|
33
|
+
* It is controlled by a Firestore handler.
|
|
34
|
+
*/
|
|
35
|
+
export const indexingWorker = functions.handler.firestore.document.onWrite(
|
|
36
|
+
async (change: Change<DocumentSnapshot>): Promise<void> => {
|
|
37
|
+
logs.start()
|
|
38
|
+
const changeType = getChangeType(change)
|
|
39
|
+
const documentId = getChangedDocumentId(change)
|
|
40
|
+
|
|
41
|
+
switch (changeType) {
|
|
42
|
+
case ChangeType.CREATE:
|
|
43
|
+
await handleAddDocument(documentId, change.after)
|
|
44
|
+
break
|
|
45
|
+
case ChangeType.DELETE:
|
|
46
|
+
await handleDeleteDocument(documentId)
|
|
47
|
+
break
|
|
48
|
+
case ChangeType.UPDATE:
|
|
49
|
+
await handleUpdateDocument(documentId, change.after)
|
|
50
|
+
break
|
|
51
|
+
}
|
|
52
|
+
logs.complete()
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Handle addition of a document in the Meilisearch index.
|
|
58
|
+
* @param {string} documentId Document id to add.
|
|
59
|
+
* @param {Change} snapshot Snapshot of the data contained in the document read from your Firestore database.
|
|
60
|
+
*/
|
|
61
|
+
async function handleAddDocument(
|
|
62
|
+
documentId: string,
|
|
63
|
+
snapshot: DocumentSnapshot
|
|
64
|
+
): Promise<void> {
|
|
65
|
+
try {
|
|
66
|
+
const document = adaptDocument(documentId, snapshot)
|
|
67
|
+
await index.addDocuments([document], { primaryKey: '_firestore_id' })
|
|
68
|
+
logs.addDocument(documentId, document)
|
|
69
|
+
} catch (e) {
|
|
70
|
+
logs.error(e as Error)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Handle deletion of a document in the Meilisearch index.
|
|
76
|
+
* @param {string} documentId Document id to delete.
|
|
77
|
+
*/
|
|
78
|
+
async function handleDeleteDocument(documentId: string): Promise<void> {
|
|
79
|
+
try {
|
|
80
|
+
await index.deleteDocument(documentId)
|
|
81
|
+
logs.deleteDocument(documentId)
|
|
82
|
+
} catch (e) {
|
|
83
|
+
logs.error(e as Error)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Handle update of a document in the Meilisearch index.
|
|
89
|
+
* @param {string} documentId Document id to update.
|
|
90
|
+
* @param {Change} after Snapshot of the data contained in the document read from your Firestore database.
|
|
91
|
+
*/
|
|
92
|
+
async function handleUpdateDocument(
|
|
93
|
+
documentId: string,
|
|
94
|
+
after: DocumentSnapshot
|
|
95
|
+
): Promise<void> {
|
|
96
|
+
try {
|
|
97
|
+
const document = adaptDocument(documentId, after)
|
|
98
|
+
await index.updateDocuments([document])
|
|
99
|
+
logs.updateDocument(documentId, document)
|
|
100
|
+
} catch (e) {
|
|
101
|
+
logs.error(e as Error)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
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 { logger } from 'firebase-functions'
|
|
19
|
+
import { config } from './config'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Initialization logger.
|
|
23
|
+
*/
|
|
24
|
+
export function init() {
|
|
25
|
+
logger.log('Initializing extension with configuration', config)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Start logger.
|
|
30
|
+
*/
|
|
31
|
+
export function start() {
|
|
32
|
+
logger.log('Started execution of extension with configuration', config)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Error logger.
|
|
37
|
+
* @param {Error} err
|
|
38
|
+
*/
|
|
39
|
+
export function error(err: Error) {
|
|
40
|
+
logger.error('Unhandled error occurred during processing:', err)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Complete logger.
|
|
45
|
+
*/
|
|
46
|
+
export function complete() {
|
|
47
|
+
logger.log('Completed execution of extension')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Log an addition of a document.
|
|
52
|
+
* @param {string} id Document id added.
|
|
53
|
+
* @param {object} data Data contained in the document.
|
|
54
|
+
*/
|
|
55
|
+
export function addDocument(id: string, data: Record<string, any>) {
|
|
56
|
+
logger.info(
|
|
57
|
+
`Creating new document ${id} in Meilisearch index ${config.meilisearch.indexUid}`,
|
|
58
|
+
data
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Log an update of a document.
|
|
64
|
+
* @param {string} id Document id updated.
|
|
65
|
+
* @param {object} data Data contained in the document.
|
|
66
|
+
*/
|
|
67
|
+
export function updateDocument(id: string, data: Record<string, any>) {
|
|
68
|
+
logger.info(
|
|
69
|
+
`Updating document ${id} in Meilisearch index ${config.meilisearch.indexUid}`,
|
|
70
|
+
data
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Log a deletion of a document.
|
|
76
|
+
* @param {string} id Document id deleted.
|
|
77
|
+
*/
|
|
78
|
+
export function deleteDocument(id: string) {
|
|
79
|
+
logger.info(
|
|
80
|
+
`Deleting document ${id} in Meilisearch index ${config.meilisearch.indexUid}`
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Log a modification of geoPoint based on whether or not it has the correct naming to enable `geosearch` in Meilisearch.
|
|
86
|
+
* @param {boolean} hasGeoField a boolean value that indicates whether the field is correctly named to enable `geosearch` in Meilisearch.
|
|
87
|
+
*/
|
|
88
|
+
export function infoGeoPoint(hasGeoField: boolean) {
|
|
89
|
+
if (hasGeoField) {
|
|
90
|
+
logger.info(
|
|
91
|
+
`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'`
|
|
92
|
+
)
|
|
93
|
+
} else {
|
|
94
|
+
logger.info(
|
|
95
|
+
`A GeoPoint was found without the field name '_geo' if you want to use the geoSearch with Meilisearch rename it to '_geo'`
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Importation data logger.
|
|
102
|
+
* @param {number} total
|
|
103
|
+
* @param {number} batches
|
|
104
|
+
*/
|
|
105
|
+
export function importData(total: number, batches: number) {
|
|
106
|
+
logger.info(`Imported ${total} documents in ${batches} batches.`)
|
|
107
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { MeiliSearch, Index } from 'meilisearch'
|
|
2
|
+
import { MeilisearchConfig } from '../types'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* initMeilisearchIndex
|
|
6
|
+
* @param {MeilisearchConfig} - Meilisearch configuration
|
|
7
|
+
* @return {Index}
|
|
8
|
+
*/
|
|
9
|
+
export function initMeilisearchIndex({
|
|
10
|
+
host,
|
|
11
|
+
apiKey,
|
|
12
|
+
indexUid,
|
|
13
|
+
}: MeilisearchConfig): Index {
|
|
14
|
+
const client = new MeiliSearch({
|
|
15
|
+
host,
|
|
16
|
+
apiKey,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
return client.index(indexUid)
|
|
20
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
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 { Change } from 'firebase-functions'
|
|
20
|
+
import { config } from './config'
|
|
21
|
+
|
|
22
|
+
export enum ChangeType {
|
|
23
|
+
CREATE,
|
|
24
|
+
DELETE,
|
|
25
|
+
UPDATE,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get type of the modification perform on a document.
|
|
30
|
+
* @param {Change<T>} change The Functions interface for events that change state.
|
|
31
|
+
* @return {ChangeType} Final type of the event.
|
|
32
|
+
*/
|
|
33
|
+
export function getChangeType(change: Change<DocumentSnapshot>): ChangeType {
|
|
34
|
+
if (!change.after.exists) {
|
|
35
|
+
return ChangeType.DELETE
|
|
36
|
+
}
|
|
37
|
+
if (!change.before.exists) {
|
|
38
|
+
return ChangeType.CREATE
|
|
39
|
+
}
|
|
40
|
+
return ChangeType.UPDATE
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get final id of a document after modification.
|
|
45
|
+
* @param {Change<T>} change The Functions interface for events that change state.
|
|
46
|
+
* @return {string} Final state type of the event.
|
|
47
|
+
*/
|
|
48
|
+
export function getChangedDocumentId(change: Change<DocumentSnapshot>): string {
|
|
49
|
+
if (change.after.exists) {
|
|
50
|
+
return change.after.id
|
|
51
|
+
}
|
|
52
|
+
return change.before.id
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns the MEILISEARCH_FIELDS_TO_INDEX value from the config file and formats it.
|
|
57
|
+
* @return {string[]} An array of fields.
|
|
58
|
+
*/
|
|
59
|
+
export function getFieldsToIndex(): string[] {
|
|
60
|
+
return config.meilisearch.fieldsToIndex
|
|
61
|
+
? config.meilisearch.fieldsToIndex.split(/[ ,]+/)
|
|
62
|
+
: []
|
|
63
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const version = '0.1.0'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"skipLibCheck": true,
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"noImplicitReturns": true,
|
|
6
|
+
"noImplicitAny": false,
|
|
7
|
+
"outDir": "lib",
|
|
8
|
+
"sourceMap": false,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"target": "es2018",
|
|
11
|
+
"types": [
|
|
12
|
+
"jest",
|
|
13
|
+
"node",
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"compileOnSave": true,
|
|
17
|
+
"include": [
|
|
18
|
+
"src",
|
|
19
|
+
],
|
|
20
|
+
"exclude": [
|
|
21
|
+
"node_modules",
|
|
22
|
+
]
|
|
23
|
+
}
|