@cloudbase/database 0.11.0 → 0.12.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/dist/commonjs/collection.d.ts +1 -1
- package/dist/commonjs/document.js +16 -6
- package/dist/commonjs/transaction/query.d.ts +39 -1
- package/dist/commonjs/transaction/query.js +251 -1
- package/dist/esm/collection.d.ts +1 -1
- package/dist/esm/document.js +16 -6
- package/dist/esm/transaction/query.d.ts +39 -1
- package/dist/esm/transaction/query.js +251 -1
- package/package.json +1 -1
- package/src/collection.ts +4 -3
- package/src/document.ts +17 -9
- package/src/transaction/query.ts +355 -2
- package/tests/transaction-query.test.ts +657 -0
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -101
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -0
- package/dist/esm/aggregate.d.ts.map +0 -1
- package/dist/esm/collection.d.ts.map +0 -1
- package/dist/esm/command.d.ts.map +0 -1
- package/dist/esm/commands/logic.d.ts.map +0 -1
- package/dist/esm/commands/query.d.ts.map +0 -1
- package/dist/esm/commands/update.d.ts.map +0 -1
- package/dist/esm/config/app.config.d.ts.map +0 -1
- package/dist/esm/config/error.config.d.ts.map +0 -1
- package/dist/esm/const/code.d.ts.map +0 -1
- package/dist/esm/constant.d.ts.map +0 -1
- package/dist/esm/document.d.ts.map +0 -1
- package/dist/esm/geo/index.d.ts.map +0 -1
- package/dist/esm/geo/interface.d.ts.map +0 -1
- package/dist/esm/geo/lineString.d.ts.map +0 -1
- package/dist/esm/geo/multiLineString.d.ts.map +0 -1
- package/dist/esm/geo/multiPoint.d.ts.map +0 -1
- package/dist/esm/geo/multiPolygon.d.ts.map +0 -1
- package/dist/esm/geo/point.d.ts.map +0 -1
- package/dist/esm/geo/polygon.d.ts.map +0 -1
- package/dist/esm/helper/symbol.d.ts.map +0 -1
- package/dist/esm/index.d.ts.map +0 -1
- package/dist/esm/lib/util.d.ts.map +0 -1
- package/dist/esm/operator-map.d.ts.map +0 -1
- package/dist/esm/query.d.ts.map +0 -1
- package/dist/esm/regexp/index.d.ts.map +0 -1
- package/dist/esm/serializer/common.d.ts.map +0 -1
- package/dist/esm/serializer/datatype.d.ts.map +0 -1
- package/dist/esm/serializer/query.d.ts.map +0 -1
- package/dist/esm/serializer/update.d.ts.map +0 -1
- package/dist/esm/serverDate/index.d.ts.map +0 -1
- package/dist/esm/transaction/collection.d.ts.map +0 -1
- package/dist/esm/transaction/document.d.ts.map +0 -1
- package/dist/esm/transaction/index.d.ts.map +0 -1
- package/dist/esm/transaction/query.d.ts.map +0 -1
- package/dist/esm/typings/index.d.ts.map +0 -1
- package/dist/esm/typings/realtime.d.ts.map +0 -1
- package/dist/esm/util.d.ts.map +0 -1
- package/dist/esm/utils/error.d.ts.map +0 -1
- package/dist/esm/utils/msg.d.ts.map +0 -1
- package/dist/esm/utils/symbol.d.ts.map +0 -1
- package/dist/esm/utils/type.d.ts.map +0 -1
- package/dist/esm/utils/utils.d.ts.map +0 -1
- package/dist/esm/validate.d.ts.map +0 -1
|
@@ -1,8 +1,258 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
13
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
14
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
22
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
23
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
24
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
25
|
+
function step(op) {
|
|
26
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
27
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
28
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
29
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
30
|
+
switch (op[0]) {
|
|
31
|
+
case 0: case 1: t = op; break;
|
|
32
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
33
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
+
default:
|
|
36
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
+
if (t[2]) _.ops.pop();
|
|
41
|
+
_.trys.pop(); continue;
|
|
42
|
+
}
|
|
43
|
+
op = body.call(thisArg, _);
|
|
44
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
import { EJSON } from 'bson';
|
|
49
|
+
import { ErrorCode } from '../constant';
|
|
50
|
+
import { Validate } from '../validate';
|
|
51
|
+
import { QuerySerializer } from '../serializer/query';
|
|
52
|
+
import { UpdateSerializer } from '../serializer/update';
|
|
53
|
+
import { Util } from '../util';
|
|
54
|
+
var GET_DOC = 'database.getInTransaction';
|
|
55
|
+
var UPDATE_DOC = 'database.updateDocInTransaction';
|
|
56
|
+
var DELETE_DOC = 'database.deleteDocInTransaction';
|
|
1
57
|
var Query = (function () {
|
|
2
|
-
function Query(transaction, coll) {
|
|
58
|
+
function Query(transaction, coll, fieldFilters, fieldOrders, queryOptions) {
|
|
3
59
|
this._coll = coll;
|
|
4
60
|
this._transaction = transaction;
|
|
61
|
+
this._fieldFilters = fieldFilters;
|
|
62
|
+
this._fieldOrders = fieldOrders || [];
|
|
63
|
+
this._queryOptions = queryOptions || {};
|
|
64
|
+
this._request = this._transaction.getRequestMethod();
|
|
65
|
+
this._transactionId = this._transaction.getTransactionId();
|
|
5
66
|
}
|
|
67
|
+
Query.prototype.where = function (query) {
|
|
68
|
+
if (Object.prototype.toString.call(query).slice(8, -1) !== 'Object') {
|
|
69
|
+
throw Error(ErrorCode.QueryParamTypeError);
|
|
70
|
+
}
|
|
71
|
+
var keys = Object.keys(query);
|
|
72
|
+
var checkFlag = keys.some(function (item) {
|
|
73
|
+
return query[item] !== undefined;
|
|
74
|
+
});
|
|
75
|
+
if (keys.length && !checkFlag) {
|
|
76
|
+
throw Error(ErrorCode.QueryParamValueError);
|
|
77
|
+
}
|
|
78
|
+
return new Query(this._transaction, this._coll, QuerySerializer.encode(query), this._fieldOrders, this._queryOptions);
|
|
79
|
+
};
|
|
80
|
+
Query.prototype.orderBy = function (fieldPath, directionStr) {
|
|
81
|
+
Validate.isFieldPath(fieldPath);
|
|
82
|
+
Validate.isFieldOrder(directionStr);
|
|
83
|
+
var newOrder = {
|
|
84
|
+
field: fieldPath,
|
|
85
|
+
direction: directionStr
|
|
86
|
+
};
|
|
87
|
+
var combinedOrders = this._fieldOrders.concat(newOrder);
|
|
88
|
+
return new Query(this._transaction, this._coll, this._fieldFilters, combinedOrders, this._queryOptions);
|
|
89
|
+
};
|
|
90
|
+
Query.prototype.limit = function (limit) {
|
|
91
|
+
Validate.isInteger('limit', limit);
|
|
92
|
+
var option = __assign({}, this._queryOptions);
|
|
93
|
+
option.limit = limit;
|
|
94
|
+
return new Query(this._transaction, this._coll, this._fieldFilters, this._fieldOrders, option);
|
|
95
|
+
};
|
|
96
|
+
Query.prototype.skip = function (offset) {
|
|
97
|
+
Validate.isInteger('offset', offset);
|
|
98
|
+
var option = __assign({}, this._queryOptions);
|
|
99
|
+
option.offset = offset;
|
|
100
|
+
return new Query(this._transaction, this._coll, this._fieldFilters, this._fieldOrders, option);
|
|
101
|
+
};
|
|
102
|
+
Query.prototype.field = function (projection) {
|
|
103
|
+
for (var k in projection) {
|
|
104
|
+
if (projection[k]) {
|
|
105
|
+
if (typeof projection[k] !== 'object') {
|
|
106
|
+
projection[k] = 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
projection[k] = 0;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
var option = __assign({}, this._queryOptions);
|
|
114
|
+
option.projection = projection;
|
|
115
|
+
return new Query(this._transaction, this._coll, this._fieldFilters, this._fieldOrders, option);
|
|
116
|
+
};
|
|
117
|
+
Query.prototype.get = function () {
|
|
118
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
119
|
+
var newOrder, param, res, data, documents, result;
|
|
120
|
+
return __generator(this, function (_a) {
|
|
121
|
+
switch (_a.label) {
|
|
122
|
+
case 0:
|
|
123
|
+
newOrder = [];
|
|
124
|
+
if (this._fieldOrders) {
|
|
125
|
+
this._fieldOrders.forEach(function (order) {
|
|
126
|
+
newOrder.push(order);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
param = {
|
|
130
|
+
collectionName: this._coll,
|
|
131
|
+
transactionId: this._transactionId
|
|
132
|
+
};
|
|
133
|
+
if (this._fieldFilters) {
|
|
134
|
+
param.query = this._fieldFilters;
|
|
135
|
+
}
|
|
136
|
+
if (newOrder.length > 0) {
|
|
137
|
+
param.order = newOrder;
|
|
138
|
+
}
|
|
139
|
+
if (this._queryOptions.offset) {
|
|
140
|
+
param.offset = this._queryOptions.offset;
|
|
141
|
+
}
|
|
142
|
+
if (this._queryOptions.limit) {
|
|
143
|
+
param.limit = this._queryOptions.limit < 1000 ? this._queryOptions.limit : 1000;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
param.limit = 100;
|
|
147
|
+
}
|
|
148
|
+
if (this._queryOptions.projection) {
|
|
149
|
+
param.projection = this._queryOptions.projection;
|
|
150
|
+
}
|
|
151
|
+
return [4, this._request.send(GET_DOC, param)];
|
|
152
|
+
case 1:
|
|
153
|
+
res = _a.sent();
|
|
154
|
+
if (res.code)
|
|
155
|
+
throw res;
|
|
156
|
+
data = res.data !== 'null' ? EJSON.parse(res.data) : null;
|
|
157
|
+
documents = data ? (Array.isArray(data) ? Util.formatResDocumentData(data) : [Util.formatField(data)]) : [];
|
|
158
|
+
result = {
|
|
159
|
+
data: documents,
|
|
160
|
+
requestId: res.requestId
|
|
161
|
+
};
|
|
162
|
+
if (res.total !== undefined)
|
|
163
|
+
result.total = res.total;
|
|
164
|
+
if (res.limit !== undefined)
|
|
165
|
+
result.limit = res.limit;
|
|
166
|
+
if (res.offset !== undefined)
|
|
167
|
+
result.offset = res.offset;
|
|
168
|
+
return [2, result];
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
Query.prototype.count = function () {
|
|
174
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
175
|
+
var param, res, data, total;
|
|
176
|
+
return __generator(this, function (_a) {
|
|
177
|
+
switch (_a.label) {
|
|
178
|
+
case 0:
|
|
179
|
+
param = {
|
|
180
|
+
collectionName: this._coll,
|
|
181
|
+
transactionId: this._transactionId
|
|
182
|
+
};
|
|
183
|
+
if (this._fieldFilters) {
|
|
184
|
+
param.query = this._fieldFilters;
|
|
185
|
+
}
|
|
186
|
+
return [4, this._request.send(GET_DOC, param)];
|
|
187
|
+
case 1:
|
|
188
|
+
res = _a.sent();
|
|
189
|
+
if (res.code)
|
|
190
|
+
throw res;
|
|
191
|
+
data = res.data !== 'null' ? EJSON.parse(res.data) : null;
|
|
192
|
+
total = Array.isArray(data) ? data.length : (data ? 1 : 0);
|
|
193
|
+
return [2, {
|
|
194
|
+
requestId: res.requestId,
|
|
195
|
+
total: res.total !== undefined ? res.total : total
|
|
196
|
+
}];
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
Query.prototype.update = function (data) {
|
|
202
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
203
|
+
var param, res;
|
|
204
|
+
return __generator(this, function (_a) {
|
|
205
|
+
switch (_a.label) {
|
|
206
|
+
case 0:
|
|
207
|
+
if (!data || typeof data !== 'object') {
|
|
208
|
+
throw new Error('参数必需是非空对象');
|
|
209
|
+
}
|
|
210
|
+
if (data.hasOwnProperty('_id')) {
|
|
211
|
+
throw new Error('不能更新_id的值');
|
|
212
|
+
}
|
|
213
|
+
param = {
|
|
214
|
+
collectionName: this._coll,
|
|
215
|
+
transactionId: this._transactionId,
|
|
216
|
+
query: this._fieldFilters,
|
|
217
|
+
data: EJSON.stringify(UpdateSerializer.encode(data), { relaxed: false })
|
|
218
|
+
};
|
|
219
|
+
return [4, this._request.send(UPDATE_DOC, param)];
|
|
220
|
+
case 1:
|
|
221
|
+
res = _a.sent();
|
|
222
|
+
if (res.code)
|
|
223
|
+
throw res;
|
|
224
|
+
return [2, __assign(__assign({}, res), { updated: EJSON.parse(res.updated) })];
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
Query.prototype.remove = function () {
|
|
230
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
231
|
+
var param, res;
|
|
232
|
+
return __generator(this, function (_a) {
|
|
233
|
+
switch (_a.label) {
|
|
234
|
+
case 0:
|
|
235
|
+
if (Object.keys(this._queryOptions).length > 0) {
|
|
236
|
+
console.warn('`offset`, `limit` and `projection` are not supported in remove() operation');
|
|
237
|
+
}
|
|
238
|
+
if (this._fieldOrders.length > 0) {
|
|
239
|
+
console.warn('`orderBy` is not supported in remove() operation');
|
|
240
|
+
}
|
|
241
|
+
param = {
|
|
242
|
+
collectionName: this._coll,
|
|
243
|
+
transactionId: this._transactionId,
|
|
244
|
+
query: this._fieldFilters
|
|
245
|
+
};
|
|
246
|
+
return [4, this._request.send(DELETE_DOC, param)];
|
|
247
|
+
case 1:
|
|
248
|
+
res = _a.sent();
|
|
249
|
+
if (res.code)
|
|
250
|
+
throw res;
|
|
251
|
+
return [2, __assign(__assign({}, res), { deleted: EJSON.parse(res.deleted) })];
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
};
|
|
6
256
|
return Query;
|
|
7
257
|
}());
|
|
8
258
|
export { Query };
|
package/package.json
CHANGED
package/src/collection.ts
CHANGED
|
@@ -42,11 +42,12 @@ export class CollectionReference extends Query {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* 添加一篇或多篇文档
|
|
46
46
|
*
|
|
47
|
-
* @param data -
|
|
47
|
+
* @param data - 单个文档数据或文档数据数组
|
|
48
|
+
* @param callback - 回调函数
|
|
48
49
|
*/
|
|
49
|
-
add(data: Object, callback?: any): Promise<any> {
|
|
50
|
+
add(data: Object | Object[], callback?: any): Promise<any> {
|
|
50
51
|
let docRef = new DocumentReference(this._db, this._coll, undefined)
|
|
51
52
|
return docRef.create(data, callback)
|
|
52
53
|
}
|
package/src/document.ts
CHANGED
|
@@ -64,21 +64,22 @@ export class DocumentReference {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
*
|
|
67
|
+
* 创建一篇或多篇文档
|
|
68
68
|
*
|
|
69
|
-
* @param data -
|
|
69
|
+
* @param data - 文档数据,支持单个对象或对象数组
|
|
70
70
|
* @internal
|
|
71
71
|
*/
|
|
72
72
|
create(data: any, callback?: any): Promise<any> {
|
|
73
73
|
callback = callback || createPromiseCallback()
|
|
74
74
|
|
|
75
|
+
const isBatch = Array.isArray(data)
|
|
76
|
+
|
|
75
77
|
let params = {
|
|
76
78
|
collectionName: this._coll,
|
|
77
|
-
|
|
78
|
-
data: serialize(data)
|
|
79
|
+
data: isBatch ? data.map(item => serialize(item)) : serialize(data)
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
if (this.id) {
|
|
82
|
+
if (!isBatch && this.id) {
|
|
82
83
|
params['_id'] = this.id
|
|
83
84
|
}
|
|
84
85
|
|
|
@@ -88,10 +89,17 @@ export class DocumentReference {
|
|
|
88
89
|
if (res.code) {
|
|
89
90
|
callback(0, res)
|
|
90
91
|
} else {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
if (isBatch) {
|
|
93
|
+
callback(0, {
|
|
94
|
+
ids: res.data?.insertedIds || [],
|
|
95
|
+
requestId: res.requestId
|
|
96
|
+
})
|
|
97
|
+
} else {
|
|
98
|
+
callback(0, {
|
|
99
|
+
id: res.data._id,
|
|
100
|
+
requestId: res.requestId
|
|
101
|
+
})
|
|
102
|
+
}
|
|
95
103
|
}
|
|
96
104
|
})
|
|
97
105
|
.catch(err => {
|
package/src/transaction/query.ts
CHANGED
|
@@ -1,8 +1,59 @@
|
|
|
1
1
|
import { Transaction } from './index'
|
|
2
|
+
import { EJSON } from 'bson'
|
|
3
|
+
import { OrderByDirection, ErrorCode } from '../constant'
|
|
4
|
+
import { Validate } from '../validate'
|
|
5
|
+
import { QuerySerializer } from '../serializer/query'
|
|
6
|
+
import { UpdateSerializer } from '../serializer/update'
|
|
7
|
+
import { Util } from '../util'
|
|
8
|
+
|
|
9
|
+
const GET_DOC = 'database.getInTransaction'
|
|
10
|
+
const UPDATE_DOC = 'database.updateDocInTransaction'
|
|
11
|
+
const DELETE_DOC = 'database.deleteDocInTransaction'
|
|
12
|
+
|
|
13
|
+
interface QueryOrder {
|
|
14
|
+
field?: string
|
|
15
|
+
direction?: 'asc' | 'desc'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface QueryOption {
|
|
19
|
+
limit?: number
|
|
20
|
+
offset?: number
|
|
21
|
+
projection?: Object
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface TransactionAPI {
|
|
25
|
+
send(interfaceName: string, param?: any)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface GetResult {
|
|
29
|
+
data: any[]
|
|
30
|
+
requestId: string
|
|
31
|
+
total?: number
|
|
32
|
+
limit?: number
|
|
33
|
+
offset?: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface UpdateResult {
|
|
37
|
+
requestId: string
|
|
38
|
+
updated: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface DeleteResult {
|
|
42
|
+
requestId: string
|
|
43
|
+
deleted: number | string
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface TcbError {
|
|
47
|
+
requestId: string
|
|
48
|
+
code: string
|
|
49
|
+
message: string
|
|
50
|
+
stack?: string
|
|
51
|
+
}
|
|
2
52
|
|
|
3
53
|
/**
|
|
4
|
-
*
|
|
54
|
+
* 事务查询模块
|
|
5
55
|
*
|
|
56
|
+
* 支持 where 条件查询在事务中使用
|
|
6
57
|
*/
|
|
7
58
|
export class Query {
|
|
8
59
|
/**
|
|
@@ -14,8 +65,310 @@ export class Query {
|
|
|
14
65
|
|
|
15
66
|
protected _transaction: Transaction
|
|
16
67
|
|
|
17
|
-
|
|
68
|
+
/**
|
|
69
|
+
* 过滤条件
|
|
70
|
+
*
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
private _fieldFilters: Object
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 排序条件
|
|
77
|
+
*
|
|
78
|
+
* @internal
|
|
79
|
+
*/
|
|
80
|
+
private _fieldOrders: QueryOrder[]
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 查询条件
|
|
84
|
+
*
|
|
85
|
+
* @internal
|
|
86
|
+
*/
|
|
87
|
+
private _queryOptions: QueryOption
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 请求实例
|
|
91
|
+
*
|
|
92
|
+
* @internal
|
|
93
|
+
*/
|
|
94
|
+
private _request: TransactionAPI
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 事务ID
|
|
98
|
+
*
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
101
|
+
private _transactionId: string
|
|
102
|
+
|
|
103
|
+
constructor(
|
|
104
|
+
transaction: Transaction,
|
|
105
|
+
coll: string,
|
|
106
|
+
fieldFilters?: Object,
|
|
107
|
+
fieldOrders?: QueryOrder[],
|
|
108
|
+
queryOptions?: QueryOption
|
|
109
|
+
) {
|
|
18
110
|
this._coll = coll
|
|
19
111
|
this._transaction = transaction
|
|
112
|
+
this._fieldFilters = fieldFilters
|
|
113
|
+
this._fieldOrders = fieldOrders || []
|
|
114
|
+
this._queryOptions = queryOptions || {}
|
|
115
|
+
this._request = this._transaction.getRequestMethod()
|
|
116
|
+
this._transactionId = this._transaction.getTransactionId()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 查询条件
|
|
121
|
+
*
|
|
122
|
+
* @param query - 查询条件对象
|
|
123
|
+
*/
|
|
124
|
+
public where(query: object): Query {
|
|
125
|
+
if (Object.prototype.toString.call(query).slice(8, -1) !== 'Object') {
|
|
126
|
+
throw Error(ErrorCode.QueryParamTypeError)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const keys = Object.keys(query)
|
|
130
|
+
const checkFlag = keys.some(item => {
|
|
131
|
+
return query[item] !== undefined
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
if (keys.length && !checkFlag) {
|
|
135
|
+
throw Error(ErrorCode.QueryParamValueError)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return new Query(
|
|
139
|
+
this._transaction,
|
|
140
|
+
this._coll,
|
|
141
|
+
QuerySerializer.encode(query),
|
|
142
|
+
this._fieldOrders,
|
|
143
|
+
this._queryOptions
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* 设置排序方式
|
|
149
|
+
*
|
|
150
|
+
* @param fieldPath - 字段路径
|
|
151
|
+
* @param directionStr - 排序方式
|
|
152
|
+
*/
|
|
153
|
+
public orderBy(fieldPath: string, directionStr: OrderByDirection): Query {
|
|
154
|
+
Validate.isFieldPath(fieldPath)
|
|
155
|
+
Validate.isFieldOrder(directionStr)
|
|
156
|
+
|
|
157
|
+
const newOrder: QueryOrder = {
|
|
158
|
+
field: fieldPath,
|
|
159
|
+
direction: directionStr
|
|
160
|
+
}
|
|
161
|
+
const combinedOrders = this._fieldOrders.concat(newOrder)
|
|
162
|
+
|
|
163
|
+
return new Query(
|
|
164
|
+
this._transaction,
|
|
165
|
+
this._coll,
|
|
166
|
+
this._fieldFilters,
|
|
167
|
+
combinedOrders,
|
|
168
|
+
this._queryOptions
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 设置查询条数
|
|
174
|
+
*
|
|
175
|
+
* @param limit - 限制条数
|
|
176
|
+
*/
|
|
177
|
+
public limit(limit: number): Query {
|
|
178
|
+
Validate.isInteger('limit', limit)
|
|
179
|
+
|
|
180
|
+
let option = { ...this._queryOptions }
|
|
181
|
+
option.limit = limit
|
|
182
|
+
|
|
183
|
+
return new Query(
|
|
184
|
+
this._transaction,
|
|
185
|
+
this._coll,
|
|
186
|
+
this._fieldFilters,
|
|
187
|
+
this._fieldOrders,
|
|
188
|
+
option
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 设置偏移量
|
|
194
|
+
*
|
|
195
|
+
* @param offset - 偏移量
|
|
196
|
+
*/
|
|
197
|
+
public skip(offset: number): Query {
|
|
198
|
+
Validate.isInteger('offset', offset)
|
|
199
|
+
|
|
200
|
+
let option = { ...this._queryOptions }
|
|
201
|
+
option.offset = offset
|
|
202
|
+
|
|
203
|
+
return new Query(
|
|
204
|
+
this._transaction,
|
|
205
|
+
this._coll,
|
|
206
|
+
this._fieldFilters,
|
|
207
|
+
this._fieldOrders,
|
|
208
|
+
option
|
|
209
|
+
)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 指定要返回的字段
|
|
214
|
+
*
|
|
215
|
+
* @param projection
|
|
216
|
+
*/
|
|
217
|
+
public field(projection: any): Query {
|
|
218
|
+
for (let k in projection) {
|
|
219
|
+
if (projection[k]) {
|
|
220
|
+
if (typeof projection[k] !== 'object') {
|
|
221
|
+
projection[k] = 1
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
projection[k] = 0
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
let option = { ...this._queryOptions }
|
|
229
|
+
option.projection = projection
|
|
230
|
+
|
|
231
|
+
return new Query(
|
|
232
|
+
this._transaction,
|
|
233
|
+
this._coll,
|
|
234
|
+
this._fieldFilters,
|
|
235
|
+
this._fieldOrders,
|
|
236
|
+
option
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 发起请求获取文档列表(事务内)
|
|
242
|
+
*/
|
|
243
|
+
public async get(): Promise<GetResult> {
|
|
244
|
+
let newOrder = []
|
|
245
|
+
if (this._fieldOrders) {
|
|
246
|
+
this._fieldOrders.forEach(order => {
|
|
247
|
+
newOrder.push(order)
|
|
248
|
+
})
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
let param: any = {
|
|
252
|
+
collectionName: this._coll,
|
|
253
|
+
transactionId: this._transactionId
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (this._fieldFilters) {
|
|
257
|
+
param.query = this._fieldFilters
|
|
258
|
+
}
|
|
259
|
+
if (newOrder.length > 0) {
|
|
260
|
+
param.order = newOrder
|
|
261
|
+
}
|
|
262
|
+
if (this._queryOptions.offset) {
|
|
263
|
+
param.offset = this._queryOptions.offset
|
|
264
|
+
}
|
|
265
|
+
if (this._queryOptions.limit) {
|
|
266
|
+
param.limit = this._queryOptions.limit < 1000 ? this._queryOptions.limit : 1000
|
|
267
|
+
} else {
|
|
268
|
+
param.limit = 100
|
|
269
|
+
}
|
|
270
|
+
if (this._queryOptions.projection) {
|
|
271
|
+
param.projection = this._queryOptions.projection
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const res = await this._request.send(GET_DOC, param)
|
|
275
|
+
if (res.code) throw res
|
|
276
|
+
|
|
277
|
+
const data = res.data !== 'null' ? EJSON.parse(res.data) : null
|
|
278
|
+
const documents = data ? (Array.isArray(data) ? Util.formatResDocumentData(data) : [Util.formatField(data)]) : []
|
|
279
|
+
|
|
280
|
+
const result: GetResult = {
|
|
281
|
+
data: documents,
|
|
282
|
+
requestId: res.requestId
|
|
283
|
+
}
|
|
284
|
+
if (res.total !== undefined) result.total = res.total
|
|
285
|
+
if (res.limit !== undefined) result.limit = res.limit
|
|
286
|
+
if (res.offset !== undefined) result.offset = res.offset
|
|
287
|
+
|
|
288
|
+
return result
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* 获取总数(事务内)
|
|
293
|
+
*/
|
|
294
|
+
public async count(): Promise<{ requestId: string; total: number }> {
|
|
295
|
+
let param: any = {
|
|
296
|
+
collectionName: this._coll,
|
|
297
|
+
transactionId: this._transactionId
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (this._fieldFilters) {
|
|
301
|
+
param.query = this._fieldFilters
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const res = await this._request.send(GET_DOC, param)
|
|
305
|
+
if (res.code) throw res
|
|
306
|
+
|
|
307
|
+
const data = res.data !== 'null' ? EJSON.parse(res.data) : null
|
|
308
|
+
const total = Array.isArray(data) ? data.length : (data ? 1 : 0)
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
requestId: res.requestId,
|
|
312
|
+
total: res.total !== undefined ? res.total : total
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 发起请求批量更新文档(事务内)
|
|
318
|
+
*
|
|
319
|
+
* @param data - 更新数据
|
|
320
|
+
*/
|
|
321
|
+
public async update(data: Object): Promise<UpdateResult> {
|
|
322
|
+
if (!data || typeof data !== 'object') {
|
|
323
|
+
throw new Error('参数必需是非空对象')
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (data.hasOwnProperty('_id')) {
|
|
327
|
+
throw new Error('不能更新_id的值')
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const param = {
|
|
331
|
+
collectionName: this._coll,
|
|
332
|
+
transactionId: this._transactionId,
|
|
333
|
+
query: this._fieldFilters,
|
|
334
|
+
data: EJSON.stringify(
|
|
335
|
+
UpdateSerializer.encode(data),
|
|
336
|
+
{ relaxed: false }
|
|
337
|
+
)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const res = await this._request.send(UPDATE_DOC, param)
|
|
341
|
+
if (res.code) throw res
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
...res,
|
|
345
|
+
updated: EJSON.parse(res.updated)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* 条件删除文档(事务内)
|
|
351
|
+
*/
|
|
352
|
+
public async remove(): Promise<DeleteResult> {
|
|
353
|
+
if (Object.keys(this._queryOptions).length > 0) {
|
|
354
|
+
console.warn('`offset`, `limit` and `projection` are not supported in remove() operation')
|
|
355
|
+
}
|
|
356
|
+
if (this._fieldOrders.length > 0) {
|
|
357
|
+
console.warn('`orderBy` is not supported in remove() operation')
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const param = {
|
|
361
|
+
collectionName: this._coll,
|
|
362
|
+
transactionId: this._transactionId,
|
|
363
|
+
query: this._fieldFilters
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const res: DeleteResult | TcbError = await this._request.send(DELETE_DOC, param)
|
|
367
|
+
if ((res as TcbError).code) throw res
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
...res,
|
|
371
|
+
deleted: EJSON.parse((res as DeleteResult).deleted as any) as any
|
|
372
|
+
}
|
|
20
373
|
}
|
|
21
374
|
}
|