@breautek/storm 8.0.0 → 8.1.0

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.
Files changed (134) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/docs/assets/navigation.js +1 -1
  3. package/docs/assets/search.js +1 -1
  4. package/docs/classes/Application.html +66 -64
  5. package/docs/classes/BackendAuthenticationMiddleware.html +3 -3
  6. package/docs/classes/CORSMiddleware.html +3 -3
  7. package/docs/classes/ConfigLoader.html +3 -3
  8. package/docs/classes/Database.html +2 -2
  9. package/docs/classes/DatabaseCastObject.html +2 -2
  10. package/docs/classes/DatabaseConnection.html +21 -19
  11. package/docs/classes/DatabaseQueryError.html +5 -5
  12. package/docs/classes/DeadLockError.html +5 -5
  13. package/docs/classes/DiskSpaceError.html +5 -5
  14. package/docs/classes/DropTemporaryTableQuery.html +6 -6
  15. package/docs/classes/DuplicateEntryError.html +5 -5
  16. package/docs/classes/EntityNotFoundError.html +5 -5
  17. package/docs/classes/ExpiredTokenError.html +5 -5
  18. package/docs/classes/Handler.html +2 -2
  19. package/docs/classes/InternalError.html +5 -5
  20. package/docs/classes/InvalidCredentialsError.html +5 -5
  21. package/docs/classes/InvalidValueError.html +5 -5
  22. package/docs/classes/LineString.html +2 -2
  23. package/docs/classes/LockWaitTimeoutError.html +5 -5
  24. package/docs/classes/ManagedDatabaseConnection.html +4 -2
  25. package/docs/classes/Middleware.html +2 -2
  26. package/docs/classes/MissingConfigError.html +5 -5
  27. package/docs/classes/MissingParameterError.html +5 -5
  28. package/docs/classes/MySQLConnection.html +28 -20
  29. package/docs/classes/MySQLDatabase.html +2 -2
  30. package/docs/classes/NotImplementedError.html +5 -5
  31. package/docs/classes/Point.html +2 -2
  32. package/docs/classes/Polygon.html +2 -2
  33. package/docs/classes/Query.html +6 -6
  34. package/docs/classes/RawError.html +5 -5
  35. package/docs/classes/RawQuery.html +6 -6
  36. package/docs/classes/Request.html +2 -2
  37. package/docs/classes/Response.html +2 -2
  38. package/docs/classes/ResponseData.html +2 -2
  39. package/docs/classes/ServiceProvider.html +2 -2
  40. package/docs/classes/ServiceResponse.html +2 -2
  41. package/docs/classes/SetSessionVariableQuery.html +6 -6
  42. package/docs/classes/StormError.html +5 -5
  43. package/docs/classes/TemporaryTableQuery.html +6 -6
  44. package/docs/classes/TimeoutError.html +24 -0
  45. package/docs/classes/Token.html +2 -2
  46. package/docs/classes/TokenManager.html +2 -2
  47. package/docs/classes/Transaction.html +2 -2
  48. package/docs/classes/UnauthorizedAccessError.html +5 -5
  49. package/docs/enums/ErrorCode.html +2 -2
  50. package/docs/enums/ExitCode.html +2 -2
  51. package/docs/enums/HTTPMethod.html +2 -2
  52. package/docs/enums/IsolationLevel.html +2 -2
  53. package/docs/enums/JWTError.html +2 -2
  54. package/docs/enums/StatusCode.html +2 -2
  55. package/docs/functions/getInstance.html +1 -1
  56. package/docs/hierarchy.html +1 -1
  57. package/docs/index.html +2 -0
  58. package/docs/interfaces/IAdditionalErrorDetails.html +1 -1
  59. package/docs/interfaces/ICloudwatchConfig.html +2 -2
  60. package/docs/interfaces/ICloudwatchCredentials.html +2 -2
  61. package/docs/interfaces/ICloudwatchStreamConfig.html +2 -2
  62. package/docs/interfaces/IConfig.html +2 -2
  63. package/docs/interfaces/IDatabaseConfig.html +2 -2
  64. package/docs/interfaces/IDatabaseConnection.html +4 -2
  65. package/docs/interfaces/IDatabasePosition.html +4 -0
  66. package/docs/interfaces/IErrorResponse.html +2 -2
  67. package/docs/interfaces/IFormData.html +2 -2
  68. package/docs/interfaces/IHandler.html +2 -2
  69. package/docs/interfaces/IInsertQueryResult.html +2 -2
  70. package/docs/interfaces/IJWTVerifyOptions.html +2 -2
  71. package/docs/interfaces/IOKPacket.html +2 -2
  72. package/docs/interfaces/IParameterMap.html +1 -1
  73. package/docs/interfaces/IQueryable.html +2 -2
  74. package/docs/interfaces/IRequestResponse.html +2 -2
  75. package/docs/interfaces/IServiceHeaders.html +1 -1
  76. package/docs/interfaces/ISetSessionVariableQueryInput.html +2 -2
  77. package/docs/interfaces/IStormCLIArgs.html +2 -2
  78. package/docs/interfaces/ITemporaryTableQueryInput.html +2 -2
  79. package/docs/interfaces/IUpdateQueryResult.html +2 -2
  80. package/docs/types/IDeleteQueryResult.html +1 -1
  81. package/docs/types/IHandlerError.html +1 -1
  82. package/docs/types/IHandlerResponse.html +1 -1
  83. package/docs/types/IStoredProcedureResult.html +1 -1
  84. package/docs/types/TCoordinate.html +1 -1
  85. package/lib/Database.d.ts +3 -2
  86. package/lib/Database.js +2 -2
  87. package/lib/Database.js.map +1 -1
  88. package/lib/DatabaseConnection.d.ts +5 -0
  89. package/lib/DatabaseConnection.js.map +1 -1
  90. package/lib/IDatabaseConnection.d.ts +5 -0
  91. package/lib/IDatabasePosition.d.ts +7 -0
  92. package/lib/IDatabasePosition.js +18 -0
  93. package/lib/IDatabasePosition.js.map +1 -0
  94. package/lib/ManagedDatabaseConnection.d.ts +2 -0
  95. package/lib/ManagedDatabaseConnection.js +4 -0
  96. package/lib/ManagedDatabaseConnection.js.map +1 -1
  97. package/lib/MySQLConnection.d.ts +9 -0
  98. package/lib/MySQLConnection.js +20 -0
  99. package/lib/MySQLConnection.js.map +1 -1
  100. package/lib/MySQLDatabase.d.ts +3 -1
  101. package/lib/MySQLDatabase.js +26 -3
  102. package/lib/MySQLDatabase.js.map +1 -1
  103. package/lib/TimeoutError.d.ts +13 -0
  104. package/lib/TimeoutError.js +43 -0
  105. package/lib/TimeoutError.js.map +1 -0
  106. package/lib/api.d.ts +2 -0
  107. package/lib/api.js +4 -2
  108. package/lib/api.js.map +1 -1
  109. package/lib/private/ConnectionReplicationWaiter.d.ts +24 -0
  110. package/lib/private/ConnectionReplicationWaiter.js +92 -0
  111. package/lib/private/ConnectionReplicationWaiter.js.map +1 -0
  112. package/lib/private/GetBinLogPositionQuery.d.ts +12 -0
  113. package/lib/private/GetBinLogPositionQuery.js +49 -0
  114. package/lib/private/GetBinLogPositionQuery.js.map +1 -0
  115. package/lib/private/GetMasterPositionQuery.d.ts +11 -0
  116. package/lib/private/GetMasterPositionQuery.js +32 -0
  117. package/lib/private/GetMasterPositionQuery.js.map +1 -0
  118. package/lib/private/GetSlavePositionQuery.d.ts +11 -0
  119. package/lib/private/GetSlavePositionQuery.js +32 -0
  120. package/lib/private/GetSlavePositionQuery.js.map +1 -0
  121. package/package.json +10 -10
  122. package/src/Database.ts +4 -3
  123. package/src/DatabaseConnection.ts +6 -0
  124. package/src/IDatabaseConnection.ts +6 -0
  125. package/src/IDatabasePosition.ts +23 -0
  126. package/src/ManagedDatabaseConnection.ts +6 -0
  127. package/src/MySQLConnection.ts +27 -0
  128. package/src/MySQLDatabase.ts +32 -4
  129. package/src/TimeoutError.ts +44 -0
  130. package/src/api.ts +2 -0
  131. package/src/private/ConnectionReplicationWaiter.ts +110 -0
  132. package/src/private/GetBinLogPositionQuery.ts +59 -0
  133. package/src/private/GetMasterPositionQuery.ts +37 -0
  134. package/src/private/GetSlavePositionQuery.ts +37 -0
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ /*
3
+ Copyright 2017-2024 Norman Breau
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.ConnectionReplicationWaiter = void 0;
19
+ const InternalError_1 = require("../InternalError");
20
+ const TimeoutError_1 = require("../TimeoutError");
21
+ class ConnectionReplicationWaiter {
22
+ constructor(conn, retryDelay = ConnectionReplicationWaiter.DEFAULT_RETRY_DELAY) {
23
+ this.$conn = conn;
24
+ this.$retryDelay = retryDelay;
25
+ }
26
+ $sleep(timeout) {
27
+ return new Promise((resolve, reject) => {
28
+ setTimeout(() => {
29
+ resolve();
30
+ }, timeout);
31
+ });
32
+ }
33
+ async wait(target, timeout = ConnectionReplicationWaiter.DEFAULT_TIMEOUT) {
34
+ if (!this.$conn.isReadOnly()) {
35
+ return;
36
+ }
37
+ let shouldTimeout = false;
38
+ let didTimeout = false;
39
+ let timeoutTimer = setTimeout(() => {
40
+ shouldTimeout = true;
41
+ }, timeout);
42
+ // eslint-disable-next-line no-constant-condition
43
+ while (true) {
44
+ if (shouldTimeout) {
45
+ didTimeout = true;
46
+ break;
47
+ }
48
+ let currentPos = await this.$conn.getCurrentDatabasePosition();
49
+ if (currentPos === null || (currentPos && !currentPos.page === null) || (currentPos && !currentPos.position === null)) {
50
+ throw new InternalError_1.InternalError('Database Position not supported');
51
+ }
52
+ // If the current page is greater than the target page,
53
+ // then the position doesn't matter, we are ahead of the
54
+ // desired target position.
55
+ if (currentPos.page > target.page) {
56
+ break;
57
+ }
58
+ // If the pages are equal, we need to check the position
59
+ // and ensure we are at or greater than the target.
60
+ if (currentPos.page === target.page && currentPos.position >= target.position) {
61
+ break;
62
+ }
63
+ // If we made it here, it means the position state checks failed
64
+ // so wait a short while and then re-iterate
65
+ await this.$sleep(this.$retryDelay);
66
+ }
67
+ if (didTimeout) {
68
+ // If the while loop exited due to the timeout,
69
+ // then throw a timeout error
70
+ throw new TimeoutError_1.TimeoutError();
71
+ }
72
+ // Otherwise we are good to go!
73
+ clearTimeout(timeoutTimer);
74
+ }
75
+ }
76
+ exports.ConnectionReplicationWaiter = ConnectionReplicationWaiter;
77
+ /**
78
+ * The default retry delay in milliseconds.
79
+ * Defaults to 1 second.
80
+ *
81
+ * This is the value used in between status query iterations.
82
+ */
83
+ ConnectionReplicationWaiter.DEFAULT_RETRY_DELAY = 1000;
84
+ /**
85
+ * The default timeout delay. Defaults to 120 seconds.
86
+ * If the connection could not reach the target position in time,
87
+ * then the wait will timeout
88
+ *
89
+ * Using `Infinity` will disable the timeout
90
+ */
91
+ ConnectionReplicationWaiter.DEFAULT_TIMEOUT = 120 * 1000; // 120 seconds in ms
92
+ //# sourceMappingURL=ConnectionReplicationWaiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectionReplicationWaiter.js","sourceRoot":"","sources":["../../src/private/ConnectionReplicationWaiter.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;EAcE;;;AAIF,oDAAiD;AACjD,kDAA+C;AAE/C,MAAa,2BAA2B;IAqBpC,YAAmB,IAAyB,EAAE,aAAqB,2BAA2B,CAAC,mBAAmB;QAC9G,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAClC,CAAC;IAEO,MAAM,CAAC,OAAe;QAC1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,UAAU,CAAC,GAAG,EAAE;gBACZ,OAAO,EAAE,CAAC;YACd,CAAC,EAAE,OAAO,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACP,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,MAAyB,EAAE,UAAkB,2BAA2B,CAAC,eAAe;QACtG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC;YAC3B,OAAO;QACX,CAAC;QAED,IAAI,aAAa,GAAY,KAAK,CAAC;QACnC,IAAI,UAAU,GAAY,KAAK,CAAC;QAEhC,IAAI,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE;YAC/B,aAAa,GAAG,IAAI,CAAC;QACzB,CAAC,EAAE,OAAO,CAAC,CAAC;QAEZ,iDAAiD;QACjD,OAAO,IAAI,EAAE,CAAC;YACV,IAAI,aAAa,EAAE,CAAC;gBAChB,UAAU,GAAG,IAAI,CAAC;gBAClB,MAAM;YACV,CAAC;YAED,IAAI,UAAU,GAAsB,MAAM,IAAI,CAAC,KAAK,CAAC,0BAA0B,EAAE,CAAC;YAElF,IAAI,UAAU,KAAK,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,QAAQ,KAAK,IAAI,CAAC,EAAE,CAAC;gBACpH,MAAM,IAAI,6BAAa,CAAC,iCAAiC,CAAC,CAAC;YAC/D,CAAC;YAED,uDAAuD;YACvD,wDAAwD;YACxD,2BAA2B;YAC3B,IAAI,UAAU,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;gBAChC,MAAM;YACV,CAAC;YAED,wDAAwD;YACxD,mDAAmD;YACnD,IAAI,UAAU,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAC5E,MAAM;YACV,CAAC;YAED,gEAAgE;YAChE,4CAA4C;YAC5C,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxC,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACb,+CAA+C;YAC/C,6BAA6B;YAC7B,MAAM,IAAI,2BAAY,EAAE,CAAC;QAC7B,CAAC;QAED,+BAA+B;QAC/B,YAAY,CAAC,YAAY,CAAC,CAAC;IAC/B,CAAC;;AArFL,kEAsFC;AArFG;;;;;GAKG;AACoB,+CAAmB,GAAW,IAAI,CAAC;AAE1D;;;;;;GAMG;AACoB,2CAAe,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,oBAAoB"}
@@ -0,0 +1,12 @@
1
+ import { Query } from '../Query';
2
+ import { IDatabasePosition } from '../IDatabasePosition';
3
+ import { IDatabaseConnection } from '../IDatabaseConnection';
4
+ /**
5
+ * @since 8.1.0
6
+ */
7
+ export declare abstract class GetBinLogPositionQuery<TStatusRow = unknown> extends Query<void, TStatusRow[], IDatabasePosition> {
8
+ protected abstract _getQuery(): string;
9
+ protected abstract _getFile(row: TStatusRow): string;
10
+ protected abstract _getPosition(row: TStatusRow): string;
11
+ onPostProcess(connection: IDatabaseConnection, resultSet: TStatusRow[]): Promise<IDatabasePosition>;
12
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ /*
3
+ Copyright 2017-2024 Norman Breau
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.GetBinLogPositionQuery = void 0;
19
+ const Query_1 = require("../Query");
20
+ /**
21
+ * @since 8.1.0
22
+ */
23
+ class GetBinLogPositionQuery extends Query_1.Query {
24
+ async onPostProcess(connection, resultSet) {
25
+ let row = null;
26
+ if (resultSet.length > 0) {
27
+ row = resultSet[0];
28
+ }
29
+ if (!row) {
30
+ return null;
31
+ }
32
+ let pageParts = this._getFile(row).split('.');
33
+ let strPage = pageParts[pageParts.length - 1];
34
+ let page = parseInt(strPage);
35
+ if (isNaN(page)) {
36
+ return null;
37
+ }
38
+ let position = parseInt(this._getPosition(row));
39
+ if (isNaN(position)) {
40
+ return null;
41
+ }
42
+ return {
43
+ page: page,
44
+ position: position
45
+ };
46
+ }
47
+ }
48
+ exports.GetBinLogPositionQuery = GetBinLogPositionQuery;
49
+ //# sourceMappingURL=GetBinLogPositionQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GetBinLogPositionQuery.js","sourceRoot":"","sources":["../../src/private/GetBinLogPositionQuery.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;EAcE;;;AAEF,oCAA+B;AAI/B;;GAEG;AACH,MAAsB,sBAA6C,SAAQ,aAA4C;IAM5G,KAAK,CAAC,aAAa,CAAC,UAA+B,EAAE,SAAuB;QAC/E,IAAI,GAAG,GAAe,IAAI,CAAC;QAC3B,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QACvB,CAAC;QAED,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,IAAI,SAAS,GAAa,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxD,IAAI,OAAO,GAAW,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEtD,IAAI,IAAI,GAAW,QAAQ,CAAC,OAAO,CAAC,CAAC;QAErC,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACd,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,IAAI,QAAQ,GAAW,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,OAAO;YACH,IAAI,EAAE,IAAI;YACV,QAAQ,EAAE,QAAQ;SACrB,CAAC;IACN,CAAC;CACJ;AAnCD,wDAmCC"}
@@ -0,0 +1,11 @@
1
+ import { GetBinLogPositionQuery } from './GetBinLogPositionQuery';
2
+ interface IStatus {
3
+ File: string;
4
+ Position: string;
5
+ }
6
+ export declare class GetMasterPositionQuery extends GetBinLogPositionQuery<IStatus> {
7
+ protected _getQuery(): string;
8
+ protected _getFile(row: IStatus): string;
9
+ protected _getPosition(row: IStatus): string;
10
+ }
11
+ export {};
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /*
3
+ Copyright 2017-2024 Norman Breau
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.GetMasterPositionQuery = void 0;
19
+ const GetBinLogPositionQuery_1 = require("./GetBinLogPositionQuery");
20
+ class GetMasterPositionQuery extends GetBinLogPositionQuery_1.GetBinLogPositionQuery {
21
+ _getQuery() {
22
+ return 'SHOW MASTER STATUS';
23
+ }
24
+ _getFile(row) {
25
+ return row.File;
26
+ }
27
+ _getPosition(row) {
28
+ return row.Position;
29
+ }
30
+ }
31
+ exports.GetMasterPositionQuery = GetMasterPositionQuery;
32
+ //# sourceMappingURL=GetMasterPositionQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GetMasterPositionQuery.js","sourceRoot":"","sources":["../../src/private/GetMasterPositionQuery.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;EAcE;;;AAEF,qEAAkE;AAOlE,MAAa,sBAAuB,SAAQ,+CAA+B;IAEpD,SAAS;QACxB,OAAO,oBAAoB,CAAC;IAChC,CAAC;IAEkB,QAAQ,CAAC,GAAY;QACpC,OAAO,GAAG,CAAC,IAAI,CAAC;IACpB,CAAC;IAEkB,YAAY,CAAC,GAAY;QACxC,OAAO,GAAG,CAAC,QAAQ,CAAC;IACxB,CAAC;CACJ;AAbD,wDAaC"}
@@ -0,0 +1,11 @@
1
+ import { GetBinLogPositionQuery } from './GetBinLogPositionQuery';
2
+ interface IStatus {
3
+ Master_Log_File: string;
4
+ Read_Master_Log_Pos: string;
5
+ }
6
+ export declare class GetSlavePositionQuery extends GetBinLogPositionQuery<IStatus> {
7
+ protected _getQuery(): string;
8
+ protected _getFile(row: IStatus): string;
9
+ protected _getPosition(row: IStatus): string;
10
+ }
11
+ export {};
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /*
3
+ Copyright 2017-2024 Norman Breau
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.GetSlavePositionQuery = void 0;
19
+ const GetBinLogPositionQuery_1 = require("./GetBinLogPositionQuery");
20
+ class GetSlavePositionQuery extends GetBinLogPositionQuery_1.GetBinLogPositionQuery {
21
+ _getQuery() {
22
+ return 'SHOW SLAVE STATUS';
23
+ }
24
+ _getFile(row) {
25
+ return row.Master_Log_File;
26
+ }
27
+ _getPosition(row) {
28
+ return row.Read_Master_Log_Pos;
29
+ }
30
+ }
31
+ exports.GetSlavePositionQuery = GetSlavePositionQuery;
32
+ //# sourceMappingURL=GetSlavePositionQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GetSlavePositionQuery.js","sourceRoot":"","sources":["../../src/private/GetSlavePositionQuery.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;EAcE;;;AAEF,qEAAkE;AAOlE,MAAa,qBAAsB,SAAQ,+CAA+B;IAEnD,SAAS;QACxB,OAAO,mBAAmB,CAAC;IAC/B,CAAC;IAEkB,QAAQ,CAAC,GAAY;QACpC,OAAO,GAAG,CAAC,eAAe,CAAC;IAC/B,CAAC;IAEkB,YAAY,CAAC,GAAY;QACxC,OAAO,GAAG,CAAC,mBAAmB,CAAC;IACnC,CAAC;CACJ;AAbD,sDAaC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@breautek/storm",
3
- "version": "8.0.0",
3
+ "version": "8.1.0",
4
4
  "description": "Object-Oriented REST API framework",
5
5
  "main": "lib/api.js",
6
6
  "types": "lib/api.d.ts",
@@ -51,19 +51,19 @@
51
51
  "@types/formidable": "3.4.5",
52
52
  "@types/jsonwebtoken": "9.0.6",
53
53
  "@types/mysql": "2.15.26",
54
- "@types/node": "20.12.7",
54
+ "@types/node": "20.14.2",
55
55
  "@types/uuid": "9.0.8",
56
- "ajv": "8.12.0",
56
+ "ajv": "8.16.0",
57
57
  "body-parser": "1.20.2",
58
- "commander": "12.0.0",
58
+ "commander": "12.1.0",
59
59
  "express": "4.19.2",
60
60
  "form-data": "4.0.0",
61
61
  "formidable": "3.5.1",
62
62
  "jsonwebtoken": "9.0.2",
63
63
  "mysql": "2.18.1",
64
64
  "sql-formatter": "15.3.1",
65
- "tslib": "2.6.2",
66
- "uuid": "9.0.1"
65
+ "tslib": "2.6.3",
66
+ "uuid": "10.0.0"
67
67
  },
68
68
  "peerDependencies": {
69
69
  "@arashi/interfaces": "1.x",
@@ -74,16 +74,16 @@
74
74
  "@arashi/logger": "4.0.6",
75
75
  "@totalpave/eslint-plugin": "6.2.0",
76
76
  "@types/jest": "29.5.12",
77
- "@typescript-eslint/eslint-plugin": "7.7.1",
78
- "@typescript-eslint/parser": "7.7.1",
77
+ "@typescript-eslint/eslint-plugin": "7.13.0",
78
+ "@typescript-eslint/parser": "7.13.0",
79
79
  "auto-changelog": "2.4.0",
80
80
  "eslint": "8.57.0",
81
81
  "jest": "29.7.0",
82
82
  "jest-jasmine2": "29.7.0",
83
- "ts-jest": "29.1.2",
83
+ "ts-jest": "29.1.4",
84
84
  "ts-node": "10.9.2",
85
85
  "typedoc": "0.25.13",
86
- "typedoc-plugin-markdown": "3.17.1",
86
+ "typedoc-plugin-markdown": "4.0.3",
87
87
  "typescript": "5.4.5"
88
88
  }
89
89
  }
package/src/Database.ts CHANGED
@@ -17,6 +17,7 @@
17
17
  import * as UUID from 'uuid';
18
18
  import {DatabaseConnection} from './DatabaseConnection';
19
19
  import { getInstance } from './instance';
20
+ import { IDatabasePosition } from './IDatabasePosition';
20
21
 
21
22
  const MASTER_NAME: string = 'MASTER';
22
23
  const TAG: string = 'Database';
@@ -61,7 +62,7 @@ export abstract class Database<TDatabaseConfig, TConnectionAPI> {
61
62
  this._removeNode(slaveID);
62
63
  }
63
64
 
64
- public getConnection(requireWriteAccess: boolean = false, nodeID?: string): Promise<DatabaseConnection<TConnectionAPI>> {
65
+ public getConnection(requireWriteAccess: boolean = false, nodeID?: string, requiredPosition?: IDatabasePosition): Promise<DatabaseConnection<TConnectionAPI>> {
65
66
  let query: string = 'SLAVE*';
66
67
 
67
68
  if (nodeID) {
@@ -71,7 +72,7 @@ export abstract class Database<TDatabaseConfig, TConnectionAPI> {
71
72
  query = 'MASTER';
72
73
  }
73
74
 
74
- return this._getConnection(query, requireWriteAccess);
75
+ return this._getConnection(query, requireWriteAccess, requiredPosition);
75
76
  }
76
77
 
77
78
  public destroy(): Promise<void> {
@@ -81,6 +82,6 @@ export abstract class Database<TDatabaseConfig, TConnectionAPI> {
81
82
  protected abstract _destroy(): Promise<void>;
82
83
  protected abstract _addNode(name: string, config: TDatabaseConfig): void;
83
84
  protected abstract _removeNode(name: string): void;
84
- protected abstract _getConnection(query: string, requireWriteAccess: boolean): Promise<DatabaseConnection<TConnectionAPI>>;
85
+ protected abstract _getConnection(query: string, requireWriteAccess: boolean, requiredPosition?: IDatabasePosition): Promise<DatabaseConnection<TConnectionAPI>>;
85
86
  public abstract escape(query: string): string;
86
87
  }
@@ -22,6 +22,7 @@ import {IDatabaseConnection} from './IDatabaseConnection';
22
22
  import {IQueryable} from './IQueryable';
23
23
  import { IConfig } from './IConfig';
24
24
  import { IsolationLevel } from './IsolationLevel';
25
+ import { IDatabasePosition } from './IDatabasePosition';
25
26
 
26
27
  export const LINGER_WARNING: number = 10000;
27
28
  export const DEFAULT_QUERY_TIMEOUT: number = 3600000;
@@ -260,4 +261,9 @@ export abstract class DatabaseConnection<TAPI> implements IDatabaseConnection {
260
261
  */
261
262
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
262
263
  protected abstract _stream(query: string, params?: any, streamOptions?: any): Readable;
264
+
265
+ /**
266
+ * @since 8.1.0
267
+ */
268
+ public abstract getCurrentDatabasePosition(): Promise<IDatabasePosition>;
263
269
  }
