@storecraft/database-mongodb 1.0.13 → 1.0.15
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 +8 -68
- package/{vector-search-extension.js → example-extension/vector-search-extension.js} +4 -1
- package/index.js +54 -61
- package/jsconfig.json +1 -0
- package/migrate.js +1 -0
- package/migrations/00001_seed_email_templates.js +1 -0
- package/migrations/00002_seed_email_templates.js +36 -0
- package/package.json +6 -2
- package/src/con.auth_users.js +8 -10
- package/src/con.collections.js +13 -14
- package/src/con.customers.js +8 -11
- package/src/con.discounts.js +8 -13
- package/src/con.discounts.utils.js +18 -10
- package/src/con.images.js +7 -6
- package/src/con.notifications.js +4 -4
- package/src/con.orders.js +4 -4
- package/src/con.posts.js +6 -1
- package/src/con.products.js +12 -17
- package/src/con.search.js +9 -9
- package/src/con.shared.js +30 -27
- package/src/con.shipping.js +6 -5
- package/src/con.storefronts.js +13 -14
- package/src/con.tags.js +4 -5
- package/src/con.templates.js +4 -5
- package/src/utils.funcs.js +2 -0
- package/src/utils.query.js +10 -7
- package/src/utils.relations.js +11 -7
- package/types.public.d.ts +4 -2
- package/vector-store/index.js +289 -0
- package/vector-store/types.d.ts +44 -0
- package/vector-store/types.private.d.ts +44 -0
package/README.md
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
[](https://github.com/store-craft/storecraft/actions/workflows/test.database-mongodb.yml)
|
9
9
|
|
10
10
|
Official `mongodb` driver for `StoreCraft` on **Node.js** / **Deno** / **Bun** platforms.
|
11
|
-
Also,
|
11
|
+
Also, official support for mongo-db as vector store.
|
12
12
|
|
13
13
|
```bash
|
14
14
|
npm i @storecraft/database-mongodb
|
@@ -24,23 +24,19 @@ import { NodePlatform } from '@storecraft/core/platform/node';
|
|
24
24
|
import { MongoDB } from '@storecraft/database-mongodb'
|
25
25
|
import { migrateToLatest } from '@storecraft/database-mongodb/migrate.js'
|
26
26
|
import { NodeLocalStorage } from '@storecraft/core/storage/node'
|
27
|
-
import {
|
27
|
+
import { MongoVectorStore } from '@storecraft/database-mongodb/vector-store'
|
28
28
|
|
29
|
-
const app = new App(
|
30
|
-
{
|
31
|
-
auth_admins_emails: ['admin@sc.com'],
|
32
|
-
auth_secret_access_token: 'auth_secret_access_token',
|
33
|
-
auth_secret_refresh_token: 'auth_secret_refresh_token'
|
34
|
-
}
|
35
|
-
)
|
29
|
+
const app = new App()
|
36
30
|
.withPlatform(new NodePlatform())
|
37
|
-
.withDatabase(new MongoDB({
|
38
|
-
.
|
39
|
-
|
31
|
+
.withDatabase(new MongoDB({}))
|
32
|
+
.withVectorStore(
|
33
|
+
new MongoVectorStore({ embedder: new OpenAIEmbedder() })
|
40
34
|
)
|
41
35
|
|
42
36
|
await app.init();
|
43
37
|
await migrateToLatest(app.db, false);
|
38
|
+
// cerate if not exists
|
39
|
+
await app.vectorstore.createVectorIndex(false, false);
|
44
40
|
|
45
41
|
const server = http.createServer(app.handler).listen(
|
46
42
|
8000,
|
@@ -51,62 +47,6 @@ const server = http.createServer(app.handler).listen(
|
|
51
47
|
|
52
48
|
```
|
53
49
|
|
54
|
-
## (Recommended) setup semantic/ai vector search extension for products
|
55
|
-
|
56
|
-
1. in [Atlas](https://cloud.mongodb.com/) dashboard, create a vector index (call it `vector_index`) for `products` collection:
|
57
|
-
|
58
|
-
```json
|
59
|
-
{
|
60
|
-
"fields": [
|
61
|
-
{
|
62
|
-
"numDimensions": 1536,
|
63
|
-
"path": "embedding",
|
64
|
-
"similarity": "cosine",
|
65
|
-
"type": "vector"
|
66
|
-
}
|
67
|
-
]
|
68
|
-
}
|
69
|
-
```
|
70
|
-
|
71
|
-
2. Now, every upserted product will be eligible for semantic search by it's title + description.
|
72
|
-
3. The extension is publicly available via HTTP (`POST` request)
|
73
|
-
```js
|
74
|
-
await fetch(
|
75
|
-
'http://localhost:8000/api/extensions/mongo-vector-search/search',
|
76
|
-
{
|
77
|
-
method: 'POST',
|
78
|
-
body: JSON.stringify(
|
79
|
-
{
|
80
|
-
query: 'I am interested in Nintendo related clothing, such as shirts',
|
81
|
-
limit: 1
|
82
|
-
}
|
83
|
-
)
|
84
|
-
}
|
85
|
-
)
|
86
|
-
```
|
87
|
-
|
88
|
-
returns `ProductType[]` array
|
89
|
-
|
90
|
-
```json
|
91
|
-
[
|
92
|
-
{
|
93
|
-
"title": "Super Mario T Shirt",
|
94
|
-
"handle": "super-mario-t-shirt",
|
95
|
-
"description": "This Super mario shirt is XL size and
|
96
|
-
features a colorful print of Lugi and Mario.",
|
97
|
-
"media": [
|
98
|
-
"storage://images/super-mario-shirt_1738686680944_w_819_h_460.jpeg"
|
99
|
-
],
|
100
|
-
"price": 100,
|
101
|
-
"qty": 1,
|
102
|
-
"active": true,
|
103
|
-
"id": "pr_67a240e4000000d34bcf0743",
|
104
|
-
"created_at": "2025-02-04T16:31:32.909Z",
|
105
|
-
"updated_at": "2025-02-04T16:58:25.286Z"
|
106
|
-
}
|
107
|
-
]
|
108
|
-
```
|
109
|
-
|
110
50
|
|
111
51
|
```text
|
112
52
|
Author: Tomer Shalev <tomer.shalev@gmail.com>
|
@@ -1,7 +1,10 @@
|
|
1
1
|
/**
|
2
|
+
* an older demo for extending storecraft with vector search.
|
3
|
+
* DO NOT USE this. Use the our official `MongoVectorSearch` insteas
|
4
|
+
*
|
2
5
|
* @import {extension} from '@storecraft/core/extensions'
|
3
6
|
*/
|
4
|
-
import { MongoDB } from '
|
7
|
+
import { MongoDB } from '../index.js';
|
5
8
|
/**
|
6
9
|
*
|
7
10
|
* @typedef {object} Config
|
package/index.js
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
* @import { Config } from './types.public.js'
|
3
|
+
* @import { MongoClientOptions } from 'mongodb'
|
4
|
+
* @import { db_driver } from '@storecraft/core/database'
|
5
|
+
* @import { BaseType } from '@storecraft/core/api'
|
6
|
+
* @import { ENV } from '@storecraft/core'
|
7
|
+
*/
|
1
8
|
import { App } from '@storecraft/core';
|
2
9
|
import { Collection, MongoClient, ServerApiVersion } from 'mongodb';
|
3
10
|
import { impl as auth_users } from './src/con.auth_users.js';
|
@@ -15,66 +22,43 @@ import { impl as tags } from './src/con.tags.js';
|
|
15
22
|
import { impl as templates } from './src/con.templates.js';
|
16
23
|
import { impl as search } from './src/con.search.js';
|
17
24
|
export { migrateToLatest } from './migrate.js';
|
25
|
+
export { MongoVectorStore } from './vector-store/index.js';
|
18
26
|
|
19
|
-
/**
|
20
|
-
* @typedef {Partial<import('./types.public.d.ts').Config>} Config
|
21
|
-
*/
|
22
|
-
|
23
|
-
/**
|
24
|
-
*
|
25
|
-
* @param {string} uri
|
26
|
-
* @param {import('mongodb').MongoClientOptions} [options]
|
27
|
-
*/
|
28
|
-
const connect = async (uri, options) => {
|
29
|
-
|
30
|
-
options = options ?? {
|
31
|
-
ignoreUndefined: true,
|
32
|
-
serverApi: {
|
33
|
-
version: ServerApiVersion.v1,
|
34
|
-
strict: false,
|
35
|
-
deprecationErrors: true,
|
36
|
-
|
37
|
-
}
|
38
|
-
}
|
39
|
-
const client = new MongoClient(uri, options);
|
40
|
-
|
41
|
-
return client.connect();
|
42
|
-
}
|
43
27
|
|
44
28
|
/**
|
45
|
-
* @typedef {import('@storecraft/core/database').db_driver} db_driver
|
46
|
-
*
|
47
|
-
*
|
48
29
|
* @implements {db_driver}
|
49
30
|
*/
|
50
31
|
export class MongoDB {
|
51
32
|
|
33
|
+
/** @satisfies {ENV<Config>} */
|
34
|
+
static EnvConfig = /** @type{const} */ ({
|
35
|
+
db_name: 'MONGODB_NAME',
|
36
|
+
url: 'MONGODB_URL',
|
37
|
+
});
|
38
|
+
|
52
39
|
/**
|
53
40
|
*
|
54
41
|
* @type {boolean}
|
55
42
|
*/
|
56
|
-
#
|
43
|
+
#is_ready;
|
57
44
|
|
58
45
|
/**
|
59
46
|
*
|
60
47
|
* @type {App<any, any, any>}
|
61
48
|
*/
|
62
|
-
#
|
49
|
+
#app;
|
63
50
|
|
64
51
|
/**
|
65
52
|
*
|
66
53
|
* @type {MongoClient}
|
67
54
|
*/
|
68
|
-
#
|
55
|
+
#mongo_client;
|
69
56
|
|
70
57
|
/**
|
71
58
|
*
|
72
59
|
* @type {Config}
|
73
60
|
*/
|
74
|
-
#
|
75
|
-
|
76
|
-
// /** @type {db_driver["resources"]} */
|
77
|
-
// #_resources;
|
61
|
+
#config;
|
78
62
|
|
79
63
|
/**
|
80
64
|
*
|
@@ -82,34 +66,35 @@ export class MongoDB {
|
|
82
66
|
* env variables `MONGODB_URL` will be used for uri upon init later
|
83
67
|
*/
|
84
68
|
constructor(config) {
|
85
|
-
this.#
|
86
|
-
this.#
|
69
|
+
this.#is_ready = false;
|
70
|
+
this.#config = {
|
71
|
+
options: {
|
72
|
+
ignoreUndefined: true,
|
73
|
+
serverApi: {
|
74
|
+
version: ServerApiVersion.v1,
|
75
|
+
strict: false,
|
76
|
+
deprecationErrors: true,
|
77
|
+
}
|
78
|
+
},
|
79
|
+
...config
|
80
|
+
};
|
87
81
|
}
|
88
82
|
|
89
83
|
/**
|
90
|
-
*
|
91
|
-
* @param {App} app
|
92
|
-
*
|
93
|
-
*
|
94
|
-
* @returns {Promise<this>}
|
84
|
+
* @type {db_driver["init"]}
|
95
85
|
*/
|
96
|
-
|
86
|
+
init(app) {
|
97
87
|
if(this.isReady)
|
98
88
|
return this;
|
99
|
-
const c = this.#
|
100
|
-
|
101
|
-
|
102
|
-
url: c?.url ?? app.platform.env.MONGODB_URL,
|
103
|
-
db_name: c?.db_name ?? app.platform.env.MONGODB_NAME ?? 'main'
|
104
|
-
}
|
105
|
-
|
106
|
-
this.#_mongo_client = await connect(
|
107
|
-
this.config.url,
|
108
|
-
this.config.options
|
109
|
-
);
|
110
|
-
|
111
|
-
this.#_app = app;
|
89
|
+
const c = this.#config;
|
90
|
+
c.db_name ??= app.platform.env[MongoDB.EnvConfig.db_name];
|
91
|
+
c.url ??= app.platform.env[MongoDB.EnvConfig.url] ?? 'main';
|
112
92
|
|
93
|
+
if(!this.config.db_name || !this.config.url) {
|
94
|
+
throw new Error('MongoVectorStore::client() - missing url or db_name');
|
95
|
+
}
|
96
|
+
|
97
|
+
this.#app = app;
|
113
98
|
this.resources = {
|
114
99
|
auth_users: auth_users(this),
|
115
100
|
collections: collections(this),
|
@@ -127,7 +112,7 @@ export class MongoDB {
|
|
127
112
|
search: search(this),
|
128
113
|
}
|
129
114
|
|
130
|
-
this.#
|
115
|
+
this.#is_ready = true;
|
131
116
|
|
132
117
|
return this;
|
133
118
|
}
|
@@ -137,7 +122,7 @@ export class MongoDB {
|
|
137
122
|
return true;
|
138
123
|
}
|
139
124
|
|
140
|
-
get isReady() { return this.#
|
125
|
+
get isReady() { return this.#is_ready; }
|
141
126
|
|
142
127
|
throwIfNotReady() {
|
143
128
|
if(!this.isReady)
|
@@ -157,7 +142,7 @@ export class MongoDB {
|
|
157
142
|
* @description Get the `storecraft` app
|
158
143
|
*/
|
159
144
|
get app() {
|
160
|
-
return this.#
|
145
|
+
return this.#app;
|
161
146
|
}
|
162
147
|
|
163
148
|
/**
|
@@ -165,7 +150,15 @@ export class MongoDB {
|
|
165
150
|
* @description Get the native `mongodb` client
|
166
151
|
*/
|
167
152
|
get mongo_client() {
|
168
|
-
|
153
|
+
if(!this.config.db_name || !this.config.url) {
|
154
|
+
throw new Error('MongoVectorStore::client() - missing url or db_name');
|
155
|
+
}
|
156
|
+
|
157
|
+
this.#mongo_client = this.#mongo_client ?? new MongoClient(
|
158
|
+
this.config.url, this.config.options
|
159
|
+
);
|
160
|
+
|
161
|
+
return this.#mongo_client;
|
169
162
|
}
|
170
163
|
|
171
164
|
/**
|
@@ -173,12 +166,12 @@ export class MongoDB {
|
|
173
166
|
* @description Get the config object
|
174
167
|
*/
|
175
168
|
get config() {
|
176
|
-
return this.#
|
169
|
+
return this.#config;
|
177
170
|
}
|
178
171
|
|
179
172
|
/**
|
180
173
|
*
|
181
|
-
* @template {
|
174
|
+
* @template {BaseType} T
|
182
175
|
*
|
183
176
|
*
|
184
177
|
* @param {string} name
|
package/jsconfig.json
CHANGED
package/migrate.js
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
import { Db, MongoClient } from 'mongodb';
|
2
|
+
import { MongoDB } from '../index.js'
|
3
|
+
import { templates } from '@storecraft/core/assets/seed-templates-v2.js'
|
4
|
+
|
5
|
+
/**
|
6
|
+
*
|
7
|
+
* @param {Db} db
|
8
|
+
* @param {MongoClient} client
|
9
|
+
*/
|
10
|
+
export async function up(db, client) {
|
11
|
+
|
12
|
+
const session = client.startSession();
|
13
|
+
try {
|
14
|
+
await session.withTransaction(
|
15
|
+
async (s) => {
|
16
|
+
/** @type {MongoDB} */
|
17
|
+
// @ts-ignore
|
18
|
+
const driver = client.__db_driver;
|
19
|
+
|
20
|
+
for (const template of templates) {
|
21
|
+
await driver.resources.templates.upsert(template, template.search);
|
22
|
+
}
|
23
|
+
}
|
24
|
+
);
|
25
|
+
} finally {
|
26
|
+
await session.endSession();
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
/**
|
31
|
+
*
|
32
|
+
* @param {Db} db
|
33
|
+
* @param {MongoClient} client
|
34
|
+
*/
|
35
|
+
export async function down(db, client) {
|
36
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@storecraft/database-mongodb",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.15",
|
4
4
|
"description": "Storecraft database driver for mongodb on node / bun / deno platform",
|
5
5
|
"license": "MIT",
|
6
6
|
"author": "Tomer Shalev (https://github.com/store-craft)",
|
@@ -24,6 +24,10 @@
|
|
24
24
|
"import": "./index.js",
|
25
25
|
"types": "./types.public.d.ts"
|
26
26
|
},
|
27
|
+
"./vector-store": {
|
28
|
+
"import": "./vector-store/index.js",
|
29
|
+
"types": "./vector-store/types.d.ts"
|
30
|
+
},
|
27
31
|
"./*": {
|
28
32
|
"import": "./*"
|
29
33
|
}
|
@@ -37,7 +41,7 @@
|
|
37
41
|
"dependencies": {
|
38
42
|
"@storecraft/core": "^1.0.0",
|
39
43
|
"migrate-mongo": "^11.0.0",
|
40
|
-
"mongodb": "^6.
|
44
|
+
"mongodb": "^6.14.0"
|
41
45
|
},
|
42
46
|
"devDependencies": {
|
43
47
|
"@types/migrate-mongo": "^10.0.4",
|
package/src/con.auth_users.js
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
+
/**
|
2
|
+
* @import { db_auth_users as db_col } from '@storecraft/core/database'
|
3
|
+
* @import { AuthUserType } from '@storecraft/core/api'
|
4
|
+
*/
|
5
|
+
|
1
6
|
import { MongoDB } from '../index.js'
|
2
7
|
import { Collection } from 'mongodb'
|
3
|
-
import {
|
8
|
+
import {
|
9
|
+
objid_or_else_filter, sanitize_one, to_objid_safe
|
10
|
+
} from './utils.funcs.js'
|
4
11
|
import {
|
5
12
|
count_regular, get_regular, list_regular, upsert_regular
|
6
13
|
} from './con.shared.js'
|
7
14
|
|
8
|
-
/**
|
9
|
-
* @typedef {import('@storecraft/core/database').db_auth_users} db_col
|
10
|
-
*/
|
11
|
-
|
12
15
|
/**
|
13
16
|
* @param {MongoDB} d
|
14
17
|
*
|
@@ -32,8 +35,6 @@ const upsert = (driver) => upsert_regular(driver, col(driver));
|
|
32
35
|
const get = (driver) => {
|
33
36
|
return async (id_or_email) => {
|
34
37
|
const filter = objid_or_else_filter(id_or_email, 'email');
|
35
|
-
|
36
|
-
/** @type {import('@storecraft/core/api').AuthUserType} */
|
37
38
|
const res = await col(driver).findOne(
|
38
39
|
filter
|
39
40
|
);
|
@@ -51,8 +52,6 @@ const get = (driver) => {
|
|
51
52
|
const getByEmail = (driver) => {
|
52
53
|
return async (email) => {
|
53
54
|
const filter = { email: email };
|
54
|
-
|
55
|
-
/** @type {import('@storecraft/core/api').AuthUserType} */
|
56
55
|
const res = await col(driver).findOne(
|
57
56
|
filter
|
58
57
|
);
|
@@ -100,7 +99,6 @@ const remove = (driver) => {
|
|
100
99
|
*/
|
101
100
|
const removeByEmail = (driver) => {
|
102
101
|
return async (email) => {
|
103
|
-
/** @type {import('@storecraft/core/api').AuthUserType} */
|
104
102
|
await col(driver).deleteOne(
|
105
103
|
{ email }
|
106
104
|
);
|
package/src/con.collections.js
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
* @import { db_collections as db_col } from '@storecraft/core/database'
|
3
|
+
* @import { ProductType, VariantType } from '@storecraft/core/api'
|
4
|
+
* @import { WithRelations } from './utils.relations.js'
|
5
|
+
* @import { Filter } from 'mongodb'
|
6
|
+
*/
|
7
|
+
|
1
8
|
import { Collection } from 'mongodb'
|
2
9
|
import { MongoDB } from '../index.js'
|
3
10
|
import { count_regular, expand, get_regular, list_regular } from './con.shared.js'
|
@@ -11,10 +18,6 @@ import {
|
|
11
18
|
update_entry_on_all_connection_of_relation
|
12
19
|
} from './utils.relations.js'
|
13
20
|
|
14
|
-
/**
|
15
|
-
* @typedef {import('@storecraft/core/database').db_collections} db_col
|
16
|
-
*/
|
17
|
-
|
18
21
|
|
19
22
|
const transactionOptions = {
|
20
23
|
readPreference: 'primary',
|
@@ -26,9 +29,7 @@ const transactionOptions = {
|
|
26
29
|
* @param {MongoDB} d
|
27
30
|
*
|
28
31
|
*
|
29
|
-
* @returns {Collection<
|
30
|
-
* import('./utils.relations.js').WithRelations<db_col["$type_get"]>
|
31
|
-
* >}
|
32
|
+
* @returns {Collection<WithRelations<db_col["$type_get"]>>}
|
32
33
|
*/
|
33
34
|
const col = (d) => d.collection('collections');
|
34
35
|
|
@@ -175,7 +176,9 @@ const count = (driver) => count_regular(driver, col(driver));
|
|
175
176
|
const list_collection_products = (driver) => {
|
176
177
|
return async (handle_or_id, query) => {
|
177
178
|
|
178
|
-
const {
|
179
|
+
const {
|
180
|
+
filter: filter_query, sort, reverse_sign
|
181
|
+
} = query_to_mongo(query);
|
179
182
|
|
180
183
|
// console.log('query', query)
|
181
184
|
// console.log('filter', JSON.stringify(filter_query, null, 2))
|
@@ -183,12 +186,8 @@ const list_collection_products = (driver) => {
|
|
183
186
|
// console.log('expand', query?.expand)
|
184
187
|
|
185
188
|
/**
|
186
|
-
* @type {
|
187
|
-
*
|
188
|
-
* import('@storecraft/core/api').ProductType |
|
189
|
-
* import('@storecraft/core/api').VariantType
|
190
|
-
* >
|
191
|
-
* >}
|
189
|
+
* @type {Filter<WithRelations<ProductType | VariantType>>
|
190
|
+
* }
|
192
191
|
*/
|
193
192
|
const filter = {
|
194
193
|
$and: [
|
package/src/con.customers.js
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
* @import { db_customers as db_col } from '@storecraft/core/database'
|
3
|
+
* @import { OrderData } from '@storecraft/core/api'
|
4
|
+
* @import { WithRelations } from './utils.relations.js'
|
5
|
+
* @import { Filter } from 'mongodb'
|
6
|
+
*/
|
7
|
+
|
1
8
|
import { Collection, ObjectId } from 'mongodb'
|
2
9
|
import { MongoDB } from '../index.js'
|
3
10
|
import { count_regular, get_regular, list_regular,
|
@@ -5,10 +12,6 @@ import { count_regular, get_regular, list_regular,
|
|
5
12
|
import { isDef, sanitize_array, to_objid } from './utils.funcs.js'
|
6
13
|
import { query_to_mongo } from './utils.query.js';
|
7
14
|
|
8
|
-
/**
|
9
|
-
* @typedef {import('@storecraft/core/database').db_customers} db_col
|
10
|
-
*/
|
11
|
-
|
12
15
|
/**
|
13
16
|
* @param {MongoDB} d
|
14
17
|
*
|
@@ -122,13 +125,7 @@ const list_customer_orders = (driver) => {
|
|
122
125
|
console.log('sort', sort)
|
123
126
|
console.log('expand', query?.expand)
|
124
127
|
|
125
|
-
/**
|
126
|
-
* @type {import('mongodb').Filter<
|
127
|
-
* import('./utils.relations.js').WithRelations<
|
128
|
-
* import('@storecraft/core/api').OrderData
|
129
|
-
* >
|
130
|
-
* >}
|
131
|
-
*/
|
128
|
+
/** @type {Filter<WithRelations<OrderData>>} */
|
132
129
|
const filter = {
|
133
130
|
$and: [
|
134
131
|
{'_relations.search': `customer:${customer_id}` },
|
package/src/con.discounts.js
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
* @import { db_discounts as db_col } from '@storecraft/core/database'
|
3
|
+
* @import { ProductType, VariantType } from '@storecraft/core/api'
|
4
|
+
* @import { WithRelations } from './utils.relations.js'
|
5
|
+
* @import { Filter } from 'mongodb'
|
6
|
+
*/
|
7
|
+
|
1
8
|
import { Collection } from 'mongodb'
|
2
9
|
import { MongoDB } from '../index.js'
|
3
10
|
import {
|
@@ -18,11 +25,6 @@ import {
|
|
18
25
|
} from './utils.relations.js'
|
19
26
|
|
20
27
|
|
21
|
-
/**
|
22
|
-
* @typedef {import('@storecraft/core/database').db_discounts} db_col
|
23
|
-
*/
|
24
|
-
|
25
|
-
|
26
28
|
/**
|
27
29
|
* @param {MongoDB} d
|
28
30
|
*
|
@@ -208,14 +210,7 @@ const list_discount_products = (driver) => {
|
|
208
210
|
// console.log('sort', sort)
|
209
211
|
// console.log('expand', query?.expand)
|
210
212
|
|
211
|
-
/**
|
212
|
-
* @type {import('mongodb').Filter<
|
213
|
-
* import('./utils.relations.js').WithRelations<
|
214
|
-
* import('@storecraft/core/api').ProductType |
|
215
|
-
* import('@storecraft/core/api').VariantType
|
216
|
-
* >
|
217
|
-
* >}
|
218
|
-
*/
|
213
|
+
/** @type {Filter<WithRelations<ProductType | VariantType>>} */
|
219
214
|
const filter = {
|
220
215
|
$and: [
|
221
216
|
{ '_relations.search': `discount:${handle_or_id}` },
|
@@ -1,12 +1,20 @@
|
|
1
|
+
/**
|
2
|
+
* @import {
|
3
|
+
* DiscountType, FilterValue_p_in_price_range, FilterValue_p_not_in_collections,
|
4
|
+
* FilterValue_p_in_collections, FilterValue_p_not_in_tags, FilterValue_p_in_tags,
|
5
|
+
* FilterValue_p_in_products, FilterValue_p_not_in_products
|
6
|
+
* } from '@storecraft/core/api'
|
7
|
+
*/
|
8
|
+
|
1
9
|
import { enums } from "@storecraft/core/api";
|
2
10
|
import { to_objid_safe } from "./utils.funcs.js";
|
3
11
|
|
4
|
-
/** @param {
|
12
|
+
/** @param {DiscountType} d */
|
5
13
|
const is_order_discount = d => {
|
6
14
|
return (d.info.details.meta.id===enums.DiscountMetaEnum.order.id);
|
7
15
|
}
|
8
16
|
|
9
|
-
/** @param {
|
17
|
+
/** @param {DiscountType} d */
|
10
18
|
const is_automatic_discount = d => {
|
11
19
|
return (d.application.id===enums.DiscountApplicationEnum.Auto.id);
|
12
20
|
}
|
@@ -20,7 +28,7 @@ const extract_abs_number = v => {
|
|
20
28
|
* for filtering.
|
21
29
|
*
|
22
30
|
*
|
23
|
-
* @param {
|
31
|
+
* @param {DiscountType} d
|
24
32
|
*/
|
25
33
|
export const discount_to_mongo_conjunctions = d => {
|
26
34
|
// discount has to be product discount + automatic + active + has filters
|
@@ -40,7 +48,7 @@ export const discount_to_mongo_conjunctions = d => {
|
|
40
48
|
break;
|
41
49
|
case enums.FilterMetaEnum.p_in_products.op:
|
42
50
|
{
|
43
|
-
const cast = /** @type {
|
51
|
+
const cast = /** @type {FilterValue_p_in_products} */ (
|
44
52
|
filter.value ?? []
|
45
53
|
);
|
46
54
|
|
@@ -51,7 +59,7 @@ export const discount_to_mongo_conjunctions = d => {
|
|
51
59
|
break;
|
52
60
|
case enums.FilterMetaEnum.p_not_in_products.op:
|
53
61
|
{
|
54
|
-
const cast = /** @type {
|
62
|
+
const cast = /** @type {FilterValue_p_not_in_products} */(
|
55
63
|
filter.value ?? []
|
56
64
|
);
|
57
65
|
|
@@ -62,7 +70,7 @@ export const discount_to_mongo_conjunctions = d => {
|
|
62
70
|
break;
|
63
71
|
case enums.FilterMetaEnum.p_in_tags.op:
|
64
72
|
{
|
65
|
-
const cast = /** @type {
|
73
|
+
const cast = /** @type {FilterValue_p_in_tags} */ (
|
66
74
|
filter.value ?? []
|
67
75
|
);
|
68
76
|
|
@@ -73,7 +81,7 @@ export const discount_to_mongo_conjunctions = d => {
|
|
73
81
|
break;
|
74
82
|
case enums.FilterMetaEnum.p_not_in_tags.op:
|
75
83
|
{
|
76
|
-
const cast = /** @type {
|
84
|
+
const cast = /** @type {FilterValue_p_not_in_tags} */(
|
77
85
|
filter.value ?? []
|
78
86
|
);
|
79
87
|
|
@@ -84,7 +92,7 @@ export const discount_to_mongo_conjunctions = d => {
|
|
84
92
|
break;
|
85
93
|
case enums.FilterMetaEnum.p_in_collections.op:
|
86
94
|
{
|
87
|
-
const cast = /** @type {
|
95
|
+
const cast = /** @type {FilterValue_p_in_collections} */ (
|
88
96
|
filter.value ?? []
|
89
97
|
);
|
90
98
|
|
@@ -99,7 +107,7 @@ export const discount_to_mongo_conjunctions = d => {
|
|
99
107
|
break;
|
100
108
|
case enums.FilterMetaEnum.p_not_in_collections.op:
|
101
109
|
{
|
102
|
-
const cast = /** @type {
|
110
|
+
const cast = /** @type {FilterValue_p_not_in_collections} */ (
|
103
111
|
filter.value ?? []
|
104
112
|
);
|
105
113
|
|
@@ -114,7 +122,7 @@ export const discount_to_mongo_conjunctions = d => {
|
|
114
122
|
break;
|
115
123
|
case enums.FilterMetaEnum.p_in_price_range.op:
|
116
124
|
{
|
117
|
-
const cast = /** @type {
|
125
|
+
const cast = /** @type {FilterValue_p_in_price_range} */ (
|
118
126
|
{
|
119
127
|
from: 0,
|
120
128
|
to: Number.POSITIVE_INFINITY,
|