ag-common 0.0.765 → 0.0.766
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/dist/api/helpers/cosmos/delete.d.ts +5 -0
- package/dist/api/helpers/cosmos/delete.js +111 -0
- package/dist/api/helpers/cosmos/get.d.ts +28 -0
- package/dist/api/helpers/cosmos/get.js +233 -0
- package/dist/api/helpers/cosmos/index.d.ts +44 -0
- package/dist/api/helpers/cosmos/index.js +80 -0
- package/dist/api/helpers/cosmos/utils.d.ts +9 -0
- package/dist/api/helpers/cosmos/utils.js +22 -0
- package/dist/api/helpers/cosmos/write.d.ts +9 -0
- package/dist/api/helpers/cosmos/write.js +107 -0
- package/dist/api/helpers/index.d.ts +1 -0
- package/dist/api/helpers/index.js +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Container } from '@azure/cosmos';
|
|
2
|
+
export declare function deleteItemCosmos(container: Container, pk: string): Promise<void>;
|
|
3
|
+
export declare function deleteItemsByField(container: Container, field: string, value: string | number | boolean): Promise<{
|
|
4
|
+
error?: string;
|
|
5
|
+
}>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.deleteItemCosmos = deleteItemCosmos;
|
|
13
|
+
exports.deleteItemsByField = deleteItemsByField;
|
|
14
|
+
const utils_1 = require("./utils");
|
|
15
|
+
const log_1 = require("../../../common/helpers/log");
|
|
16
|
+
const withRetry_1 = require("../withRetry");
|
|
17
|
+
function deleteItemCosmos(container, pk) {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
try {
|
|
20
|
+
// First query to find items with matching PK
|
|
21
|
+
const querySpec = {
|
|
22
|
+
query: 'SELECT * FROM c WHERE c.PK = @pk',
|
|
23
|
+
parameters: [{ name: '@pk', value: pk }],
|
|
24
|
+
};
|
|
25
|
+
const { resources: items } = yield container.items
|
|
26
|
+
.query(querySpec)
|
|
27
|
+
.fetchAll();
|
|
28
|
+
// Delete each found item and collect their IDs
|
|
29
|
+
for (const item of items) {
|
|
30
|
+
(0, log_1.warn)('deleting items:', item.id, pk);
|
|
31
|
+
yield container.item(item.id, pk).delete();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
const em = e.message;
|
|
36
|
+
(0, log_1.error)('Error deleting item:', em);
|
|
37
|
+
throw e;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function deleteItemsByField(container, field, value) {
|
|
42
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
try {
|
|
44
|
+
const query = `
|
|
45
|
+
SELECT c.id, c.PK
|
|
46
|
+
FROM c
|
|
47
|
+
WHERE c.${field} = @value
|
|
48
|
+
`;
|
|
49
|
+
const { resources } = yield container.items
|
|
50
|
+
.query({
|
|
51
|
+
query,
|
|
52
|
+
parameters: [{ name: '@value', value }],
|
|
53
|
+
})
|
|
54
|
+
.fetchAll();
|
|
55
|
+
if (resources.length === 0) {
|
|
56
|
+
return {};
|
|
57
|
+
}
|
|
58
|
+
(0, log_1.info)(`Deleting ${resources.length} items where ${field} = ${value} from Cosmos`);
|
|
59
|
+
//throw if item.id or PK doesn't exist on an item
|
|
60
|
+
resources.forEach((item) => {
|
|
61
|
+
if (!item.id || !item.PK) {
|
|
62
|
+
throw new Error('Item missing required fields: ' + JSON.stringify(item));
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
const operations = resources.map((item) => ({
|
|
66
|
+
id: item.id,
|
|
67
|
+
partitionKey: item.PK,
|
|
68
|
+
operationType: 'Delete',
|
|
69
|
+
}));
|
|
70
|
+
for (let i = 0; i < operations.length; i += utils_1.BULK_CHUNK_SIZE) {
|
|
71
|
+
const chunk = operations.slice(i, i + utils_1.BULK_CHUNK_SIZE);
|
|
72
|
+
// Execute bulk operation with retry
|
|
73
|
+
yield (0, withRetry_1.withRetry)(() => __awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
(0, log_1.info)(`Deleting chunk ${i / utils_1.BULK_CHUNK_SIZE + 1} of ${Math.ceil(operations.length / utils_1.BULK_CHUNK_SIZE)}`);
|
|
75
|
+
const bulkResponse = yield container.items.bulk(chunk);
|
|
76
|
+
//if an item contains a statuscode 429, then throw an error
|
|
77
|
+
bulkResponse.forEach((response) => {
|
|
78
|
+
if (response.statusCode === 429) {
|
|
79
|
+
throw new Error('429');
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
// Process results
|
|
83
|
+
let successCount = 0;
|
|
84
|
+
let failureCount = 0;
|
|
85
|
+
bulkResponse.forEach((response, index) => {
|
|
86
|
+
if (response.statusCode === 204) {
|
|
87
|
+
successCount++;
|
|
88
|
+
}
|
|
89
|
+
else if (response.statusCode === 404) {
|
|
90
|
+
failureCount++;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const item = chunk[index];
|
|
94
|
+
(0, log_1.error)(`Failed to delete item - ID: ${item.id}, PK: ${item.partitionKey}, Status: ${response.statusCode}`, response.resourceBody);
|
|
95
|
+
failureCount++;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
(0, log_1.info)(`Chunk ${i / utils_1.BULK_CHUNK_SIZE + 1}/${Math.ceil(operations.length / utils_1.BULK_CHUNK_SIZE)} results - Success: ${successCount}, Failed: ${failureCount}`);
|
|
99
|
+
return bulkResponse;
|
|
100
|
+
}), `bulk_delete_chunk_${i / utils_1.BULK_CHUNK_SIZE + 1}`);
|
|
101
|
+
}
|
|
102
|
+
(0, log_1.info)('All items deleted successfully');
|
|
103
|
+
return {};
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
const em = e.message;
|
|
107
|
+
(0, log_1.error)('Error deleting items:', em);
|
|
108
|
+
throw e;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Container } from '@azure/cosmos';
|
|
2
|
+
export declare function getItemCosmos<T>(container: Container, partitionValue: string): Promise<T | null>;
|
|
3
|
+
export declare function getItemsByCosmos<T>(container: Container, partitionValues: string[]): Promise<T[]>;
|
|
4
|
+
export declare function queryItemsByText<T>(container: Container, searchFields: {
|
|
5
|
+
fieldName: string;
|
|
6
|
+
fieldValue: string;
|
|
7
|
+
type: 'contains' | 'equals';
|
|
8
|
+
}[], operator?: 'AND' | 'OR'): Promise<T[] | {
|
|
9
|
+
error: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function scanCosmos<T>(container: Container): Promise<T[] | {
|
|
12
|
+
error: string;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function queryItemsByNumber<T>(container: Container, options: {
|
|
15
|
+
type: string;
|
|
16
|
+
field: string;
|
|
17
|
+
minValue?: number;
|
|
18
|
+
limit?: number;
|
|
19
|
+
descending?: boolean;
|
|
20
|
+
}): Promise<T[] | {
|
|
21
|
+
error: string;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function queryItemsByType<T>(container: Container, type: string): Promise<T[] | {
|
|
24
|
+
error: string;
|
|
25
|
+
}>;
|
|
26
|
+
export declare function queryItemsByRelevancy<T>(container: Container, type: string, limit?: number): Promise<T[] | {
|
|
27
|
+
error: string;
|
|
28
|
+
}>;
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getItemCosmos = getItemCosmos;
|
|
16
|
+
exports.getItemsByCosmos = getItemsByCosmos;
|
|
17
|
+
exports.queryItemsByText = queryItemsByText;
|
|
18
|
+
exports.scanCosmos = scanCosmos;
|
|
19
|
+
exports.queryItemsByNumber = queryItemsByNumber;
|
|
20
|
+
exports.queryItemsByType = queryItemsByType;
|
|
21
|
+
exports.queryItemsByRelevancy = queryItemsByRelevancy;
|
|
22
|
+
const log_1 = require("../../../common/helpers/log");
|
|
23
|
+
const node_cache_1 = __importDefault(require("node-cache"));
|
|
24
|
+
// Create a NodeCache instance with 5 second TTL
|
|
25
|
+
const cache = new node_cache_1.default({ stdTTL: 5 });
|
|
26
|
+
function getItemCosmos(container, partitionValue) {
|
|
27
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
try {
|
|
29
|
+
const querySpec = {
|
|
30
|
+
query: 'SELECT TOP 1 * FROM c WHERE c.PK = @val',
|
|
31
|
+
parameters: [
|
|
32
|
+
{
|
|
33
|
+
name: '@val',
|
|
34
|
+
value: partitionValue,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
const { resources, requestCharge } = yield container.items
|
|
39
|
+
.query(querySpec)
|
|
40
|
+
.fetchAll();
|
|
41
|
+
(0, log_1.info)(`getItemCosmos:${partitionValue}. chg=${requestCharge}`);
|
|
42
|
+
if (resources.length > 0) {
|
|
43
|
+
return resources[0];
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
if (e.message.includes('404')) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const em = e.message;
|
|
54
|
+
(0, log_1.error)('Error deleting item:', em);
|
|
55
|
+
throw e;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function getItemsByCosmos(container, partitionValues) {
|
|
60
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
try {
|
|
62
|
+
if (!partitionValues.length) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
const querySpec = {
|
|
66
|
+
query: 'SELECT * FROM c WHERE ARRAY_CONTAINS(@values, c.PK)',
|
|
67
|
+
parameters: [
|
|
68
|
+
{
|
|
69
|
+
name: '@values',
|
|
70
|
+
value: partitionValues,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
const { resources, requestCharge } = yield container.items
|
|
75
|
+
.query(querySpec)
|
|
76
|
+
.fetchAll();
|
|
77
|
+
(0, log_1.info)(`getItemsByCosmos: fetched ${resources.length} items. chg=${requestCharge}`);
|
|
78
|
+
return resources;
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
const em = e.message;
|
|
82
|
+
(0, log_1.error)('Error getting multiple items:', em);
|
|
83
|
+
throw e;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function escapeSqlString(str) {
|
|
88
|
+
return str.replace(/'/g, "''");
|
|
89
|
+
}
|
|
90
|
+
function queryItemsCosmos(container, query, parameters) {
|
|
91
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
92
|
+
try {
|
|
93
|
+
const querySpec = {
|
|
94
|
+
query,
|
|
95
|
+
parameters: parameters
|
|
96
|
+
? Object.entries(parameters).map(([name, value]) => ({
|
|
97
|
+
name: `@${name}`,
|
|
98
|
+
value,
|
|
99
|
+
}))
|
|
100
|
+
: undefined,
|
|
101
|
+
};
|
|
102
|
+
const { resources, requestCharge } = yield container.items
|
|
103
|
+
.query(querySpec)
|
|
104
|
+
.fetchAll();
|
|
105
|
+
return { resources, requestCharge };
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
const em = e.message;
|
|
109
|
+
(0, log_1.error)('Error queryItemsCosmos item:', em);
|
|
110
|
+
return { error: em };
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function queryItemsByText(container_1, searchFields_1) {
|
|
115
|
+
return __awaiter(this, arguments, void 0, function* (container, searchFields, operator = 'AND') {
|
|
116
|
+
try {
|
|
117
|
+
const conditions = searchFields.map((field, index) => field.type === 'contains' //true to ignore case
|
|
118
|
+
? `CONTAINS(c.${field.fieldName}, @value${index}, true)`
|
|
119
|
+
: `c.${field.fieldName} = @value${index}`);
|
|
120
|
+
const query = `SELECT * FROM c WHERE ${conditions.join(` ${operator} `)}`;
|
|
121
|
+
const parameters = searchFields.reduce((acc, field, index) => {
|
|
122
|
+
acc[`value${index}`] = escapeSqlString(field.fieldValue);
|
|
123
|
+
return acc;
|
|
124
|
+
}, {});
|
|
125
|
+
const x = yield queryItemsCosmos(container, query, parameters);
|
|
126
|
+
(0, log_1.debug)(`queryItemsByText: ${JSON.stringify(searchFields)}, operator=${operator}. chg=${x.requestCharge}`);
|
|
127
|
+
if ('error' in x) {
|
|
128
|
+
throw x.error;
|
|
129
|
+
}
|
|
130
|
+
return x.resources;
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
const em = e.message;
|
|
134
|
+
(0, log_1.error)('Error queryItemsByText item:', em);
|
|
135
|
+
return { error: em };
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function scanCosmos(container) {
|
|
140
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
141
|
+
try {
|
|
142
|
+
const query = `SELECT * FROM c`;
|
|
143
|
+
const x = yield queryItemsCosmos(container, query, {});
|
|
144
|
+
(0, log_1.info)(`scan. chg=${x.requestCharge}`);
|
|
145
|
+
if ('error' in x) {
|
|
146
|
+
throw x.error;
|
|
147
|
+
}
|
|
148
|
+
return x.resources;
|
|
149
|
+
}
|
|
150
|
+
catch (e) {
|
|
151
|
+
const em = e.message;
|
|
152
|
+
(0, log_1.error)('Error queryItemsByText item:', em);
|
|
153
|
+
return { error: em };
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function queryItemsByNumber(container, options) {
|
|
158
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
+
try {
|
|
160
|
+
const { type, field, minValue = 0, limit, descending = true } = options;
|
|
161
|
+
const query = `
|
|
162
|
+
SELECT * FROM c
|
|
163
|
+
WHERE IS_NUMBER(c.${field})
|
|
164
|
+
AND c.${field} > @minValue
|
|
165
|
+
AND c.type = @type
|
|
166
|
+
ORDER BY c.${field} ${descending ? 'DESC' : 'ASC'}
|
|
167
|
+
${limit ? 'OFFSET 0 LIMIT @limit' : ''}
|
|
168
|
+
`;
|
|
169
|
+
const parameters = {
|
|
170
|
+
type,
|
|
171
|
+
minValue,
|
|
172
|
+
};
|
|
173
|
+
if (limit) {
|
|
174
|
+
parameters.limit = limit;
|
|
175
|
+
}
|
|
176
|
+
const x = yield queryItemsCosmos(container, query, parameters);
|
|
177
|
+
(0, log_1.debug)(`queryItemsByNumber: type=${type}, field=${field}, minValue=${minValue}, limit=${limit}. chg=${x.requestCharge}`);
|
|
178
|
+
if ('error' in x) {
|
|
179
|
+
throw x.error;
|
|
180
|
+
}
|
|
181
|
+
return x.resources;
|
|
182
|
+
}
|
|
183
|
+
catch (e) {
|
|
184
|
+
const em = e.message;
|
|
185
|
+
(0, log_1.error)('Error queryItemsByNumber:', em);
|
|
186
|
+
return { error: em };
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
function queryItemsByType(container, type) {
|
|
191
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
192
|
+
try {
|
|
193
|
+
// Check if data is in cache
|
|
194
|
+
const cacheKey = `queryItemsByType:${type}`;
|
|
195
|
+
const cachedData = cache.get(cacheKey);
|
|
196
|
+
if (cachedData) {
|
|
197
|
+
(0, log_1.info)(`queryItemsByType: type=${type}. [CACHE HIT]`);
|
|
198
|
+
return cachedData;
|
|
199
|
+
}
|
|
200
|
+
const query = `
|
|
201
|
+
SELECT * FROM c
|
|
202
|
+
WHERE c.type = @type
|
|
203
|
+
`;
|
|
204
|
+
const parameters = {
|
|
205
|
+
type,
|
|
206
|
+
};
|
|
207
|
+
const x = yield queryItemsCosmos(container, query, parameters);
|
|
208
|
+
(0, log_1.info)(`queryItemsByType: type=${type}. chg=${x.requestCharge}`);
|
|
209
|
+
if ('error' in x) {
|
|
210
|
+
throw x.error;
|
|
211
|
+
}
|
|
212
|
+
const result = x.resources;
|
|
213
|
+
// Store result in cache
|
|
214
|
+
cache.set(cacheKey, result);
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
const em = e.message;
|
|
219
|
+
(0, log_1.error)('Error queryItemsByType:', em);
|
|
220
|
+
return { error: em };
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function queryItemsByRelevancy(container, type, limit) {
|
|
225
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
226
|
+
return queryItemsByNumber(container, {
|
|
227
|
+
type,
|
|
228
|
+
field: 'relevancy',
|
|
229
|
+
limit,
|
|
230
|
+
descending: true,
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type CosmosSettings } from './utils';
|
|
2
|
+
export declare class Cosmos {
|
|
3
|
+
private container;
|
|
4
|
+
constructor(settings: CosmosSettings);
|
|
5
|
+
getItem<T>(partitionValue: string): Promise<T | null>;
|
|
6
|
+
getItemsBy<T>(partitionValues: string[]): Promise<T[]>;
|
|
7
|
+
queryItemsByText<T>(searchFields: {
|
|
8
|
+
fieldName: string;
|
|
9
|
+
fieldValue: string;
|
|
10
|
+
type: 'contains' | 'equals';
|
|
11
|
+
}[], operator?: 'AND' | 'OR'): Promise<T[] | {
|
|
12
|
+
error: string;
|
|
13
|
+
}>;
|
|
14
|
+
scan<T>(): Promise<T[] | {
|
|
15
|
+
error: string;
|
|
16
|
+
}>;
|
|
17
|
+
queryItemsByNumber<T>(options: {
|
|
18
|
+
type: string;
|
|
19
|
+
field: string;
|
|
20
|
+
minValue?: number;
|
|
21
|
+
limit?: number;
|
|
22
|
+
descending?: boolean;
|
|
23
|
+
}): Promise<T[] | {
|
|
24
|
+
error: string;
|
|
25
|
+
}>;
|
|
26
|
+
queryItemsByType<T>(type: string): Promise<T[] | {
|
|
27
|
+
error: string;
|
|
28
|
+
}>;
|
|
29
|
+
queryItemsByRelevancy<T>(type: string, limit?: number): Promise<T[] | {
|
|
30
|
+
error: string;
|
|
31
|
+
}>;
|
|
32
|
+
putItem<T extends {
|
|
33
|
+
PK: string;
|
|
34
|
+
}>(item: T): Promise<T>;
|
|
35
|
+
putItems<T extends {
|
|
36
|
+
PK: string;
|
|
37
|
+
}>(items: T[]): Promise<{
|
|
38
|
+
error?: string;
|
|
39
|
+
}>;
|
|
40
|
+
deleteItem(pk: string): Promise<void>;
|
|
41
|
+
deleteItemsByField(field: string, value: string | number | boolean): Promise<{
|
|
42
|
+
error?: string;
|
|
43
|
+
}>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Cosmos = void 0;
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
const delete_1 = require("./delete");
|
|
15
|
+
const get_1 = require("./get");
|
|
16
|
+
const write_1 = require("./write");
|
|
17
|
+
class Cosmos {
|
|
18
|
+
constructor(settings) {
|
|
19
|
+
this.container = (0, utils_1.createContainer)(settings);
|
|
20
|
+
}
|
|
21
|
+
// Get operations
|
|
22
|
+
getItem(partitionValue) {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
return (0, get_1.getItemCosmos)(this.container, partitionValue);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
getItemsBy(partitionValues) {
|
|
28
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
return (0, get_1.getItemsByCosmos)(this.container, partitionValues);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
queryItemsByText(searchFields_1) {
|
|
33
|
+
return __awaiter(this, arguments, void 0, function* (searchFields, operator = 'AND') {
|
|
34
|
+
return (0, get_1.queryItemsByText)(this.container, searchFields, operator);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
scan() {
|
|
38
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
return (0, get_1.scanCosmos)(this.container);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
queryItemsByNumber(options) {
|
|
43
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
return (0, get_1.queryItemsByNumber)(this.container, options);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
queryItemsByType(type) {
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
return (0, get_1.queryItemsByType)(this.container, type);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
queryItemsByRelevancy(type, limit) {
|
|
53
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
return (0, get_1.queryItemsByRelevancy)(this.container, type, limit);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// Write operations
|
|
58
|
+
putItem(item) {
|
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
return (0, write_1.putItemCosmos)(this.container, item);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
putItems(items) {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
return (0, write_1.putItemsCosmos)(this.container, items);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
// Delete operations
|
|
69
|
+
deleteItem(pk) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
return (0, delete_1.deleteItemCosmos)(this.container, pk);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
deleteItemsByField(field, value) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
return (0, delete_1.deleteItemsByField)(this.container, field, value);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.Cosmos = Cosmos;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Container } from '@azure/cosmos';
|
|
2
|
+
export declare const BULK_CHUNK_SIZE = 50;
|
|
3
|
+
export interface CosmosSettings {
|
|
4
|
+
endpoint: string;
|
|
5
|
+
key: string;
|
|
6
|
+
database_name: string;
|
|
7
|
+
container_name: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function createContainer(settings: CosmosSettings): Container;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BULK_CHUNK_SIZE = void 0;
|
|
4
|
+
exports.createContainer = createContainer;
|
|
5
|
+
const cosmos_1 = require("@azure/cosmos");
|
|
6
|
+
exports.BULK_CHUNK_SIZE = 50;
|
|
7
|
+
function createContainer(settings) {
|
|
8
|
+
if (!settings.endpoint ||
|
|
9
|
+
!settings.key ||
|
|
10
|
+
!settings.database_name ||
|
|
11
|
+
!settings.container_name) {
|
|
12
|
+
throw new Error('no cosmos settings');
|
|
13
|
+
}
|
|
14
|
+
const client = new cosmos_1.CosmosClient(settings);
|
|
15
|
+
const database = client.database(settings.database_name);
|
|
16
|
+
const container = database.container(settings.container_name);
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
18
|
+
if (!container) {
|
|
19
|
+
throw new Error('error, cosmos container undefined!!');
|
|
20
|
+
}
|
|
21
|
+
return container;
|
|
22
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Container } from '@azure/cosmos';
|
|
2
|
+
export declare function putItemCosmos<T extends {
|
|
3
|
+
PK: string;
|
|
4
|
+
}>(container: Container, item: T): Promise<T>;
|
|
5
|
+
export declare function putItemsCosmos<T extends {
|
|
6
|
+
PK: string;
|
|
7
|
+
}>(container: Container, items: T[]): Promise<{
|
|
8
|
+
error?: string;
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.putItemCosmos = putItemCosmos;
|
|
13
|
+
exports.putItemsCosmos = putItemsCosmos;
|
|
14
|
+
const withRetry_1 = require("../withRetry");
|
|
15
|
+
const log_1 = require("../../../common/helpers/log");
|
|
16
|
+
const utils_1 = require("./utils");
|
|
17
|
+
function putItemCosmos(container, item) {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
try {
|
|
20
|
+
// First, try to find existing item with the same PK
|
|
21
|
+
const querySpec = {
|
|
22
|
+
query: 'SELECT * FROM c WHERE c.PK = @pk',
|
|
23
|
+
parameters: [{ name: '@pk', value: item.PK }],
|
|
24
|
+
};
|
|
25
|
+
const { resources: existingItems } = yield container.items
|
|
26
|
+
.query(querySpec)
|
|
27
|
+
.fetchAll();
|
|
28
|
+
if (existingItems.length > 0) {
|
|
29
|
+
// If item exists, update it with the existing ID
|
|
30
|
+
const existingItem = existingItems[0];
|
|
31
|
+
const updatedItem = Object.assign(Object.assign({}, item), { id: existingItem.id });
|
|
32
|
+
const { resource: result } = yield container.items.upsert(updatedItem);
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// If no existing item, create new one (let Cosmos generate the id)
|
|
37
|
+
const newItem = Object.assign(Object.assign({}, item), { id: undefined });
|
|
38
|
+
const { resource: result } = yield container.items.create(newItem);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
const em = e.message;
|
|
44
|
+
(0, log_1.error)('Error upserting item:', em);
|
|
45
|
+
throw e;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function putItemsCosmos(container, items) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
try {
|
|
52
|
+
if (items.length === 0) {
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
(0, log_1.info)(`Bulk writing ${items.length} items to Cosmos`);
|
|
56
|
+
for (let i = 0; i < items.length; i += utils_1.BULK_CHUNK_SIZE) {
|
|
57
|
+
const chunk = items.slice(i, i + utils_1.BULK_CHUNK_SIZE);
|
|
58
|
+
// Execute bulk operation with retry
|
|
59
|
+
yield (0, withRetry_1.withRetry)(() => __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
(0, log_1.info)(`Writing chunk ${i / utils_1.BULK_CHUNK_SIZE + 1} of ${Math.ceil(items.length / utils_1.BULK_CHUNK_SIZE)}`);
|
|
61
|
+
const operations = yield Promise.all(chunk.map((item) => __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
// Query to check if item exists
|
|
63
|
+
const querySpec = {
|
|
64
|
+
query: 'SELECT * FROM c WHERE c.PK = @pk',
|
|
65
|
+
parameters: [{ name: '@pk', value: item.PK }],
|
|
66
|
+
};
|
|
67
|
+
const { resources: existingItems } = yield container.items
|
|
68
|
+
.query(querySpec)
|
|
69
|
+
.fetchAll();
|
|
70
|
+
const existingItem = existingItems[0];
|
|
71
|
+
return {
|
|
72
|
+
operationType: 'Upsert',
|
|
73
|
+
partitionKey: item.PK,
|
|
74
|
+
resourceBody: Object.assign(Object.assign({}, item), { id: existingItem === null || existingItem === void 0 ? void 0 : existingItem.id }),
|
|
75
|
+
};
|
|
76
|
+
})));
|
|
77
|
+
const bulkResponse = yield container.items.bulk(operations);
|
|
78
|
+
// Process results
|
|
79
|
+
let successCount = 0;
|
|
80
|
+
let failureCount = 0;
|
|
81
|
+
bulkResponse.forEach((response, index) => {
|
|
82
|
+
if (response.statusCode === 429) {
|
|
83
|
+
throw new Error('429');
|
|
84
|
+
}
|
|
85
|
+
if (response.statusCode >= 200 && response.statusCode < 300) {
|
|
86
|
+
successCount++;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const item = chunk[index];
|
|
90
|
+
(0, log_1.error)(`Failed to write item - PK: ${item.PK}, Status: ${response.statusCode}`, response.resourceBody);
|
|
91
|
+
failureCount++;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
(0, log_1.info)(`Chunk ${i / utils_1.BULK_CHUNK_SIZE + 1}/${Math.ceil(items.length / utils_1.BULK_CHUNK_SIZE)} results - Success: ${successCount}, Failed: ${failureCount}`);
|
|
95
|
+
return bulkResponse;
|
|
96
|
+
}), `bulk_write_chunk_${i / utils_1.BULK_CHUNK_SIZE + 1}`);
|
|
97
|
+
}
|
|
98
|
+
(0, log_1.info)('All items written successfully');
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
const em = e.message;
|
|
103
|
+
(0, log_1.error)('Error bulk writing items:', em);
|
|
104
|
+
throw e;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.0.
|
|
2
|
+
"version": "0.0.766",
|
|
3
3
|
"name": "ag-common",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
@@ -25,10 +25,12 @@
|
|
|
25
25
|
"@aws-sdk/client-sts": "^3.879.0",
|
|
26
26
|
"@aws-sdk/lib-dynamodb": "^3.879.0",
|
|
27
27
|
"@aws-sdk/s3-presigned-post": "^3.879.0",
|
|
28
|
+
"@azure/cosmos": "^4.5.1",
|
|
28
29
|
"aws-cdk-lib": "^2.213.0",
|
|
29
30
|
"buffer": "^6.0.3",
|
|
30
31
|
"jsonwebtoken": "^9.0.2",
|
|
31
32
|
"jwks-rsa": "^3.2.0",
|
|
33
|
+
"node-cache": "^5.1.2",
|
|
32
34
|
"react": "^19.1.1",
|
|
33
35
|
"react-dom": "^19.1.1",
|
|
34
36
|
"typescript": "^5.9.2"
|