@@ -17,6 +17,7 @@
17
17
  import { Readable } from 'stream';
18
18
  import { IQueryable } from './IQueryable';
19
19
  import { IsolationLevel } from './IsolationLevel';
20
+ import { IDatabasePosition } from './IDatabasePosition';
20
21
 
21
22
  export interface IDatabaseConnection {
22
23
  setInstantiationStack(stack: string): void;
@@ -33,4 +34,9 @@ export interface IDatabaseConnection {
33
34
  isTransaction(): boolean;
34
35
  commit(): Promise<void>;
35
36
  rollback(): Promise<void>;
37
+
38
+ /**
39
+ * @since 8.1.0
40
+ */
41
+ getCurrentDatabasePosition(): Promise<IDatabasePosition>;
36
42
  }
@@ -0,0 +1,23 @@
1
+ /*
2
+ Copyright 2017-2024 Norman Breau
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ /**
18
+ * @since 8.1.0
19
+ */
20
+ export interface IDatabasePosition {
21
+ page: number;
22
+ position: number;
23
+ }
@@ -19,6 +19,7 @@ import {getInstance} from './instance';
19
19
  import {Readable} from 'stream';
20
20
  import { Query } from './Query';
21
21
  import { IsolationLevel } from './IsolationLevel';
22
+ import { IDatabasePosition } from './IDatabasePosition';
22
23
 
23
24
  const TAG: string = 'ManagedDatabaseConnection';
24
25
 
@@ -81,6 +82,11 @@ export class ManagedDatabaseConnection implements IDatabaseConnection {
81
82
  }
82
83
  }
