transaction.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import { EJSON } from 'bson';
  2. import { Db } from './index';
  3. class DocumentSnapshot {
  4. constructor(data, requestId) {
  5. this._data = data;
  6. this.requestId = requestId;
  7. }
  8. data() {
  9. return this._data;
  10. }
  11. }
  12. const START = 'database.startTransaction';
  13. const COMMIT = 'database.commitTransaction';
  14. const ABORT = 'database.abortTransaction';
  15. const GET_DOC = 'database.getInTransaction';
  16. const UPDATE_DOC = 'database.updateDocInTransaction';
  17. const DELETE_DOC = 'database.deleteDocInTransaction';
  18. export class Transaction {
  19. constructor(db) {
  20. this._db = db;
  21. this._request = new Db.reqClass(this._db.config);
  22. }
  23. async init() {
  24. const res = await this._request.send(START, {});
  25. if (res.code) {
  26. throw res;
  27. }
  28. this._id = res.transactionId;
  29. }
  30. async get(documentRef) {
  31. const param = {
  32. collectionName: documentRef._coll,
  33. transactionId: this._id,
  34. _id: documentRef.id
  35. };
  36. const res = await this._request.send(GET_DOC, param);
  37. if (res.code)
  38. throw res;
  39. return new DocumentSnapshot(EJSON.parse(res.data), res.requestId);
  40. }
  41. async set(documentRef, data) {
  42. const param = {
  43. collectionName: documentRef._coll,
  44. transactionId: this._id,
  45. _id: documentRef.id,
  46. data: EJSON.stringify(data, { relaxed: false }),
  47. upsert: true
  48. };
  49. const res = await this._request.send(UPDATE_DOC, param);
  50. if (res.code)
  51. throw res;
  52. return Object.assign(Object.assign({}, res), { updated: EJSON.parse(res.updated), upserted: res.upserted
  53. ? JSON.parse(res.upserted)
  54. : null });
  55. }
  56. async update(documentRef, data) {
  57. const param = {
  58. collectionName: documentRef._coll,
  59. transactionId: this._id,
  60. _id: documentRef.id,
  61. data: EJSON.stringify({
  62. $set: data
  63. }, {
  64. relaxed: false
  65. })
  66. };
  67. const res = await this._request.send(UPDATE_DOC, param);
  68. if (res.code)
  69. throw res;
  70. return Object.assign(Object.assign({}, res), { updated: EJSON.parse(res.updated) });
  71. }
  72. async delete(documentRef) {
  73. const param = {
  74. collectionName: documentRef._coll,
  75. transactionId: this._id,
  76. _id: documentRef.id
  77. };
  78. const res = await this._request.send(DELETE_DOC, param);
  79. if (res.code)
  80. throw res;
  81. return Object.assign(Object.assign({}, res), { deleted: EJSON.parse(res.deleted) });
  82. }
  83. async commit() {
  84. const param = {
  85. transactionId: this._id
  86. };
  87. const res = await this._request.send(COMMIT, param);
  88. if (res.code)
  89. throw res;
  90. return res;
  91. }
  92. async rollback() {
  93. const param = {
  94. transactionId: this._id
  95. };
  96. const res = await this._request.send(ABORT, param);
  97. if (res.code)
  98. throw res;
  99. return res;
  100. }
  101. }
  102. export async function startTransaction() {
  103. const transaction = new Transaction(this);
  104. await transaction.init();
  105. return transaction;
  106. }
  107. export async function runTransaction(callback, times = 3) {
  108. if (times <= 0) {
  109. throw new Error('Transaction failed');
  110. }
  111. try {
  112. const transaction = new Transaction(this);
  113. await transaction.init();
  114. await callback(transaction);
  115. await transaction.commit();
  116. }
  117. catch (error) {
  118. console.log(error);
  119. return runTransaction.bind(this)(callback, --times);
  120. }
  121. }