@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.
- package/README.md +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +24 -0
- package/dist/initialize/index.d.ts +8 -0
- package/dist/initialize/index.js +17 -0
- package/dist/joiner-config.d.ts +2 -0
- package/dist/joiner-config.js +4 -0
- package/dist/loaders/connection.d.ts +4 -0
- package/dist/loaders/connection.js +41 -0
- package/dist/loaders/container.d.ts +4 -0
- package/dist/loaders/container.js +21 -0
- package/dist/loaders/index.d.ts +2 -0
- package/dist/loaders/index.js +10 -0
- package/dist/migrations/Migration20231019174230.d.ts +4 -0
- package/dist/migrations/Migration20231019174230.js +18 -0
- package/dist/models/catalog-relation.d.ts +15 -0
- package/dist/models/catalog-relation.js +72 -0
- package/dist/models/catalog.d.ts +11 -0
- package/dist/models/catalog.js +55 -0
- package/dist/models/index.d.ts +2 -0
- package/dist/models/index.js +18 -0
- package/dist/module-definition.d.ts +2 -0
- package/dist/module-definition.js +15 -0
- package/dist/scripts/bin/run-migration-down.d.ts +3 -0
- package/dist/scripts/bin/run-migration-down.js +32 -0
- package/dist/scripts/bin/run-migration-up.d.ts +3 -0
- package/dist/scripts/bin/run-migration-up.js +32 -0
- package/dist/scripts/bin/run-seed.d.ts +3 -0
- package/dist/scripts/bin/run-seed.js +38 -0
- package/dist/scripts/index.d.ts +2 -0
- package/dist/scripts/index.js +18 -0
- package/dist/scripts/migration-down.d.ts +10 -0
- package/dist/scripts/migration-down.js +52 -0
- package/dist/scripts/migration-up.d.ts +10 -0
- package/dist/scripts/migration-up.js +56 -0
- package/dist/scripts/seed-data/index.d.ts +8 -0
- package/dist/scripts/seed-data/index.js +138 -0
- package/dist/scripts/seed.d.ts +5 -0
- package/dist/scripts/seed.js +65 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +8 -0
- package/dist/services/postgres-provider.d.ts +126 -0
- package/dist/services/postgres-provider.js +441 -0
- package/dist/services/search-module-service.d.ts +31 -0
- package/dist/services/search-module-service.js +66 -0
- package/dist/types/index.d.ts +122 -0
- package/dist/types/index.js +7 -0
- package/dist/utils/build-config.d.ts +21 -0
- package/dist/utils/build-config.js +437 -0
- package/dist/utils/create-partitions.d.ts +3 -0
- package/dist/utils/create-partitions.js +27 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +19 -0
- package/dist/utils/query-builder.d.ts +28 -0
- package/dist/utils/query-builder.js +375 -0
- 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 {};
|