83
84
 
85
+ public async getCurrentDatabasePosition(): Promise<IDatabasePosition> {
86
+ let conn: IDatabaseConnection = await this.$getConnection();
87
+ return await conn.getCurrentDatabasePosition();
88
+ }
89
+
84
90
  public isWriteRequired(): boolean {
85
91
  return this.$requiresWrite;
86
92
  }
@@ -31,6 +31,10 @@ import { DeadLockError } from './DeadLockError';
31
31
  import { IsolationLevel } from './IsolationLevel';
32
32
  import {SetIsolationLevelQuery} from './private/SetIsolationLevelQuery';
33
33
  import { LockWaitTimeoutError } from './LockWaitTimeoutError';
34
+ import { IDatabasePosition } from './IDatabasePosition';
35
+ import { GetBinLogPositionQuery } from './private/GetBinLogPositionQuery';
36
+ import { GetSlavePositionQuery } from './private/GetSlavePositionQuery';
37
+ import { GetMasterPositionQuery } from './private/GetMasterPositionQuery';
34
38
 
35
39
  const DEFAULT_HIGH_WATERMARK: number = 512; // in number of result objects
36
40
  const TAG: string = 'MySQLConnection';
@@ -57,12 +61,14 @@ let rollbackQuery: Query = new RollbackQuery();
57
61
  export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
