@medusajs/search 0.0.1

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 (56) hide show
  1. package/README.md +1 -0
  2. package/dist/index.d.ts +8 -0
  3. package/dist/index.js +24 -0
  4. package/dist/initialize/index.d.ts +8 -0
  5. package/dist/initialize/index.js +17 -0
  6. package/dist/joiner-config.d.ts +2 -0
  7. package/dist/joiner-config.js +4 -0
  8. package/dist/loaders/connection.d.ts +4 -0
  9. package/dist/loaders/connection.js +41 -0
  10. package/dist/loaders/container.d.ts +4 -0
  11. package/dist/loaders/container.js +21 -0
  12. package/dist/loaders/index.d.ts +2 -0
  13. package/dist/loaders/index.js +10 -0
  14. package/dist/migrations/Migration20231019174230.d.ts +4 -0
  15. package/dist/migrations/Migration20231019174230.js +18 -0
  16. package/dist/models/catalog-relation.d.ts +15 -0
  17. package/dist/models/catalog-relation.js +72 -0
  18. package/dist/models/catalog.d.ts +11 -0
  19. package/dist/models/catalog.js +55 -0
  20. package/dist/models/index.d.ts +2 -0
  21. package/dist/models/index.js +18 -0
  22. package/dist/module-definition.d.ts +2 -0
  23. package/dist/module-definition.js +15 -0
  24. package/dist/scripts/bin/run-migration-down.d.ts +3 -0
  25. package/dist/scripts/bin/run-migration-down.js +32 -0
  26. package/dist/scripts/bin/run-migration-up.d.ts +3 -0
  27. package/dist/scripts/bin/run-migration-up.js +32 -0
  28. package/dist/scripts/bin/run-seed.d.ts +3 -0
  29. package/dist/scripts/bin/run-seed.js +38 -0
  30. package/dist/scripts/index.d.ts +2 -0
  31. package/dist/scripts/index.js +18 -0
  32. package/dist/scripts/migration-down.d.ts +10 -0
  33. package/dist/scripts/migration-down.js +52 -0
  34. package/dist/scripts/migration-up.d.ts +10 -0
  35. package/dist/scripts/migration-up.js +56 -0
  36. package/dist/scripts/seed-data/index.d.ts +8 -0
  37. package/dist/scripts/seed-data/index.js +138 -0
  38. package/dist/scripts/seed.d.ts +5 -0
  39. package/dist/scripts/seed.js +65 -0
  40. package/dist/services/index.d.ts +1 -0
  41. package/dist/services/index.js +8 -0
  42. package/dist/services/postgres-provider.d.ts +126 -0
  43. package/dist/services/postgres-provider.js +441 -0
  44. package/dist/services/search-module-service.d.ts +31 -0
  45. package/dist/services/search-module-service.js +66 -0
  46. package/dist/types/index.d.ts +122 -0
  47. package/dist/types/index.js +7 -0
  48. package/dist/utils/build-config.d.ts +21 -0
  49. package/dist/utils/build-config.js +437 -0
  50. package/dist/utils/create-partitions.d.ts +3 -0
  51. package/dist/utils/create-partitions.js +27 -0
  52. package/dist/utils/index.d.ts +3 -0
  53. package/dist/utils/index.js +19 -0
  54. package/dist/utils/query-builder.d.ts +28 -0
  55. package/dist/utils/query-builder.js +375 -0
  56. package/package.json +67 -0
