document.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import { Db } from './index';
  2. import { Util } from './util';
  3. import { UpdateSerializer } from './serializer/update';
  4. import { serialize } from './serializer/datatype';
  5. import { UpdateCommand } from './commands/update';
  6. import { RealtimeWebSocketClient } from './realtime/websocket-client';
  7. import { QueryType } from './constant';
  8. import { getReqOpts, stringifyByEJSON, processReturn } from './utils/utils';
  9. import { ERRORS } from './const/code';
  10. import { EJSON } from 'bson';
  11. export class DocumentReference {
  12. constructor(db, coll, apiOptions, docID, transactionId) {
  13. this.watch = (options) => {
  14. if (!Db.ws) {
  15. Db.ws = new RealtimeWebSocketClient({
  16. context: {
  17. appConfig: {
  18. docSizeLimit: 1000,
  19. realtimePingInterval: 10000,
  20. realtimePongWaitTimeout: 5000,
  21. request: this.request
  22. }
  23. }
  24. });
  25. }
  26. return Db.ws.watch(Object.assign(Object.assign({}, options), { envId: this._db.config.env, collectionName: this._coll, query: JSON.stringify({
  27. _id: this.id
  28. }) }));
  29. };
  30. this._db = db;
  31. this._coll = coll;
  32. this.id = docID;
  33. this._transactionId = transactionId;
  34. this.request = new Db.reqClass(this._db.config);
  35. this._apiOptions = apiOptions;
  36. }
  37. async create(data) {
  38. if (this.id) {
  39. data['_id'] = this.id;
  40. }
  41. let params = {
  42. collectionName: this._coll,
  43. data: [stringifyByEJSON(serialize(data))],
  44. transactionId: this._transactionId
  45. };
  46. const res = await this.request.send('database.insertDocument', params, getReqOpts(this._apiOptions));
  47. if (res.code) {
  48. return res;
  49. }
  50. if (this._transactionId) {
  51. return {
  52. inserted: 1,
  53. ok: 1,
  54. id: res.data.insertedIds[0],
  55. requestId: res.requestId
  56. };
  57. }
  58. return {
  59. id: res.data.insertedIds[0],
  60. requestId: res.requestId
  61. };
  62. }
  63. async set(data) {
  64. if (!this.id) {
  65. return processReturn(this._db.config.throwOnCode, Object.assign(Object.assign({}, ERRORS.INVALID_PARAM), { message: 'docId不能为空' }));
  66. }
  67. if (!data || typeof data !== 'object') {
  68. return processReturn(this._db.config.throwOnCode, Object.assign(Object.assign({}, ERRORS.INVALID_PARAM), { message: '参数必需是非空对象' }));
  69. }
  70. if (data.hasOwnProperty('_id')) {
  71. return processReturn(this._db.config.throwOnCode, Object.assign(Object.assign({}, ERRORS.INVALID_PARAM), { message: '不能更新_id的值' }));
  72. }
  73. let hasOperator = false;
  74. const checkMixed = objs => {
  75. if (typeof objs === 'object') {
  76. for (let key in objs) {
  77. if (objs[key] instanceof UpdateCommand) {
  78. hasOperator = true;
  79. }
  80. else if (typeof objs[key] === 'object') {
  81. checkMixed(objs[key]);
  82. }
  83. }
  84. }
  85. };
  86. checkMixed(data);
  87. if (hasOperator) {
  88. return processReturn(this._db.config.throwOnCode, Object.assign(Object.assign({}, ERRORS.DATABASE_REQUEST_FAILED), { message: 'update operator complicit' }));
  89. }
  90. let param = {
  91. collectionName: this._coll,
  92. queryType: QueryType.DOC,
  93. data: stringifyByEJSON(serialize(data)),
  94. transactionId: this._transactionId,
  95. multi: false,
  96. merge: false,
  97. upsert: true
  98. };
  99. if (this.id) {
  100. param['query'] = stringifyByEJSON({ _id: this.id });
  101. }
  102. const res = await this.request.send('database.modifyDocument', param, getReqOpts(this._apiOptions));
  103. if (res.code) {
  104. return res;
  105. }
  106. if (this._transactionId) {
  107. return {
  108. updated: res.data.updated,
  109. upserted: [{ _id: res.data.upsert_id }],
  110. requestId: res.requestId
  111. };
  112. }
  113. return {
  114. updated: res.data.updated,
  115. upsertedId: res.data.upsert_id,
  116. requestId: res.requestId
  117. };
  118. }
  119. async update(data) {
  120. if (!data || typeof data !== 'object') {
  121. return processReturn(this._db.config.throwOnCode, Object.assign(Object.assign({}, ERRORS.INVALID_PARAM), { message: '参数必需是非空对象' }));
  122. }
  123. if (data.hasOwnProperty('_id')) {
  124. return processReturn(this._db.config.throwOnCode, Object.assign(Object.assign({}, ERRORS.INVALID_PARAM), { message: '不能更新_id的值' }));
  125. }
  126. const query = stringifyByEJSON({ _id: this.id });
  127. const param = {
  128. collectionName: this._coll,
  129. transactionId: this._transactionId,
  130. data: UpdateSerializer.encodeEJSON(data),
  131. query,
  132. queryType: QueryType.DOC,
  133. multi: false,
  134. merge: true,
  135. upsert: false
  136. };
  137. const res = await this.request.send('database.modifyDocument', param, getReqOpts(this._apiOptions));
  138. if (res.code) {
  139. return res;
  140. }
  141. return {
  142. updated: res.data.updated,
  143. requestId: res.requestId
  144. };
  145. }
  146. async delete() {
  147. return this.remove();
  148. }
  149. async remove() {
  150. const query = stringifyByEJSON({ _id: this.id });
  151. const param = {
  152. collectionName: this._coll,
  153. transactionId: this._transactionId,
  154. query: query,
  155. queryType: QueryType.DOC,
  156. multi: false
  157. };
  158. const res = await this.request.send('database.removeDocument', param, getReqOpts(this._apiOptions));
  159. if (res.code) {
  160. return res;
  161. }
  162. return {
  163. deleted: res.data.deleted,
  164. requestId: res.requestId
  165. };
  166. }
  167. async get() {
  168. const query = stringifyByEJSON({ _id: this.id });
  169. const { projection } = this._apiOptions;
  170. const param = {
  171. collectionName: this._coll,
  172. query,
  173. transactionId: this._transactionId,
  174. queryType: QueryType.DOC,
  175. multi: false
  176. };
  177. if (projection) {
  178. param.projection = stringifyByEJSON(projection);
  179. }
  180. const res = await this.request.send('database.getDocument', param, getReqOpts(this._apiOptions));
  181. if (res.code) {
  182. return res;
  183. }
  184. const list = res.data.list.map(item => EJSON.parse(item));
  185. const documents = Util.formatResDocumentData(list);
  186. if (this._transactionId) {
  187. return {
  188. data: documents[0] || null,
  189. requestId: res.requestId
  190. };
  191. }
  192. return {
  193. data: documents,
  194. requestId: res.requestId,
  195. offset: res.data.offset,
  196. limit: res.data.limit
  197. };
  198. }
  199. field(projection) {
  200. let transformProjection = {};
  201. for (let k in projection) {
  202. if (typeof projection[k] === 'boolean') {
  203. transformProjection[k] = projection[k] === true ? 1 : 0;
  204. }
  205. if (typeof projection[k] === 'number') {
  206. transformProjection[k] = projection[k] > 0 ? 1 : 0;
  207. }
  208. if (typeof projection[k] === 'object') {
  209. transformProjection[k] = projection[k];
  210. }
  211. }
  212. let newApiOption = Object.assign({}, this._apiOptions);
  213. newApiOption.projection = transformProjection;
  214. return new DocumentReference(this._db, this._coll, newApiOption, this.id, this._transactionId);
  215. }
  216. }