58
62
  private $transaction: boolean;
59
63
  private $opened: boolean;
64
+ private $isMasterConnection: boolean;
60
65
 
61
66
  public constructor(connection: MySQL.PoolConnection, instantiationStack: string, isReadOnly: boolean = true) {
62
67
  super(connection, isReadOnly, instantiationStack);
63
68
 
64
69
  this.$opened = true;
65
70
  this.$transaction = false;
71
+ this.$isMasterConnection = null;
66
72
 
67
73
  connection.config.queryFormat = function(query: string, values: any) {
68
74
  if (!values) return query;
@@ -77,6 +83,22 @@ export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
77
83
  };
78
84
  }
79
85
 
86
+ /**
87
+ * @internal - Do not use in application code
88
+ */
89
+ public async __internal_init(): Promise<void> {
90
+ let result = await new GetSlavePositionQuery().execute(this);
91
+ this.$isMasterConnection = result === null;
92
+ }
93
+
94
+ public isMaster(): boolean {
95
+ return this.$isMasterConnection;
96
+ }
97
+
98
+ public isReplication(): boolean {
99
+ return !this.isMaster();
100
+ }
101
+
80
102
  public isTransaction(): boolean {
81
103
  return this.$transaction;
82
104
  }
@@ -85,6 +107,11 @@ export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
85
107
  return this.$opened;