@@ -0,0 +1,441 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _PostgresProvider_isReady_;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.PostgresProvider = void 0;
16
+ const utils_1 = require("@medusajs/utils");
17
+ const _models_1 = require("../models");
18
+ const utils_2 = require("../utils");
19
+ class PostgresProvider {
20
+ get remoteQuery_() {
21
+ return this.container_.remoteQuery;
22
+ }
23
+ constructor(container, options, moduleOptions) {
24
+ _PostgresProvider_isReady_.set(this, void 0);
25
+ this.eventActionToMethodMap_ = {
26
+ created: "onCreate",
27
+ updated: "onUpdate",
28
+ deleted: "onDelete",
29
+ attached: "onAttach",
30
+ detached: "onDetach",
31
+ };
32
+ this.container_ = container;
33
+ this.moduleOptions_ = moduleOptions;
34
+ this.schemaObjectRepresentation_ = options.schemaObjectRepresentation;
35
+ this.schemaEntitiesMap_ = options.entityMap;
36
+ // Add a new column for each key that can be found in the jsonb data column to perform indexes and query on it.
37
+ // So far, the execution time is about the same
38
+ /*;(async () => {
39
+ const query = [
40
+ ...new Set(
41
+ Object.keys(this.schemaObjectRepresentation_)
42
+ .filter(
43
+ (key) =>
44
+ ![
45
+ "_serviceNameModuleConfigMap",
46
+ "_schemaPropertiesMap",
47
+ ].includes(key)
48
+ )
49
+ .map((key) => {
50
+ return this.schemaObjectRepresentation_[key].fields.filter(
51
+ (field) => !field.includes(".")
52
+ )
53
+ })
54
+ .flat()
55
+ ),
56
+ ].map(
57
+ (field) =>
58
+ "ALTER TABLE catalog ADD IF NOT EXISTS " +
59
+ field +
60
+ " text GENERATED ALWAYS AS (NEW.data->>'" +
61
+ field +
62
+ "') STORED"
63
+ )
64
+ await this.container_.manager.execute(query.join(";"))
65
+ })()*/
66
+ }
67
+ async onApplicationStart() {
68
+ let initalizedOk = () => { };
69
+ let initalizedNok = () => { };
70
+ __classPrivateFieldSet(this, _PostgresProvider_isReady_, new Promise((resolve, reject) => {
71
+ initalizedOk = resolve;
72
+ initalizedNok = reject;
73
+ }), "f");
74
+ await (0, utils_2.createPartitions)(this.schemaObjectRepresentation_, this.container_.manager)
75
+ .then(initalizedOk)
76
+ .catch(initalizedNok);
77
+ }
78
+ static parseData(data, schemaEntityObjectRepresentation) {
79
+ const data_ = Array.isArray(data) ? data : [data];
80
+ // Always keep the id in the entity properties
81
+ const entityProperties = ["id"];
82
+ const parentsProperties = {};
83
+ /**
84
+ * Split fields into entity properties and parents properties
85
+ */
86
+ schemaEntityObjectRepresentation.fields.forEach((field) => {
87
+ var _a;
88
+ if (field.includes(".")) {
89
+ const parentAlias = field.split(".")[0];
90
+ const parentSchemaObjectRepresentation = schemaEntityObjectRepresentation.parents.find((parent) => parent.ref.alias === parentAlias);
91
+ if (!parentSchemaObjectRepresentation) {
92
+ throw new Error(`SearchModule error, unable to parse data for ${schemaEntityObjectRepresentation.entity}. The parent schema object representation could not be found for the alias ${parentAlias} for the entity ${schemaEntityObjectRepresentation.entity}.`);
93
+ }
94
+ parentsProperties[_a = parentSchemaObjectRepresentation.ref.entity] ?? (parentsProperties[_a] = []);
95
+ parentsProperties[parentSchemaObjectRepresentation.ref.entity].push(field);
96
+ }
97
+ else {
98
+ entityProperties.push(field);
99
+ }
100
+ });
101
+ return {
102
+ data: data_,
103
+ entityProperties,
104
+ parentsProperties,
105
+ };
106
+ }
107
+ static parseMessageData(message) {
108
+ const isMessageShape = (0, utils_1.isDefined)(message?.body);
109
+ if (!isMessageShape) {
110
+ return;
111
+ }
112
+ const result = {
113
+ action: "",
114
+ data: [],
115
+ ids: [],
116
+ };
117
+ result.action = message.body.metadata.action;
118
+ result.data = message.body.data;
119
+ result.data = Array.isArray(result.data) ? result.data : [result.data];
120
+ result.ids = result.data.map((d) => d.id);
121
+ return result;
122
+ }
123
+ async query(selection, options) {
124
+ await __classPrivateFieldGet(this, _PostgresProvider_isReady_, "f");
125
+ let hasPagination = false;
126
+ if (typeof options?.take === "number" ||
127
+ typeof options?.skip === "number") {
128
+ hasPagination = true;
129
+ }
130
+ const connection = this.container_.manager.getConnection();
131
+ const qb = new utils_2.QueryBuilder({
132
+ schema: this.schemaObjectRepresentation_,
133
+ entityMap: this.schemaEntitiesMap_,
134
+ knex: connection.getKnex(),
135
+ selector: selection,
136
+ options,
137
+ });
138
+ const sql = qb.buildQuery(hasPagination, !!options?.keepFilteredEntities);
139
+ let resultset = await connection.execute(sql);
140
+ if (options?.keepFilteredEntities) {
141
+ const mainEntity = Object.keys(selection.select)[0];
142
+ const ids = resultset.map((r) => r[`${mainEntity}.id`]);
143
+ if (ids.length) {
144
+ const selection_ = {
145
+ select: selection.select,
146
+ joinWhere: selection.joinWhere,
147
+ where: {
148
+ [`${mainEntity}.id`]: ids,
149
+ },
150
+ };
151
+ return await this.query(selection_);
152
+ }
153
+ }
154
+ return qb.buildObjectFromResultset(resultset);
155
+ }
156
+ async queryAndCount(selection, options) {
157
+ await __classPrivateFieldGet(this, _PostgresProvider_isReady_, "f");
158
+ const connection = this.container_.manager.getConnection();
159
+ const qb = new utils_2.QueryBuilder({
160
+ schema: this.schemaObjectRepresentation_,
161
+ entityMap: this.schemaEntitiesMap_,
162
+ knex: connection.getKnex(),
163
+ selector: selection,
164
+ options,
165
+ });
166
+ const sql = qb.buildQuery(true, !!options?.keepFilteredEntities);
167
+ let resultset = await connection.execute(sql);
168
+ const count = +(resultset[0]?.count ?? 0);
169
+ if (options?.keepFilteredEntities) {
170
+ const mainEntity = Object.keys(selection.select)[0];
171
+ const ids = resultset.map((r) => r[`${mainEntity}.id`]);
172
+ if (ids.length) {
173
+ const selection_ = {
174
+ select: selection.select,
175
+ joinWhere: selection.joinWhere,
176
+ where: {
177
+ [`${mainEntity}.id`]: ids,
178
+ },
179
+ };
180
+ return [await this.query(selection_), count];
181
+ }
182
+ }
183
+ return [qb.buildObjectFromResultset(resultset), count];
184
+ }
185
+ consumeEvent(schemaEntityObjectRepresentation) {
186
+ return async (data, eventName) => {
187
+ await __classPrivateFieldGet(this, _PostgresProvider_isReady_, "f");
188
+ const data_ = Array.isArray(data) ? data : [data];
189
+ let ids = data_.map((d) => d.id);
190
+ let action = eventName.split(".").pop() || "";
191
+ const parsedMessage = PostgresProvider.parseMessageData(data);
192
+ if (parsedMessage) {
193
+ action = parsedMessage.action;
194
+ ids = parsedMessage.ids;
195
+ }
196
+ const { fields, alias } = schemaEntityObjectRepresentation;
197
+ const entityData = await this.remoteQuery_((0, utils_1.remoteQueryObjectFromString)({
198
+ entryPoint: alias,
199
+ variables: {
200
+ filters: {
201
+ id: ids,
202
+ },
203
+ },
204
+ fields,
205
+ }));
206
+ const argument = {
207
+ entity: schemaEntityObjectRepresentation.entity,
208
+ data: entityData,
209
+ schemaEntityObjectRepresentation,
210
+ };
211
+ const targetMethod = this.eventActionToMethodMap_[action];
212
+ if (!targetMethod) {
213
+ return;
214
+ }
215
+ await this[targetMethod](argument);
216
+ };
217
+ }
218
+ /**
219
+ * Create the catalog entry and the catalog relation entry when this event is emitted.
220
+ * @param entity
221
+ * @param data
222
+ * @param schemaEntityObjectRepresentation
223
+ * @protected
224
+ */
225
+ async onCreate({ entity, data, schemaEntityObjectRepresentation, }) {
226
+ await this.container_.manager.transactional(async (em) => {
227
+ const catalogRepository = em.getRepository(_models_1.Catalog);
228
+ const catalogRelationRepository = em.getRepository(_models_1.CatalogRelation);
229
+ const { data: data_, entityProperties, parentsProperties, } = PostgresProvider.parseData(data, schemaEntityObjectRepresentation);
230
+ /**
231
+ * Loop through the data and create catalog entries for each entity as well as the
232
+ * catalog relation entries if the entity has parents
233
+ */
234
+ for (const entityData of data_) {
235
+ /**
236
+ * Clean the entity data to only keep the properties that are defined in the schema
237
+ */
238
+ const cleanedEntityData = entityProperties.reduce((acc, property) => {
239
+ acc[property] = entityData[property];
240
+ return acc;
241
+ }, {});
242
+ await catalogRepository.upsert({
243
+ id: cleanedEntityData.id,
244
+ name: entity,
245
+ data: cleanedEntityData,
246
+ });
247
+ /**
248
+ * Retrieve the parents to attach it to the catalog entry.
249
+ */
250
+ for (const [parentEntity, parentProperties] of Object.entries(parentsProperties)) {
251
+ const parentAlias = parentProperties[0].split(".")[0];
252
+ const parentData = entityData[parentAlias];
253
+ if (!parentData) {
254
+ continue;
255
+ }
256
+ const parentDataCollection = Array.isArray(parentData)
257
+ ? parentData
258
+ : [parentData];
259
+ for (const parentData_ of parentDataCollection) {
260
+ await catalogRepository.upsert({
261
+ id: parentData_.id,
262
+ name: parentEntity,
263
+ data: parentData_,
264
+ });
265
+ const parentCatalogRelationEntry = catalogRelationRepository.create({
266
+ parent_id: parentData_.id,
267
+ parent_name: parentEntity,
268
+ child_id: cleanedEntityData.id,
269
+ child_name: entity,
270
+ pivot: `${parentEntity}-${entity}`,
271
+ });
272
+ catalogRelationRepository.persist(parentCatalogRelationEntry);
273
+ }
274
+ }
275
+ }
276
+ await em.flush();
277
+ });
278
+ }
279
+ /**
280
+ * Update the catalog entry when this event is emitted.
281
+ * @param entity
282
+ * @param data
283
+ * @param schemaEntityObjectRepresentation
284
+ * @protected
285
+ */
286
+ async onUpdate({ entity, data, schemaEntityObjectRepresentation, }) {
287
+ await this.container_.manager.transactional(async (em) => {
288
+ const catalogRepository = em.getRepository(_models_1.Catalog);
289
+ const { data: data_, entityProperties } = PostgresProvider.parseData(data, schemaEntityObjectRepresentation);
290
+ await catalogRepository.upsertMany(data_.map((entityData) => {
291
+ return {
292
+ id: entityData.id,
293
+ name: entity,
294
+ data: entityProperties.reduce((acc, property) => {
295
+ acc[property] = entityData[property];
296
+ return acc;
297
+ }, {}),
298
+ };
299
+ }));
300
+ });
301
+ }
302
+ /**
303
+ * Delete the catalog entry when this event is emitted.
304
+ * @param entity
305
+ * @param data
306
+ * @param schemaEntityObjectRepresentation
307
+ * @protected
308
+ */
309
+ async onDelete({ entity, data, schemaEntityObjectRepresentation, }) {
310
+ await this.container_.manager.transactional(async (em) => {
311
+ const catalogRepository = em.getRepository(_models_1.Catalog);
312
+ const catalogRelationRepository = em.getRepository(_models_1.CatalogRelation);
313
+ const { data: data_ } = PostgresProvider.parseData(data, schemaEntityObjectRepresentation);
314
+ const ids = data_.map((entityData) => entityData.id);
315
+ await catalogRepository.nativeDelete({
316
+ id: { $in: ids },
317
+ name: entity,
318
+ });
319
+ await catalogRelationRepository.nativeDelete({
320
+ $or: [
321
+ {
322
+ parent_id: { $in: ids },
323
+ parent_name: entity,
324
+ },
325
+ {
326
+ child_id: { $in: ids },
327
+ child_name: entity,
328
+ },
329
+ ],
330
+ });
331
+ });
332
+ }
333
+ /**
334
+ * event emitted from the link modules to attach a link entity to its parent and child entities from the linked modules.
335
+ * @param entity
336
+ * @param data
337
+ * @param schemaEntityObjectRepresentation
338
+ * @protected
339
+ */
340
+ async onAttach({ entity, data, schemaEntityObjectRepresentation, }) {
341
+ await this.container_.manager.transactional(async (em) => {
342
+ const catalogRepository = em.getRepository(_models_1.Catalog);
343
+ const catalogRelationRepository = em.getRepository(_models_1.CatalogRelation);
344
+ const { data: data_, entityProperties } = PostgresProvider.parseData(data, schemaEntityObjectRepresentation);
345
+ /**
346
+ * Retrieve the property that represent the foreign key related to the parent entity of the link entity.
347
+ * Then from the service name of the parent entity, retrieve the entity name using the linkable keys.
348
+ */
349
+ const parentPropertyId = schemaEntityObjectRepresentation.moduleConfig.relationships[0]
350
+ .foreignKey;
351
+ const parentServiceName = schemaEntityObjectRepresentation.moduleConfig.relationships[0]
352
+ .serviceName;
353
+ const parentEntityName = this.schemaObjectRepresentation_._serviceNameModuleConfigMap[parentServiceName].linkableKeys?.[parentPropertyId];
354
+ if (!parentEntityName) {
355
+ throw new Error(`SearchModule error, unable to handle attach event for ${entity}. The parent entity name could not be found using the linkable keys from the module ${parentServiceName}.`);
356
+ }
357
+ /**
358
+ * Retrieve the property that represent the foreign key related to the child entity of the link entity.
359
+ * Then from the service name of the child entity, retrieve the entity name using the linkable keys.
360
+ */
361
+ const childPropertyId = schemaEntityObjectRepresentation.moduleConfig.relationships[1]
362
+ .foreignKey;
363
+ const childServiceName = schemaEntityObjectRepresentation.moduleConfig.relationships[1]
364
+ .serviceName;
365
+ const childEntityName = this.schemaObjectRepresentation_._serviceNameModuleConfigMap[childServiceName].linkableKeys?.[childPropertyId];
366
+ if (!childEntityName) {
367
+ throw new Error(`SearchModule error, unable to handle attach event for ${entity}. The child entity name could not be found using the linkable keys from the module ${childServiceName}.`);
368
+ }
369
+ for (const entityData of data_) {
370
+ /**
371
+ * Clean the link entity data to only keep the properties that are defined in the schema
372
+ */
373
+ const cleanedEntityData = entityProperties.reduce((acc, property) => {
374
+ acc[property] = entityData[property];
375
+ return acc;
376
+ }, {});
377
+ const catalogEntry = catalogRepository.create({
378
+ id: cleanedEntityData.id,
379
+ name: entity,
380
+ data: cleanedEntityData,
381
+ });
382
+ catalogRepository.persist(catalogEntry);
383
+ /**
384
+ * Create the catalog relation entries for the parent entity and the child entity
385
+ */
386
+ const parentCatalogRelationEntry = catalogRelationRepository.create({
387
+ parent_id: entityData[parentPropertyId],
388
+ parent_name: parentEntityName,
389
+ child_id: cleanedEntityData.id,
390
+ child_name: entity,
391
+ pivot: `${parentEntityName}-${entity}`,
392
+ });
393
+ const childCatalogRelationEntry = catalogRelationRepository.create({
394
+ parent_id: cleanedEntityData.id,
395
+ parent_name: entity,
396
+ child_id: entityData[childPropertyId],
397
+ child_name: childEntityName,
398
+ pivot: `${entity}-${childEntityName}`,
399
+ });
400
+ catalogRelationRepository.persist([
401
+ parentCatalogRelationEntry,
402
+ childCatalogRelationEntry,
403
+ ]);
404
+ }
405
+ await em.flush();
406
+ });
407
+ }
408
+ /**
409
+ * Event emitted from the link modules to detach a link entity from its parent and child entities from the linked modules.
410
+ * @param entity
411
+ * @param data
412
+ * @param schemaEntityObjectRepresentation
413
+ * @protected
414
+ */
415
+ async onDetach({ entity, data, schemaEntityObjectRepresentation, }) {
416
+ await this.container_.manager.transactional(async (em) => {
417
+ const catalogRepository = em.getRepository(_models_1.Catalog);
418
+ const catalogRelationRepository = em.getRepository(_models_1.CatalogRelation);
419
+ const { data: data_ } = PostgresProvider.parseData(data, schemaEntityObjectRepresentation);
420
+ const ids = data_.map((entityData) => entityData.id);
421
+ await catalogRepository.nativeDelete({
422
+ id: { $in: ids },
423
+ name: entity,
424
+ });
425
+ await catalogRelationRepository.nativeDelete({
426
+ $or: [
427
+ {
428
+ parent_id: { $in: ids },
429
+ parent_name: entity,
430
+ },
431
+ {
432
+ child_id: { $in: ids },
433
+ child_name: entity,
434
+ },
435
+ ],
436
+ });
437
+ });
438
+ }
439
+ }
440
+ exports.PostgresProvider = PostgresProvider;
441
+ _PostgresProvider_isReady_ = new WeakMap();
@@ -0,0 +1,31 @@
1
+ import { IEventBusModuleService, InternalModuleDeclaration, ModuleJoinerConfig, RemoteJoinerQuery, SearchModuleTypes } from "@medusajs/types";
2
+ import { SchemaObjectRepresentation, StorageProvider } from "../types";
3
+ type InjectedDependencies = {
4
+ eventBusModuleService: IEventBusModuleService;
5
+ storageProviderCtr: StorageProvider;
6
+ storageProviderCtrOptions: unknown;
7
+ remoteQuery: (query: string | RemoteJoinerQuery | object, variables?: Record<string, unknown>) => Promise<any>;
8
+ };
9
+ export default class SearchModuleService implements SearchModuleTypes.ISearchModuleService {
10
+ protected readonly moduleDeclaration: InternalModuleDeclaration;
11
+ private readonly container_;
12
+ private readonly moduleOptions_;
13
+ protected readonly eventBusModuleService_: IEventBusModuleService;
14
+ protected schemaObjectRepresentation_: SchemaObjectRepresentation;
15
+ protected schemaEntitiesMap_: Record<string, any>;
16
+ protected storageProviderInstance_: StorageProvider;
17
+ protected readonly storageProviderCtr_: StorageProvider;
18
+ protected readonly storageProviderCtrOptions_: unknown;
19
+ protected storageProvider_: StorageProvider;
20
+ constructor(container: InjectedDependencies, moduleDeclaration: InternalModuleDeclaration);
21
+ __hooks: {
22
+ onApplicationStart(this: SearchModuleService): Promise<void>;
23
+ };
24
+ __joinerConfig(): ModuleJoinerConfig;
25
+ protected onApplicationStart_(): Promise<void>;
26
+ query(...args: any[]): Promise<any>;
27
+ queryAndCount(...args: any[]): Promise<any>;
28
+ protected registerListeners(): void;
29
+ private buildSchemaObjectRepresentation_;
30
+ }
31
+ export {};
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const types_1 = require("../types");
4
+ const build_config_1 = require("../utils/build-config");
5
+ const joiner_config_1 = require("./../joiner-config");
6
+ class SearchModuleService {
7
+ constructor(container, moduleDeclaration) {
8
+ this.moduleDeclaration = moduleDeclaration;
9
+ this.__hooks = {
10
+ onApplicationStart() {
11
+ return this.onApplicationStart_();
12
+ },
13
+ };
14
+ this.container_ = container;
15
+ this.moduleOptions_ = (moduleDeclaration.options ??
16
+ moduleDeclaration);
17
+ const { eventBusModuleService, storageProviderCtr, storageProviderCtrOptions, } = container;
18
+ this.eventBusModuleService_ = eventBusModuleService;
19
+ this.storageProviderCtr_ = storageProviderCtr;
20
+ this.storageProviderCtrOptions_ = storageProviderCtrOptions;
21
+ if (!this.eventBusModuleService_) {
22
+ throw new Error("EventBusModuleService is required for the SearchModule to work");
23
+ }
24
+ }
25
+ __joinerConfig() {
26
+ return joiner_config_1.joinerConfig;
27
+ }
28
+ async onApplicationStart_() {
29
+ this.buildSchemaObjectRepresentation_();
30
+ this.storageProvider_ = new this.storageProviderCtr_(this.container_, Object.assign(this.storageProviderCtrOptions_ ?? {}, {
31
+ schemaObjectRepresentation: this.schemaObjectRepresentation_,
32
+ entityMap: this.schemaEntitiesMap_,
33
+ }), this.moduleOptions_);
34
+ this.registerListeners();
35
+ if (this.storageProvider_.onApplicationStart) {
36
+ await this.storageProvider_.onApplicationStart();
37
+ }
38
+ }
39
+ async query(...args) {
40
+ return await this.storageProvider_.query.apply(this.storageProvider_, args);
41
+ }
42
+ async queryAndCount(...args) {
43
+ return await this.storageProvider_.queryAndCount.apply(this.storageProvider_, args);
44
+ }
45
+ registerListeners() {
46
+ const schemaObjectRepresentation = this.schemaObjectRepresentation_ ?? {};
47
+ for (const [entityName, schemaEntityObjectRepresentation] of Object.entries(schemaObjectRepresentation)) {
48
+ if (types_1.schemaObjectRepresentationPropertiesToOmit.includes(entityName)) {
49
+ continue;
50
+ }
51
+ schemaEntityObjectRepresentation.listeners.forEach((listener) => {
52
+ this.eventBusModuleService_.subscribe(listener, this.storageProvider_.consumeEvent(schemaEntityObjectRepresentation));
53
+ });
54
+ }
55
+ }
56
+ buildSchemaObjectRepresentation_() {
57
+ if (this.schemaObjectRepresentation_) {
58
+ return this.schemaObjectRepresentation_;
59
+ }
60
+ const [objectRepresentation, entityMap] = (0, build_config_1.buildSchemaObjectRepresentation)(this.moduleOptions_.schema);
61
+ this.schemaObjectRepresentation_ = objectRepresentation;
62
+ this.schemaEntitiesMap_ = entityMap;
63
+ return this.schemaObjectRepresentation_;
64
+ }
65
+ }
66
+ exports.default = SearchModuleService;
@@ -0,0 +1,122 @@
1
+ import { ModuleJoinerConfig, ModulesSdkTypes, Subscriber } from "@medusajs/types";
2
+ /**
3
+ * Represents the module options that can be provided
4
+ */
5
+ export interface SearchModuleOptions {
6
+ customAdapter?: {
7
+ constructor: new (...args: any[]) => any;
8
+ options: any;
9
+ };
10
+ defaultAdapterOptions?: ModulesSdkTypes.ModuleServiceInitializeOptions;
11
+ schema: string;
12
+ }
13
+ export type SchemaObjectEntityRepresentation = {
14
+ /**
15
+ * The name of the type/entity in the schema
16
+ */
17
+ entity: string;
18
+ /**
19
+ * All parents a type/entity refers to in the schema
20
+ * or through links
21
+ */
22
+ parents: {
23
+ /**
24
+ * The reference to the schema object representation
25
+ * of the parent
26
+ */
27
+ ref: SchemaObjectEntityRepresentation;
28
+ /**
29
+ * When a link is inferred between two types/entities
30
+ * we are configuring the link tree, and therefore we are
31
+ * storing the reference to the parent type/entity within the
32
+ * schema which defer from the true parent from a pure entity
33
+ * point of view
34
+ */
35
+ inSchemaRef?: SchemaObjectEntityRepresentation;
36
+ /**
37
+ * The property the data should be assigned to in the parent
38
+ */
39
+ targetProp: string;
40
+ /**
41
+ * Are the data expected to be a list or not
42
+ */
43
+ isList?: boolean;
44
+ }[];
45
+ /**
46
+ * The default fields to query for the type/entity
47
+ */
48
+ fields: string[];
49
+ /**
50
+ * @Listerners directive is required and all listeners found
51
+ * for the type will be stored here
52
+ */
53
+ listeners: string[];
54
+ /**
55
+ * The alias for the type/entity retrieved in the corresponding
56
+ * module
57
+ */
58
+ alias: string;
59
+ /**
60
+ * The module joiner config corresponding to the module the type/entity
61
+ * refers to
62
+ */
63
+ moduleConfig: ModuleJoinerConfig;
64
+ };
65
+ export type SchemaPropertiesMap = {
66
+ [key: string]: {
67
+ shortCutOf?: string;
68
+ ref: SchemaObjectEntityRepresentation;
69
+ };
70
+ };
71
+ export type EntityNameModuleConfigMap = {
72
+ [key: string]: ModuleJoinerConfig;
73
+ };
74
+ /**
75
+ * Represents the schema objects representation once the schema has been processed
76
+ */
77
+ export type SchemaObjectRepresentation = {
78
+ [key: string]: SchemaObjectEntityRepresentation;
79
+ } | {
80
+ _schemaPropertiesMap: SchemaPropertiesMap;
81
+ _serviceNameModuleConfigMap: EntityNameModuleConfigMap;
82
+ };
83
+ export declare const schemaObjectRepresentationPropertiesToOmit: string[];
84
+ /**
85
+ * Represents the storage provider interface, TODO: move this to @medusajs/types once we are settled on the interface
86
+ */
87
+ export interface StorageProvider {
88
+ new (container: {
89
+ [key: string]: any;
90
+ }, storageProviderOptions: unknown & {
91
+ schemaObjectRepresentation: SchemaObjectRepresentation;
92
+ }, moduleOptions: SearchModuleOptions): StorageProvider;
93
+ onApplicationStart?(): Promise<void>;
94
+ query(...args: any[]): unknown;
95
+ queryAndCount(...args: any[]): unknown;
96
+ consumeEvent(schemaEntityObjectRepresentation: SchemaObjectEntityRepresentation): Subscriber;
97
+ }
98
+ export type Select = {
99
+ [key: string]: boolean | Select | Select[];
100
+ };
101
+ export type Where = {
102
+ [key: string]: any;
103
+ };
104
+ export type OrderBy = {
105
+ [path: string]: OrderBy | "ASC" | "DESC" | 1 | -1 | true | false;
106
+ };
107
+ export type QueryFormat = {
108
+ select: Select;
109
+ where?: Where;
110
+ joinWhere?: Where;
111
+ };
112
+ export type QueryOptions = {
113
+ skip?: number;
114
+ take?: number;
115
+ orderBy?: OrderBy | OrderBy[];
116
+ keepFilteredEntities?: boolean;
117
+ };
118
+ type ResultSetLimit = [never | 0 | 1 | 2];
119
+ export type Resultset<Select, Prev extends number = 3> = Prev extends never ? never : {
120
+ [key in keyof Select]: Select[key] extends boolean ? string : Select[key] extends Select[] ? Resultset<Select[key][0], ResultSetLimit[Prev]>[] : Select[key] extends {} ? Resultset<Select[key], ResultSetLimit[Prev]> : unknown;
121
+ };
122
+ export {};
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.schemaObjectRepresentationPropertiesToOmit = void 0;
4
+ exports.schemaObjectRepresentationPropertiesToOmit = [
5
+ "_schemaPropertiesMap",
6
+ "_serviceNameModuleConfigMap",
7
+ ];