query.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const constant_1 = require("./constant");
  4. const index_1 = require("./index");
  5. const validate_1 = require("./validate");
  6. const util_1 = require("./util");
  7. const query_1 = require("./serializer/query");
  8. const update_1 = require("./serializer/update");
  9. const websocket_client_1 = require("./realtime/websocket-client");
  10. const constant_2 = require("./constant");
  11. const utils_1 = require("./utils/utils");
  12. const code_1 = require("./const/code");
  13. const bson_1 = require("bson");
  14. class Query {
  15. constructor(db, coll, fieldFilters, apiOptions, transactionId) {
  16. this.watch = (options) => {
  17. if (!index_1.Db.ws) {
  18. index_1.Db.ws = new websocket_client_1.RealtimeWebSocketClient({
  19. context: {
  20. appConfig: {
  21. docSizeLimit: 1000,
  22. realtimePingInterval: 10000,
  23. realtimePongWaitTimeout: 5000,
  24. request: this._request
  25. }
  26. }
  27. });
  28. }
  29. const { limit, order } = this._apiOptions;
  30. return index_1.Db.ws.watch(Object.assign(Object.assign({}, options), { envId: this._db.config.env, collectionName: this._coll, query: JSON.stringify(this._fieldFilters), limit, orderBy: order
  31. ? order.reduce((acc, cur) => {
  32. acc[cur.field] = cur.direction;
  33. return acc;
  34. }, {})
  35. : undefined }));
  36. };
  37. this._db = db;
  38. this._coll = coll;
  39. this._fieldFilters = fieldFilters;
  40. this._apiOptions = apiOptions || {};
  41. this._request = new index_1.Db.reqClass(this._db.config);
  42. this._transactionId = transactionId;
  43. }
  44. async get() {
  45. const order = this._apiOptions.order;
  46. let param = {
  47. collectionName: this._coll,
  48. queryType: constant_1.QueryType.WHERE,
  49. transactionId: this._transactionId
  50. };
  51. if (this._fieldFilters) {
  52. param.query = this._fieldFilters;
  53. }
  54. if (order) {
  55. param.order = utils_1.stringifyByEJSON(order);
  56. }
  57. const offset = this._apiOptions.offset;
  58. if (offset) {
  59. param.offset = offset;
  60. }
  61. const limit = this._apiOptions.limit;
  62. if (limit) {
  63. param.limit = limit < 1000 ? limit : 1000;
  64. }
  65. else {
  66. param.limit = 100;
  67. }
  68. const projection = this._apiOptions.projection;
  69. if (projection) {
  70. param.projection = utils_1.stringifyByEJSON(projection);
  71. }
  72. const res = await this._request.send('database.getDocument', param, utils_1.getReqOpts(this._apiOptions));
  73. if (res.code) {
  74. return res;
  75. }
  76. const list = res.data.list.map(item => bson_1.EJSON.parse(item));
  77. const documents = util_1.Util.formatResDocumentData(list);
  78. const result = {
  79. data: documents,
  80. requestId: res.requestId
  81. };
  82. if (res.limit)
  83. result.limit = res.limit;
  84. if (res.offset)
  85. result.offset = res.offset;
  86. return result;
  87. }
  88. async count() {
  89. let param = {
  90. collectionName: this._coll,
  91. queryType: constant_1.QueryType.WHERE
  92. };
  93. if (this._fieldFilters) {
  94. param.query = this._fieldFilters;
  95. }
  96. const res = await this._request.send('database.calculateDocument', param, utils_1.getReqOpts(this._apiOptions));
  97. if (res.code) {
  98. return res;
  99. }
  100. return {
  101. requestId: res.requestId,
  102. total: res.data.total
  103. };
  104. }
  105. where(query) {
  106. if (Object.prototype.toString.call(query).slice(8, -1) !== 'Object') {
  107. throw Error(constant_2.ErrorCode.QueryParamTypeError);
  108. }
  109. const keys = Object.keys(query);
  110. const checkFlag = keys.some(item => {
  111. return query[item] !== undefined;
  112. });
  113. if (keys.length && !checkFlag) {
  114. throw Error(constant_2.ErrorCode.QueryParamValueError);
  115. }
  116. return new Query(this._db, this._coll, query_1.QuerySerializer.encodeEJSON(query), this._apiOptions, this._transactionId);
  117. }
  118. options(apiOptions) {
  119. validate_1.Validate.isValidOptions(apiOptions);
  120. return new Query(this._db, this._coll, this._fieldFilters, apiOptions, this._transactionId);
  121. }
  122. orderBy(fieldPath, directionStr) {
  123. validate_1.Validate.isFieldPath(fieldPath);
  124. validate_1.Validate.isFieldOrder(directionStr);
  125. const newOrder = {
  126. [fieldPath]: directionStr === 'desc' ? -1 : 1
  127. };
  128. const order = this._apiOptions.order || {};
  129. const newApiOption = Object.assign({}, this._apiOptions, {
  130. order: Object.assign({}, order, newOrder)
  131. });
  132. return new Query(this._db, this._coll, this._fieldFilters, newApiOption, this._transactionId);
  133. }
  134. limit(limit) {
  135. validate_1.Validate.isInteger('limit', limit);
  136. let newApiOption = Object.assign({}, this._apiOptions);
  137. newApiOption.limit = limit;
  138. return new Query(this._db, this._coll, this._fieldFilters, newApiOption, this._transactionId);
  139. }
  140. skip(offset) {
  141. validate_1.Validate.isInteger('offset', offset);
  142. let newApiOption = Object.assign({}, this._apiOptions);
  143. newApiOption.offset = offset;
  144. return new Query(this._db, this._coll, this._fieldFilters, newApiOption, this._transactionId);
  145. }
  146. async update(data) {
  147. if (!data || typeof data !== 'object') {
  148. return utils_1.processReturn(this._db.config.throwOnCode, Object.assign(Object.assign({}, code_1.ERRORS.INVALID_PARAM), { message: '参数必需是非空对象' }));
  149. }
  150. if (data.hasOwnProperty('_id')) {
  151. return utils_1.processReturn(this._db.config.throwOnCode, Object.assign(Object.assign({}, code_1.ERRORS.INVALID_PARAM), { message: '不能更新_id的值' }));
  152. }
  153. let { multiple } = this._apiOptions;
  154. const multi = multiple === undefined ? true : multiple;
  155. let param = {
  156. collectionName: this._coll,
  157. queryType: constant_1.QueryType.WHERE,
  158. multi,
  159. merge: true,
  160. upsert: false,
  161. data: update_1.UpdateSerializer.encodeEJSON(data)
  162. };
  163. if (this._fieldFilters) {
  164. param.query = this._fieldFilters;
  165. }
  166. const res = await this._request.send('database.modifyDocument', param, utils_1.getReqOpts(this._apiOptions));
  167. if (res.code) {
  168. return res;
  169. }
  170. return {
  171. requestId: res.requestId,
  172. updated: res.data.updated,
  173. upsertId: res.data.upsert_id
  174. };
  175. }
  176. field(projection) {
  177. let transformProjection = {};
  178. for (let k in projection) {
  179. if (typeof projection[k] === 'boolean') {
  180. transformProjection[k] = projection[k] === true ? 1 : 0;
  181. }
  182. if (typeof projection[k] === 'number') {
  183. transformProjection[k] = projection[k] > 0 ? 1 : 0;
  184. }
  185. if (typeof projection[k] === 'object') {
  186. transformProjection[k] = projection[k];
  187. }
  188. }
  189. let newApiOption = Object.assign({}, this._apiOptions);
  190. newApiOption.projection = transformProjection;
  191. return new Query(this._db, this._coll, this._fieldFilters, newApiOption, this._transactionId);
  192. }
  193. async remove() {
  194. const { offset, limit, projection, order } = this._apiOptions;
  195. if (offset !== undefined ||
  196. limit !== undefined ||
  197. projection !== undefined ||
  198. order !== undefined) {
  199. console.warn('`offset`, `limit`, `projection`, `orderBy` are not supported in remove() operation');
  200. }
  201. let { multiple } = this._apiOptions;
  202. const multi = multiple === undefined ? true : multiple;
  203. const param = {
  204. collectionName: this._coll,
  205. query: this._fieldFilters,
  206. queryType: constant_1.QueryType.WHERE,
  207. multi
  208. };
  209. const res = await this._request.send('database.removeDocument', param, utils_1.getReqOpts(this._apiOptions));
  210. if (res.code) {
  211. return res;
  212. }
  213. return {
  214. requestId: res.requestId,
  215. deleted: res.data.deleted
  216. };
  217. }
  218. async updateAndReturn(data) {
  219. if (!data || typeof data !== 'object') {
  220. return utils_1.processReturn(this._db.config.throwOnCode, Object.assign(Object.assign({}, code_1.ERRORS.INVALID_PARAM), { message: '参数必需是非空对象' }));
  221. }
  222. if (data.hasOwnProperty('_id')) {
  223. return utils_1.processReturn(this._db.config.throwOnCode, Object.assign(Object.assign({}, code_1.ERRORS.INVALID_PARAM), { message: '不能更新_id的值' }));
  224. }
  225. let param = {
  226. collectionName: this._coll,
  227. queryType: constant_1.QueryType.WHERE,
  228. data: update_1.UpdateSerializer.encodeEJSON(data)
  229. };
  230. if (this._transactionId) {
  231. param.transactionId = this._transactionId;
  232. }
  233. if (this._fieldFilters) {
  234. param.query = this._fieldFilters;
  235. }
  236. const res = await this._request.send('database.modifyAndReturnDoc', param, utils_1.getReqOpts(this._apiOptions));
  237. if (res.code) {
  238. return res;
  239. }
  240. return {
  241. requestId: res.requestId,
  242. updated: res.data.updated,
  243. doc: res.data.doc && bson_1.EJSON.parse(res.data.doc)
  244. };
  245. }
  246. }
  247. exports.Query = Query;