86
108
  }
87
109
 
110
+ public override async getCurrentDatabasePosition(): Promise<IDatabasePosition> {
111
+ let statusQuery: GetBinLogPositionQuery = this.isReplication() ? new GetSlavePositionQuery() : new GetMasterPositionQuery();
112
+ return await statusQuery.execute(this);
113
+ }
114
+
88
115
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
89
116
  protected _query(query: string, params?: any): Promise<any> {
90
117
  let logger: BaseLogger = getInstance().getLogger();
@@ -18,6 +18,8 @@ import {Database} from './Database';
18
18
  import {MySQLConnection} from './MySQLConnection';
19
19
  import * as MySQL from 'mysql';
20
20
  import {getInstance} from './instance';
21
+ import { IDatabasePosition } from './IDatabasePosition';
22
+ import { ConnectionReplicationWaiter } from './private/ConnectionReplicationWaiter';
21
23
 
22
24
  const TAG: string = 'MySQLDatabase';
23
25
 
@@ -69,18 +71,44 @@ export class MySQLDatabase extends Database<MySQL.PoolConfig, MySQL.PoolConnecti
69
71
  });
70
72
  }
71
73
 
72
- protected _getConnection(query: string, requireWriteAccess: boolean): Promise<MySQLConnection> {
73
- getInstance().getLogger().trace(TAG, `Querying connection pool for "${query}".`);
74
+ private $getConnectionFromPool(query: string, requireWriteAccess: boolean, instantationStack: string): Promise<MySQLConnection> {
74
75
  return new Promise<MySQLConnection>((resolve, reject) => {
75
- let instantationStack: string = new Error().stack;
76
76
  this.$cluster.getConnection(query, (error: MySQL.MysqlError, connection: MySQL.PoolConnection) => {
77
77
  if (error) {
78
78
  reject(error);
79
79
  return;
80
80
  }
81
-
81
+
82
82
  resolve(new MySQLConnection(connection, instantationStack, !requireWriteAccess));
83
83
  });
84
84
  });
85
85
  }
86
+
87
+ protected override async _getConnection(query: string, requireWriteAccess: boolean, position?: IDatabasePosition): Promise<MySQLConnection> {
88
+ getInstance().getLogger().trace(TAG, `Querying connection pool for "${query}".`);
89
+ let instantationStack: string = new Error().stack;
90
+
91
+ let conn: MySQLConnection = await this.$getConnectionFromPool(query, requireWriteAccess, instantationStack);
92
+ await conn.__internal_init();
93
+
94
+ if (conn.isReplication()) {
95
+ // master connections will not wait on database positions
96
+ // they are guarenteed to be at the tip.
97
+ // readonly, or otherwise known as replication connections
98
+ // may have replication lag. If we have a desired position target,
99
+ // then await for the connection to catch up to that target.
100
+ if (position && position.page && position.position) {
101
+ let waiter: ConnectionReplicationWaiter = new ConnectionReplicationWaiter(conn);
102
+ try {
103
+ await waiter.wait(position);
104
+ }
105
+ catch (ex) {
106
+ conn.close(true);
107
+ throw ex;
108
+ }
109
+ }
110
+ }
111
+
112
+ return conn;
113
+ }
86
114
  }
