@storecraft/database-mongodb 1.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.
@@ -0,0 +1,137 @@
1
+ import { enums } from "@storecraft/core/v-api";
2
+ import { to_objid_safe } from "./utils.funcs.js";
3
+
4
+ /** @param {import("@storecraft/core/v-api").DiscountType} d */
5
+ const is_order_discount = d => {
6
+ return (d.info.details.meta.id===enums.DiscountMetaEnum.order.id);
7
+ }
8
+
9
+ /** @param {import("@storecraft/core/v-api").DiscountType} d */
10
+ const is_automatic_discount = d => {
11
+ return (d.application.id===enums.DiscountApplicationEnum.Auto.id);
12
+ }
13
+
14
+ const extract_abs_number = v => {
15
+ return v && !isNaN(v) && v!==Infinity && Math.abs(v);
16
+ }
17
+
18
+ /**
19
+ * create a mongodb conjunctions clauses from discount, intended
20
+ * for filtering.
21
+ *
22
+ *
23
+ * @param {import("@storecraft/core/v-api").DiscountType} d
24
+ */
25
+ export const discount_to_mongo_conjunctions = d => {
26
+ // discount has to be product discount + automatic + active + has filters
27
+ const conjunctions = [];
28
+ const is_good = !is_order_discount(d) && is_automatic_discount(d) &&
29
+ d.active && d?.info?.filters?.length;
30
+ if(!is_good) conjunctions;
31
+
32
+ const filters = d.info.filters;
33
+
34
+ for(const filter of filters) {
35
+ const op = filter.meta.op;
36
+
37
+ switch (op) {
38
+ case enums.FilterMetaEnum.p_all.op:
39
+ // do nothing
40
+ break;
41
+ case enums.FilterMetaEnum.p_in_products.op:
42
+ {
43
+ /** @type {import("@storecraft/core/v-api").FilterValue_p_in_products} */
44
+ const cast = filter.value ?? [];
45
+
46
+ conjunctions.push(
47
+ { handle: { $in: cast.map(it => it.handle) } }
48
+ );
49
+ }
50
+ break;
51
+ case enums.FilterMetaEnum.p_not_in_products.op:
52
+ {
53
+ /** @type {import("@storecraft/core/v-api").FilterValue_p_not_in_products} */
54
+ const cast = filter.value ?? [];
55
+
56
+ conjunctions.push(
57
+ { handle: { $nin: cast.map(it => it.handle) } }
58
+ );
59
+ }
60
+ break;
61
+ case enums.FilterMetaEnum.p_in_tags.op:
62
+ {
63
+ /** @type {import("@storecraft/core/v-api").FilterValue_p_in_tags} */
64
+ const cast = filter.value ?? [];
65
+
66
+ conjunctions.push(
67
+ { tags: { $in: cast } }
68
+ );
69
+ }
70
+ break;
71
+ case enums.FilterMetaEnum.p_not_in_tags.op:
72
+ {
73
+ /** @type {import("@storecraft/core/v-api").FilterValue_p_not_in_tags} */
74
+ const cast = filter.value ?? [];
75
+
76
+ conjunctions.push(
77
+ { tags: { $nin: cast } }
78
+ );
79
+ }
80
+ break;
81
+ case enums.FilterMetaEnum.p_in_collections.op:
82
+ {
83
+ /** @type {import("@storecraft/core/v-api").FilterValue_p_in_collections} */
84
+ const cast = filter.value ?? [];
85
+
86
+ conjunctions.push(
87
+ {
88
+ '_relations.collections.ids': {
89
+ $in: cast.map(c => to_objid_safe(c.id)).filter(Boolean)
90
+ }
91
+ }
92
+ );
93
+ }
94
+ break;
95
+ case enums.FilterMetaEnum.p_not_in_collections.op:
96
+ {
97
+ /** @type {import("@storecraft/core/v-api").FilterValue_p_not_in_collections} */
98
+ const cast = filter.value ?? [];
99
+
100
+ conjunctions.push(
101
+ {
102
+ '_relations.collections.ids': {
103
+ $nin: cast.map(c => to_objid_safe(c.id)).filter(Boolean)
104
+ }
105
+ }
106
+ );
107
+ }
108
+ break;
109
+ case enums.FilterMetaEnum.p_in_price_range.op:
110
+ {
111
+ /** @type {import("@storecraft/core/v-api").FilterValue_p_in_price_range} */
112
+ const cast = {
113
+ from: 0,
114
+ to: Number.POSITIVE_INFINITY,
115
+ ...(filter?.value ?? {})
116
+ };
117
+
118
+ const from = extract_abs_number(cast.from);
119
+ const to = extract_abs_number(cast.to);
120
+
121
+ const conj = { price: { $and: [] } };
122
+
123
+ if(from) conj.price.$and.push({ $gte: from });
124
+ if(to) conj.price.$and.push({ $lt: to });
125
+
126
+ (to || from) && conjunctions.push(conj);
127
+
128
+ }
129
+ break;
130
+
131
+ default:
132
+ break;
133
+ }
134
+ }
135
+
136
+ return conjunctions;
137
+ }
@@ -0,0 +1,173 @@
1
+ import { Collection } from 'mongodb'
2
+ import { MongoDB } from '../index.js'
3
+ import { count_regular, get_regular, list_regular,
4
+ upsert_regular } from './con.shared.js'
5
+ import { handle_or_id, to_objid } from './utils.funcs.js';
6
+ import { func } from '@storecraft/core/v-api';
7
+ import { ID } from '@storecraft/core/v-api/utils.func.js';
8
+ import {
9
+ image_url_to_handle, image_url_to_name
10
+ } from '@storecraft/core/v-api/con.images.logic.js';
11
+
12
+ /**
13
+ * @typedef {import('@storecraft/core/v-database').db_images} db_col
14
+ */
15
+
16
+ /**
17
+ * @param {MongoDB} d @returns {Collection<db_col["$type_get"]>}
18
+ */
19
+ const col = (d) => d.collection('images');
20
+
21
+ /**
22
+ * @param {MongoDB} driver
23
+ */
24
+ const upsert = (driver) => upsert_regular(driver, col(driver));
25
+
26
+ /**
27
+ * @param {MongoDB} driver
28
+ */
29
+ const get = (driver) => get_regular(driver, col(driver));
30
+
31
+
32
+ /**
33
+ * @param {MongoDB} driver
34
+ *
35
+ *
36
+ * @returns {db_col["remove"]}
37
+ */
38
+ const remove = (driver) => {
39
+ return async (id) => {
40
+ const image = await col(driver).findOne(handle_or_id(id));
41
+ if(!image) return;
42
+
43
+ const session = driver.mongo_client.startSession();
44
+ try {
45
+ await session.withTransaction(
46
+ async () => {
47
+ ////
48
+ // EVERYTHING --> IMAGES URL
49
+ ////
50
+ const filter = { media : image.url };
51
+ const update = { $pull: { media: image.url } };
52
+ const options = { session };
53
+
54
+ await Promise.all(
55
+ [
56
+ driver.resources.collections._col.updateMany(filter, update, options),
57
+ driver.resources.discounts._col.updateMany(filter, update, options),
58
+ driver.resources.posts._col.updateMany(filter, update, options),
59
+ driver.resources.products._col.updateMany(filter, update, options),
60
+ driver.resources.shipping_methods._col.updateMany(filter, update, options),
61
+ driver.resources.storefronts._col.updateMany(filter, update, options),
62
+ ]
63
+ );
64
+
65
+ // DELETE ME
66
+ const res = await col(driver).deleteOne(
67
+ { _id: image._id },
68
+ options
69
+ );
70
+ }
71
+ );
72
+ } catch(e) {
73
+ console.log(e);
74
+ return false;
75
+ } finally {
76
+ await session.endSession();
77
+ }
78
+
79
+ return true;
80
+ }
81
+
82
+ }
83
+
84
+ /**
85
+ * report media usages
86
+ *
87
+ *
88
+ * @param {MongoDB} driver
89
+ *
90
+ *
91
+ * @returns {db_col["report_document_media"]}
92
+ */
93
+ export const report_document_media = (driver) => {
94
+ return async (data, session) => {
95
+ if(!(data?.media?.length))
96
+ return;
97
+
98
+ const add_to_search_index = func.union(
99
+ data['title'], func.to_tokens(data['title'])
100
+ );
101
+
102
+ const dates = func.apply_dates({});
103
+
104
+ /**
105
+ * @param {string} url
106
+ *
107
+ *
108
+ * @returns {import('mongodb').AnyBulkWriteOperation<
109
+ * import('@storecraft/core/v-api').ImageType>
110
+ * }
111
+ */
112
+ const url_to_update = url => {
113
+ const id_on_insert = ID('img');
114
+ return {
115
+ updateOne: {
116
+ filter: { handle: image_url_to_handle(url) },
117
+ update: {
118
+ $addToSet : { '_relations.search': { $each: add_to_search_index} },
119
+ $set: {
120
+ name: image_url_to_name(url),
121
+ url: url,
122
+ updated_at: dates.updated_at
123
+ },
124
+ $setOnInsert: {
125
+ created_at: dates.created_at,
126
+ _id: to_objid(id_on_insert),
127
+ id: id_on_insert
128
+ }
129
+ },
130
+ upsert: true
131
+ }
132
+ }
133
+ }
134
+
135
+ const ops = data.media.map(url_to_update);
136
+
137
+ await driver.resources.images._col.bulkWrite(
138
+ ops, { session }
139
+ );
140
+
141
+ }
142
+ }
143
+
144
+ /**
145
+ * @param {MongoDB} driver
146
+ */
147
+ const list = (driver) => list_regular(driver, col(driver));
148
+
149
+
150
+ /**
151
+ * @param {MongoDB} driver
152
+ */
153
+ const count = (driver) => count_regular(driver, col(driver));
154
+
155
+
156
+ /**
157
+ * @param {MongoDB} driver
158
+ *
159
+ *
160
+ * @return {db_col & { _col: ReturnType<col>}}
161
+ * */
162
+ export const impl = (driver) => {
163
+
164
+ return {
165
+ _col: col(driver),
166
+ get: get(driver),
167
+ upsert: upsert(driver),
168
+ remove: remove(driver),
169
+ list: list(driver),
170
+ count: count(driver),
171
+ report_document_media: report_document_media(driver)
172
+ }
173
+ }
@@ -0,0 +1,101 @@
1
+ import { Collection } from 'mongodb'
2
+ import { MongoDB } from '../index.js'
3
+ import { count_regular, get_regular, list_regular,
4
+ remove_regular, upsert_regular } from './con.shared.js'
5
+ import { to_objid } from './utils.funcs.js';
6
+ import { add_search_terms_relation_on } from './utils.relations.js';
7
+ import { union } from '@storecraft/core/v-api/utils.func.js';
8
+
9
+ /**
10
+ * @typedef {import('@storecraft/core/v-database').db_notifications} db_col
11
+ */
12
+
13
+ /**
14
+ * @param {MongoDB} d
15
+ *
16
+ *
17
+ * @returns {Collection<db_col["$type_get"]>}
18
+ */
19
+ const col = (d) => d.collection('notifications');
20
+
21
+ /**
22
+ * @param {MongoDB} driver
23
+ *
24
+ * @returns {db_col["upsert"]}
25
+ */
26
+ const upsert = (driver) => {
27
+ return (item, search_terms=[]) => {
28
+ return upsertBulk(driver)([item], [search_terms]);
29
+ }
30
+ }
31
+
32
+
33
+ /**
34
+ * @param {MongoDB} driver
35
+ *
36
+ *
37
+ * @returns {db_col["upsertBulk"]}
38
+ */
39
+ const upsertBulk = (driver) => {
40
+ return async (items, search_terms=[]) => {
41
+
42
+ items = items.map(item => ({...item}));
43
+ items.forEach(
44
+ (item, ix) => {
45
+ item._id = to_objid(item.id);
46
+
47
+ add_search_terms_relation_on(
48
+ item,
49
+ union(item.search, search_terms[ix])
50
+ );
51
+ }
52
+ );
53
+
54
+ // SEARCH
55
+
56
+ const res = await col(driver).insertMany(
57
+ items
58
+ );
59
+
60
+ return true;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * @param {MongoDB} driver
66
+ */
67
+ const get = (driver) => get_regular(driver, col(driver));
68
+
69
+ /**
70
+ * @param {MongoDB} driver
71
+ */
72
+ const remove = (driver) => remove_regular(driver, col(driver));
73
+
74
+ /**
75
+ * @param {MongoDB} driver
76
+ */
77
+ const list = (driver) => list_regular(driver, col(driver));
78
+
79
+ /**
80
+ * @param {MongoDB} driver
81
+ */
82
+ const count = (driver) => count_regular(driver, col(driver));
83
+
84
+ /**
85
+ * @param {MongoDB} driver
86
+ *
87
+ *
88
+ * @return {db_col & { _col: ReturnType<col>}}
89
+ */
90
+ export const impl = (driver) => {
91
+
92
+ return {
93
+ _col: col(driver),
94
+ get: get(driver),
95
+ upsert: upsert(driver),
96
+ upsertBulk: upsertBulk(driver),
97
+ remove: remove(driver),
98
+ list: list(driver),
99
+ count: count(driver)
100
+ }
101
+ }
@@ -0,0 +1,61 @@
1
+ import { Collection } from 'mongodb'
2
+ import { MongoDB } from '../index.js'
3
+ import { count_regular, get_regular, list_regular,
4
+ remove_regular, upsert_regular } from './con.shared.js'
5
+
6
+ /**
7
+ * @typedef {import('@storecraft/core/v-database').db_orders} db_col
8
+ */
9
+
10
+ /**
11
+ * @param {MongoDB} d
12
+ *
13
+ *
14
+ * @returns {Collection<db_col["$type_get"]>}
15
+ */
16
+ const col = (d) => d.collection('orders');
17
+
18
+ /**
19
+ * @param {MongoDB} driver
20
+ */
21
+ const upsert = (driver) => upsert_regular(driver, col(driver));
22
+
23
+ /**
24
+ * @param {MongoDB} driver
25
+ */
26
+ const get = (driver) => get_regular(driver, col(driver));
27
+
28
+
29
+ /**
30
+ * @param {MongoDB} driver
31
+ */
32
+ const remove = (driver) => remove_regular(driver, col(driver));
33
+
34
+ /**
35
+ * @param {MongoDB} driver
36
+ */
37
+ const list = (driver) => list_regular(driver, col(driver));
38
+
39
+ /**
40
+ * @param {MongoDB} driver
41
+ */
42
+ const count = (driver) => count_regular(driver, col(driver));
43
+
44
+
45
+ /**
46
+ * @param {MongoDB} driver
47
+ *
48
+ *
49
+ * @return {db_col & { _col: ReturnType<col>}}
50
+ */
51
+ export const impl = (driver) => {
52
+
53
+ return {
54
+ _col: col(driver),
55
+ get: get(driver),
56
+ upsert: upsert(driver),
57
+ remove: remove(driver),
58
+ list: list(driver),
59
+ count: count(driver),
60
+ }
61
+ }
@@ -0,0 +1,149 @@
1
+ import { Collection } from 'mongodb'
2
+ import { MongoDB } from '../index.js'
3
+ import { count_regular, get_regular, list_regular } from './con.shared.js'
4
+ import { handle_or_id, to_objid } from './utils.funcs.js';
5
+ import { report_document_media } from './con.images.js';
6
+ import {
7
+ add_search_terms_relation_on, delete_me,
8
+ remove_entry_from_all_connection_of_relation, save_me,
9
+ update_entry_on_all_connection_of_relation
10
+ } from './utils.relations.js';
11
+
12
+
13
+ /**
14
+ * @typedef {import('@storecraft/core/v-database').db_posts} db_col
15
+ */
16
+
17
+ /**
18
+ * @param {MongoDB} d
19
+ *
20
+ *
21
+ * @returns {Collection<import('./utils.relations.js').WithRelations<db_col["$type_get"]>>}
22
+ */
23
+ const col = (d) => d.collection('posts');
24
+
25
+ /**
26
+ * @param {MongoDB} driver
27
+ *
28
+ *
29
+ * @returns {db_col["upsert"]}
30
+ */
31
+ const upsert = (driver) => {
32
+ return async (data, search_terms=[]) => {
33
+ data = {...data};
34
+ const objid = to_objid(data.id);
35
+ const session = driver.mongo_client.startSession();
36
+
37
+ try {
38
+ await session.withTransaction(
39
+ async () => {
40
+
41
+ // SEARCH
42
+ add_search_terms_relation_on(data, search_terms);
43
+
44
+ ////
45
+ // STOREFRONTS --> POSTS RELATION
46
+ ////
47
+
48
+ await update_entry_on_all_connection_of_relation(
49
+ driver, 'storefronts', 'posts', objid, data, session
50
+ );
51
+
52
+ ////
53
+ // REPORT IMAGES USAGE
54
+ ////
55
+ await report_document_media(driver)(data, session);
56
+
57
+ // SAVE ME
58
+ await save_me(driver, 'posts', objid, data, session);
59
+
60
+ }
61
+ );
62
+ } catch(e) {
63
+ console.log(e);
64
+ return false;
65
+ } finally {
66
+ await session.endSession();
67
+ }
68
+
69
+ return true;
70
+ }
71
+
72
+ }
73
+ /**
74
+ * @param {MongoDB} driver
75
+ */
76
+ const get = (driver) => get_regular(driver, col(driver));
77
+
78
+ /**
79
+ * @param {MongoDB} driver
80
+ *
81
+ *
82
+ * @returns {db_col["remove"]}
83
+ */
84
+ const remove = (driver) => {
85
+ return async (id_or_handle) => {
86
+ const item = await col(driver).findOne(handle_or_id(id_or_handle));
87
+
88
+ if(!item) return;
89
+
90
+ const objid = to_objid(item.id)
91
+ const session = driver.mongo_client.startSession();
92
+
93
+ try {
94
+ await session.withTransaction(
95
+ async () => {
96
+ ////
97
+ // STOREFRONTS --> POSTS RELATION
98
+ ////
99
+ await remove_entry_from_all_connection_of_relation(
100
+ driver, 'storefronts', 'posts', objid, session
101
+ );
102
+
103
+ // DELETE ME
104
+ await delete_me(
105
+ driver, 'posts', objid, session
106
+ );
107
+
108
+ }
109
+ );
110
+ } catch(e) {
111
+ console.log(e);
112
+ return false;
113
+ } finally {
114
+ await session.endSession();
115
+ }
116
+
117
+ return true;
118
+ }
119
+
120
+ }
121
+
122
+
123
+ /**
124
+ * @param {MongoDB} driver
125
+ */
126
+ const list = (driver) => list_regular(driver, col(driver));
127
+
128
+ /**
129
+ * @param {MongoDB} driver
130
+ */
131
+ const count = (driver) => count_regular(driver, col(driver));
132
+
133
+ /**
134
+ * @param {MongoDB} driver
135
+ *
136
+ *
137
+ * @return {db_col & { _col: ReturnType<col>}}
138
+ */
139
+ export const impl = (driver) => {
140
+
141
+ return {
142
+ _col: col(driver),
143
+ get: get(driver),
144
+ upsert: upsert(driver),
145
+ remove: remove(driver),
146
+ list: list(driver),
147
+ count: count(driver),
148
+ }
149
+ }