@@ -0,0 +1,44 @@
1
+ /*
2
+ Copyright 2017-2024 Norman Breau
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import {StormError} from './StormError';
18
+ import {ErrorCode} from './ErrorCode';
19
+ import {StatusCode} from './StatusCode';
20
+
21
+ /**
22
+ * @since 8.1.0
23
+ */
24
+ export class TimeoutError extends StormError {
25
+ public constructor() {
26
+ super();
27
+ }
28
+
29
+ public getMessage(): string {
30
+ return `The requested resource could not be reached in time.`;
31
+ }
32
+
33
+ public getCode(): ErrorCode {
34
+ return ErrorCode.INTERNAL;
35
+ }
36
+
37
+ public getHTTPCode(): StatusCode {
38
+ return StatusCode.ERR_REQUEST_TIMEOUT;
39
+ }
40
+
41
+ public override getLocaleCode(): string {
42
+ return '@breautek/storm/TimeoutError/message';
43
+ }
44
+ }
package/src/api.ts CHANGED
@@ -51,6 +51,7 @@ export {
51
51
  IErrorResponse,
52
52
  IAdditionalErrorDetails
53
53
  } from './StormError';
54
+ export {TimeoutError} from './TimeoutError';
54
55
  export {JWTError} from './JWTError';
55
56
  export {MissingParameterError} from './MissingParameterError';
56
57
  export {InvalidCredentialsError} from './InvalidCredentialsError';
@@ -96,6 +97,7 @@ export {IDatabaseConnection} from './IDatabaseConnection';
96
97
  export {IServiceHeaders} from './IServiceHeaders';
97
98
  export {IAuthTokenData} from './IAuthTokenData';
98
99
  export {IQueryable} from './IQueryable';
100
+ export {IDatabasePosition} from './IDatabasePosition';
99
101
 
100
102
  // Token
101
103
  export {Token} from './Token';