@spine-event-engine/storage-mysql 2.0.0-snapshot.13
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/LICENSE +201 -0
- package/README.md +243 -0
- package/REFERENCE.md +140 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/mysql/column-mapping.d.ts +27 -0
- package/dist/mysql/column-mapping.d.ts.map +1 -0
- package/dist/mysql/column-mapping.js +94 -0
- package/dist/mysql/column-mapping.js.map +1 -0
- package/dist/mysql/delivery-cleanup.d.ts +37 -0
- package/dist/mysql/delivery-cleanup.d.ts.map +1 -0
- package/dist/mysql/delivery-cleanup.js +108 -0
- package/dist/mysql/delivery-cleanup.js.map +1 -0
- package/dist/mysql/entity-commit.d.ts +79 -0
- package/dist/mysql/entity-commit.d.ts.map +1 -0
- package/dist/mysql/entity-commit.js +123 -0
- package/dist/mysql/entity-commit.js.map +1 -0
- package/dist/mysql/entity-history.d.ts +123 -0
- package/dist/mysql/entity-history.d.ts.map +1 -0
- package/dist/mysql/entity-history.js +347 -0
- package/dist/mysql/entity-history.js.map +1 -0
- package/dist/mysql/errors.d.ts +25 -0
- package/dist/mysql/errors.d.ts.map +1 -0
- package/dist/mysql/errors.js +44 -0
- package/dist/mysql/errors.js.map +1 -0
- package/dist/mysql/id-column.d.ts +36 -0
- package/dist/mysql/id-column.d.ts.map +1 -0
- package/dist/mysql/id-column.js +113 -0
- package/dist/mysql/id-column.js.map +1 -0
- package/dist/mysql/record-storage.d.ts +379 -0
- package/dist/mysql/record-storage.d.ts.map +1 -0
- package/dist/mysql/record-storage.js +941 -0
- package/dist/mysql/record-storage.js.map +1 -0
- package/dist/mysql/storage-factory.d.ts +218 -0
- package/dist/mysql/storage-factory.d.ts.map +1 -0
- package/dist/mysql/storage-factory.js +477 -0
- package/dist/mysql/storage-factory.js.map +1 -0
- package/dist/mysql/table-resolver.d.ts +34 -0
- package/dist/mysql/table-resolver.d.ts.map +1 -0
- package/dist/mysql/table-resolver.js +87 -0
- package/dist/mysql/table-resolver.js.map +1 -0
- package/dist/mysql/table-spec.d.ts +88 -0
- package/dist/mysql/table-spec.d.ts.map +1 -0
- package/dist/mysql/table-spec.js +105 -0
- package/dist/mysql/table-spec.js.map +1 -0
- package/dist/mysql/testing.d.ts +47 -0
- package/dist/mysql/testing.d.ts.map +1 -0
- package/dist/mysql/testing.js +111 -0
- package/dist/mysql/testing.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, CodeMatters. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
5
|
+
* in compliance with the License. You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
10
|
+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
11
|
+
* or implied. See the License for the specific language governing permissions and limitations under
|
|
12
|
+
* the License.
|
|
13
|
+
*/
|
|
14
|
+
import { ScalarType } from "@bufbuild/protobuf";
|
|
15
|
+
import { StringifierRegistry } from "@spine-event-engine/core";
|
|
16
|
+
const timestampType = "google.protobuf.Timestamp";
|
|
17
|
+
const versionType = "spine.core.Version";
|
|
18
|
+
/**
|
|
19
|
+
* Converts typed Protobuf column values to Spine JVM JDBC values.
|
|
20
|
+
*/
|
|
21
|
+
export class MysqlColumnMapping {
|
|
22
|
+
#stringifiers;
|
|
23
|
+
/**
|
|
24
|
+
* Creates a JVM-compatible MySQL column mapping.
|
|
25
|
+
*
|
|
26
|
+
* @param stringifiers The schema-bound message stringifiers.
|
|
27
|
+
*/
|
|
28
|
+
constructor(stringifiers = new StringifierRegistry()) {
|
|
29
|
+
this.#stringifiers = new StringifierRegistry(stringifiers);
|
|
30
|
+
}
|
|
31
|
+
// prettier-ignore
|
|
32
|
+
/**
|
|
33
|
+
* Returns the conversion for one generated column type.
|
|
34
|
+
*
|
|
35
|
+
* @param type The generated Protobuf column type.
|
|
36
|
+
* @returns The JVM-compatible MySQL parameter conversion.
|
|
37
|
+
*/
|
|
38
|
+
of(type) {
|
|
39
|
+
switch (type.kind) {
|
|
40
|
+
case "scalar":
|
|
41
|
+
return MysqlMappings.scalar(type.scalar);
|
|
42
|
+
case "enum":
|
|
43
|
+
return (value) => value;
|
|
44
|
+
case "message":
|
|
45
|
+
if (type.message.typeName === timestampType) {
|
|
46
|
+
return (value) => MysqlMappings.timestamp(value);
|
|
47
|
+
}
|
|
48
|
+
if (type.message.typeName === versionType) {
|
|
49
|
+
return (value) => MysqlMappings.version(value);
|
|
50
|
+
}
|
|
51
|
+
return (value) => this.#stringifiers
|
|
52
|
+
.forMessage(type.message)
|
|
53
|
+
.toString(value);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns SQL null unchanged.
|
|
58
|
+
* @returns The null conversion.
|
|
59
|
+
*/
|
|
60
|
+
ofNull() {
|
|
61
|
+
return (value) => value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const MysqlMappings = Object.freeze({
|
|
65
|
+
scalar(type) {
|
|
66
|
+
switch (type) {
|
|
67
|
+
case ScalarType.STRING:
|
|
68
|
+
case ScalarType.INT32:
|
|
69
|
+
case ScalarType.SINT32:
|
|
70
|
+
case ScalarType.SFIXED32:
|
|
71
|
+
case ScalarType.UINT32:
|
|
72
|
+
case ScalarType.FIXED32:
|
|
73
|
+
case ScalarType.INT64:
|
|
74
|
+
case ScalarType.SINT64:
|
|
75
|
+
case ScalarType.SFIXED64:
|
|
76
|
+
case ScalarType.UINT64:
|
|
77
|
+
case ScalarType.FIXED64:
|
|
78
|
+
case ScalarType.BOOL:
|
|
79
|
+
case ScalarType.BYTES:
|
|
80
|
+
return (value) => value;
|
|
81
|
+
case ScalarType.FLOAT:
|
|
82
|
+
case ScalarType.DOUBLE:
|
|
83
|
+
throw new Error("Spine JVM JDBC does not support floating-point record columns.");
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
timestamp(value) {
|
|
87
|
+
const timestamp = value;
|
|
88
|
+
return timestamp.seconds * 1000000000n + BigInt(timestamp.nanos);
|
|
89
|
+
},
|
|
90
|
+
version(value) {
|
|
91
|
+
return value.number;
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=column-mapping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"column-mapping.js","sourceRoot":"","sources":["../../src/mysql/column-mapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAgB,MAAM,oBAAoB,CAAC;AAE9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAO/D,MAAM,aAAa,GAAG,2BAA2B,CAAC;AAClD,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAEzC;;GAEG;AACH,MAAM,OAAO,kBAAkB;IACpB,aAAa,CAAsB;IAE5C;;;;OAIG;IACH,YAAY,eAAoC,IAAI,mBAAmB,EAAE;QACvE,IAAI,CAAC,aAAa,GAAG,IAAI,mBAAmB,CAAC,YAAY,CAAC,CAAC;IAC7D,CAAC;IAED,kBAAkB;IAElB;;;;;OAKG;IACH,EAAE,CAAI,IAAyB;QAC7B,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,QAAQ;gBACX,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC3C,KAAK,MAAM;gBACT,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;YAC1B,KAAK,SAAS;gBACZ,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;oBAC5C,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;gBACnD,CAAC;gBACD,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;oBAC1C,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACjD,CAAC;gBACD,OAAO,CAAC,KAAK,EAAE,EAAE,CACf,IAAI,CAAC,aAAa;qBACf,UAAU,CAAC,IAAI,CAAC,OAA8B,CAAC;qBAC/C,QAAQ,CAAC,KAAgB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;IAC1B,CAAC;CACF;AAED,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,MAAM,CAAI,IAAgB;QACxB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,UAAU,CAAC,MAAM,CAAC;YACvB,KAAK,UAAU,CAAC,KAAK,CAAC;YACtB,KAAK,UAAU,CAAC,MAAM,CAAC;YACvB,KAAK,UAAU,CAAC,QAAQ,CAAC;YACzB,KAAK,UAAU,CAAC,MAAM,CAAC;YACvB,KAAK,UAAU,CAAC,OAAO,CAAC;YACxB,KAAK,UAAU,CAAC,KAAK,CAAC;YACtB,KAAK,UAAU,CAAC,MAAM,CAAC;YACvB,KAAK,UAAU,CAAC,QAAQ,CAAC;YACzB,KAAK,UAAU,CAAC,MAAM,CAAC;YACvB,KAAK,UAAU,CAAC,OAAO,CAAC;YACxB,KAAK,UAAU,CAAC,IAAI,CAAC;YACrB,KAAK,UAAU,CAAC,KAAK;gBACnB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;YAC1B,KAAK,UAAU,CAAC,KAAK,CAAC;YACtB,KAAK,UAAU,CAAC,MAAM;gBACpB,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IAED,SAAS,CAAC,KAAc;QACtB,MAAM,SAAS,GAAG,KAA6D,CAAC;QAChF,OAAO,SAAS,CAAC,OAAO,GAAG,WAAc,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,CAAC,KAAc;QACpB,OAAQ,KAAqC,CAAC,MAAM,CAAC;IACvD,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Message } from "@bufbuild/protobuf";
|
|
2
|
+
import type { PoolConnection } from "mysql2/promise";
|
|
3
|
+
import { type DeliveryCleanupInput, type DeliveryCleanupStorage } from "@spine-event-engine/storage/provider";
|
|
4
|
+
import type { RecordSpec, StorageContext } from "@spine-event-engine/storage";
|
|
5
|
+
import { MysqlRecordStorage } from "./record-storage.js";
|
|
6
|
+
/**
|
|
7
|
+
* Coordinates one fenced delivered Inbox deletion in MySQL.
|
|
8
|
+
*/
|
|
9
|
+
export declare class MysqlDeliveryCleanupStorage implements DeliveryCleanupStorage {
|
|
10
|
+
#private;
|
|
11
|
+
private readonly openStorage;
|
|
12
|
+
private readonly coordinate;
|
|
13
|
+
private readonly lockKey;
|
|
14
|
+
/**
|
|
15
|
+
* Creates a MySQL cleanup coordinator.
|
|
16
|
+
*
|
|
17
|
+
* @param openStorage Opens a record-storage handle for one record family.
|
|
18
|
+
* @param coordinate Runs work under the provider's two-family coordinator.
|
|
19
|
+
* @param lockKey Derives the provider coordination key from cleanup input.
|
|
20
|
+
*/
|
|
21
|
+
constructor(openStorage: <I, R extends Message>(context: StorageContext, spec: RecordSpec<I, R>) => MysqlRecordStorage<I, R>, coordinate: <T>(context: StorageContext, tables: readonly string[], key: string, work: (connection: PoolConnection) => Promise<T>) => Promise<T>, lockKey: (input: DeliveryCleanupInput<unknown, Message, unknown, Message>) => string);
|
|
22
|
+
/**
|
|
23
|
+
* Removes an exact Inbox row after locking and validating its session row.
|
|
24
|
+
*
|
|
25
|
+
* @param input Describes the records and ownership predicate for deletion.
|
|
26
|
+
* @returns Whether the coordinator deleted the exact Inbox row.
|
|
27
|
+
*/
|
|
28
|
+
remove<InboxId, InboxRecord extends Message, SessionId, SessionRecord extends Message>(input: DeliveryCleanupInput<InboxId, InboxRecord, SessionId, SessionRecord>): Promise<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Closes this cleanup coordinator to further removal operations.
|
|
31
|
+
*/
|
|
32
|
+
close(): void;
|
|
33
|
+
private removeOn;
|
|
34
|
+
private static same;
|
|
35
|
+
private static active;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=delivery-cleanup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery-cleanup.d.ts","sourceRoot":"","sources":["../../src/mysql/delivery-cleanup.ts"],"names":[],"mappings":"AAcA,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC5B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;GAEG;AACH,qBAAa,2BAA4B,YAAW,sBAAsB;;IAWtE,OAAO,CAAC,QAAQ,CAAC,WAAW;IAI5B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAM3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAlB1B;;;;;;OAMG;gBAEgB,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,SAAS,OAAO,EACjD,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,KACnB,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,EACZ,UAAU,EAAE,CAAC,CAAC,EAC7B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,CAAC,UAAU,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,KAC7C,OAAO,CAAC,CAAC,CAAC,EACE,OAAO,EAAE,CACxB,KAAK,EAAE,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,KAC5D,MAAM;IAGb;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,WAAW,SAAS,OAAO,EAAE,SAAS,EAAE,aAAa,SAAS,OAAO,EACzF,KAAK,EAAE,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,CAAC,GAC1E,OAAO,CAAC,OAAO,CAAC;IAuBnB;;OAEG;IACH,KAAK,IAAI,IAAI;YAIC,QAAQ;IA0CtB,OAAO,CAAC,MAAM,CAAC,IAAI;IAKnB,OAAO,CAAC,MAAM,CAAC,MAAM;CAGtB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, CodeMatters. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
5
|
+
* in compliance with the License. You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
10
|
+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
11
|
+
* or implied. See the License for the specific language governing permissions and limitations under
|
|
12
|
+
* the License.
|
|
13
|
+
*/
|
|
14
|
+
import { toBinary } from "@bufbuild/protobuf";
|
|
15
|
+
import { cleanupOperationActive, } from "@spine-event-engine/storage/provider";
|
|
16
|
+
import { MysqlRecordStorage } from "./record-storage.js";
|
|
17
|
+
/**
|
|
18
|
+
* Coordinates one fenced delivered Inbox deletion in MySQL.
|
|
19
|
+
*/
|
|
20
|
+
export class MysqlDeliveryCleanupStorage {
|
|
21
|
+
openStorage;
|
|
22
|
+
coordinate;
|
|
23
|
+
lockKey;
|
|
24
|
+
#open = true;
|
|
25
|
+
/**
|
|
26
|
+
* Creates a MySQL cleanup coordinator.
|
|
27
|
+
*
|
|
28
|
+
* @param openStorage Opens a record-storage handle for one record family.
|
|
29
|
+
* @param coordinate Runs work under the provider's two-family coordinator.
|
|
30
|
+
* @param lockKey Derives the provider coordination key from cleanup input.
|
|
31
|
+
*/
|
|
32
|
+
constructor(openStorage, coordinate, lockKey) {
|
|
33
|
+
this.openStorage = openStorage;
|
|
34
|
+
this.coordinate = coordinate;
|
|
35
|
+
this.lockKey = lockKey;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Removes an exact Inbox row after locking and validating its session row.
|
|
39
|
+
*
|
|
40
|
+
* @param input Describes the records and ownership predicate for deletion.
|
|
41
|
+
* @returns Whether the coordinator deleted the exact Inbox row.
|
|
42
|
+
*/
|
|
43
|
+
async remove(input) {
|
|
44
|
+
if (!this.#open)
|
|
45
|
+
throw new Error("Delivery cleanup storage is closed.");
|
|
46
|
+
if (!MysqlDeliveryCleanupStorage.active(input))
|
|
47
|
+
return false;
|
|
48
|
+
const inbox = this.openStorage(input.context, input.inbox.spec);
|
|
49
|
+
const sessions = this.openStorage(input.context, input.session.spec);
|
|
50
|
+
try {
|
|
51
|
+
await Promise.all([inbox.prepare(), sessions.prepare()]);
|
|
52
|
+
if (!MysqlDeliveryCleanupStorage.active(input))
|
|
53
|
+
return false;
|
|
54
|
+
return await this.coordinate(input.context, [inbox.tableName, sessions.tableName], this.lockKey(input), async (connection) => this.removeOn(connection, inbox, sessions, input));
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof CleanupExpired)
|
|
58
|
+
return false;
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
inbox.close();
|
|
63
|
+
sessions.close();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Closes this cleanup coordinator to further removal operations.
|
|
68
|
+
*/
|
|
69
|
+
close() {
|
|
70
|
+
this.#open = false;
|
|
71
|
+
}
|
|
72
|
+
async removeOn(connection, inbox, sessions, input) {
|
|
73
|
+
if (!MysqlDeliveryCleanupStorage.active(input))
|
|
74
|
+
return false;
|
|
75
|
+
return sessions.withConnection(connection, () => inbox.withConnection(connection, async () => {
|
|
76
|
+
const currentSession = await sessions.readLocked(input.session.id);
|
|
77
|
+
if (currentSession === undefined ||
|
|
78
|
+
!MysqlDeliveryCleanupStorage.same(input.session.spec, currentSession, input.session.expected) ||
|
|
79
|
+
!input.session.isCurrent(currentSession)) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const currentInbox = await inbox.readLocked(input.inbox.id);
|
|
83
|
+
if (currentInbox === undefined ||
|
|
84
|
+
!MysqlDeliveryCleanupStorage.same(input.inbox.spec, currentInbox, input.inbox.expected)) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (!input.session.isCurrent(currentSession))
|
|
88
|
+
return false;
|
|
89
|
+
if (!MysqlDeliveryCleanupStorage.active(input))
|
|
90
|
+
return false;
|
|
91
|
+
const removed = await inbox.delete(input.inbox.id);
|
|
92
|
+
if (!input.session.isCurrent(currentSession))
|
|
93
|
+
throw new CleanupExpired();
|
|
94
|
+
if (!MysqlDeliveryCleanupStorage.active(input))
|
|
95
|
+
throw new CleanupExpired();
|
|
96
|
+
return removed;
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
static same(spec, left, right) {
|
|
100
|
+
return Buffer.from(toBinary(spec.recordType, left)).equals(Buffer.from(toBinary(spec.recordType, right)));
|
|
101
|
+
}
|
|
102
|
+
static active(input) {
|
|
103
|
+
return cleanupOperationActive(input.operation);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
class CleanupExpired extends Error {
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=delivery-cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery-cleanup.js","sourceRoot":"","sources":["../../src/mysql/delivery-cleanup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { PoolConnection } from "mysql2/promise";
|
|
2
|
+
/**
|
|
3
|
+
* Identifies one Entity commit in MySQL's server advisory-lock namespace.
|
|
4
|
+
*/
|
|
5
|
+
export interface MysqlEntityLockIdentity {
|
|
6
|
+
/**
|
|
7
|
+
* Names the MySQL database containing the Entity families.
|
|
8
|
+
*/
|
|
9
|
+
readonly databaseName: string;
|
|
10
|
+
/**
|
|
11
|
+
* Identifies the Entity.
|
|
12
|
+
*/
|
|
13
|
+
readonly entityKey: string;
|
|
14
|
+
/**
|
|
15
|
+
* Names the Entity source type.
|
|
16
|
+
*/
|
|
17
|
+
readonly sourceTypeName: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Calculates MySQL's fixed-width advisory-lock key for one Entity identity.
|
|
21
|
+
*
|
|
22
|
+
* @param identity Identifies the Entity commit.
|
|
23
|
+
* @returns Returns the advisory-lock key.
|
|
24
|
+
*/
|
|
25
|
+
export declare function mysqlEntityLockKey(identity: MysqlEntityLockIdentity): string;
|
|
26
|
+
/**
|
|
27
|
+
* Coordinates one-connection Entity commits.
|
|
28
|
+
*/
|
|
29
|
+
export declare class MysqlEntityCommitCoordinator {
|
|
30
|
+
private readonly connections;
|
|
31
|
+
/**
|
|
32
|
+
* Creates an Entity commit coordinator.
|
|
33
|
+
*
|
|
34
|
+
* @param connections Acquires and releases MySQL connections.
|
|
35
|
+
*/
|
|
36
|
+
constructor(connections: {
|
|
37
|
+
acquire(): Promise<PoolConnection>;
|
|
38
|
+
release(connection: PoolConnection): void;
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Commits one Entity mutation with a transaction or advisory lock.
|
|
42
|
+
*
|
|
43
|
+
* @param tables Lists participating physical tables.
|
|
44
|
+
* @param key Identifies the advisory lock.
|
|
45
|
+
* @param work Performs the connection-bound mutation.
|
|
46
|
+
* @param options Requires a transaction when the caller cannot use an advisory lock.
|
|
47
|
+
* @typeParam T The mutation result type.
|
|
48
|
+
* @returns Returns the work result.
|
|
49
|
+
*/
|
|
50
|
+
commit<T>(tables: readonly string[], key: string, work: (connection: PoolConnection, transactional: boolean) => Promise<T>, options?: {
|
|
51
|
+
readonly requireTransaction?: boolean;
|
|
52
|
+
}): Promise<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Determines whether every participating table supports transactions.
|
|
55
|
+
*
|
|
56
|
+
* @param connection Provides the connection used for metadata inspection.
|
|
57
|
+
* @param tables Lists participating physical tables.
|
|
58
|
+
* @returns Resolves whether every table uses InnoDB.
|
|
59
|
+
*/
|
|
60
|
+
private allTransactional;
|
|
61
|
+
/**
|
|
62
|
+
* Commits transactional work and retries one deadlock.
|
|
63
|
+
*
|
|
64
|
+
* @param connection Provides the transaction connection.
|
|
65
|
+
* @param work Performs the connection-bound mutation.
|
|
66
|
+
* @typeParam T The mutation result type.
|
|
67
|
+
* @returns Resolves to the mutation result.
|
|
68
|
+
*/
|
|
69
|
+
private commitTransaction;
|
|
70
|
+
/**
|
|
71
|
+
* Acquires the advisory lock for a non-transactional commit.
|
|
72
|
+
*
|
|
73
|
+
* @param connection Provides the lock connection.
|
|
74
|
+
* @param key Identifies the advisory lock.
|
|
75
|
+
* @returns Resolves after the lock is acquired.
|
|
76
|
+
*/
|
|
77
|
+
private acquireLock;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=entity-commit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-commit.d.ts","sourceRoot":"","sources":["../../src/mysql/entity-commit.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,gBAAgB,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IAGtC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,MAAM,CAI5E;AAED;;GAEG;AACH,qBAAa,4BAA4B;IASrC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAN9B;;;;OAIG;gBAEgB,WAAW,EAAE;QAC5B,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;QACnC,OAAO,CAAC,UAAU,EAAE,cAAc,GAAG,IAAI,CAAC;KAC3C;IAGH;;;;;;;;;OASG;IACG,MAAM,CAAC,CAAC,EACZ,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,CAAC,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,EACxE,OAAO,GAAE;QAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAO,GACtD,OAAO,CAAC,CAAC,CAAC;IAiBb;;;;;;OAMG;YACW,gBAAgB;IAa9B;;;;;;;OAOG;YACW,iBAAiB;IAmB/B;;;;;;OAMG;YACW,WAAW;CAQ1B"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, CodeMatters. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
5
|
+
* in compliance with the License. You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
10
|
+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
11
|
+
* or implied. See the License for the specific language governing permissions and limitations under
|
|
12
|
+
* the License.
|
|
13
|
+
*/
|
|
14
|
+
import { createHash } from "node:crypto";
|
|
15
|
+
/**
|
|
16
|
+
* Calculates MySQL's fixed-width advisory-lock key for one Entity identity.
|
|
17
|
+
*
|
|
18
|
+
* @param identity Identifies the Entity commit.
|
|
19
|
+
* @returns Returns the advisory-lock key.
|
|
20
|
+
*/
|
|
21
|
+
export function mysqlEntityLockKey(identity) {
|
|
22
|
+
return createHash("sha256")
|
|
23
|
+
.update([identity.databaseName, identity.sourceTypeName, identity.entityKey].join("\u0000"))
|
|
24
|
+
.digest("hex");
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Coordinates one-connection Entity commits.
|
|
28
|
+
*/
|
|
29
|
+
export class MysqlEntityCommitCoordinator {
|
|
30
|
+
connections;
|
|
31
|
+
// prettier-ignore
|
|
32
|
+
/**
|
|
33
|
+
* Creates an Entity commit coordinator.
|
|
34
|
+
*
|
|
35
|
+
* @param connections Acquires and releases MySQL connections.
|
|
36
|
+
*/
|
|
37
|
+
constructor(connections) {
|
|
38
|
+
this.connections = connections;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Commits one Entity mutation with a transaction or advisory lock.
|
|
42
|
+
*
|
|
43
|
+
* @param tables Lists participating physical tables.
|
|
44
|
+
* @param key Identifies the advisory lock.
|
|
45
|
+
* @param work Performs the connection-bound mutation.
|
|
46
|
+
* @param options Requires a transaction when the caller cannot use an advisory lock.
|
|
47
|
+
* @typeParam T The mutation result type.
|
|
48
|
+
* @returns Returns the work result.
|
|
49
|
+
*/
|
|
50
|
+
async commit(tables, key, work, options = {}) {
|
|
51
|
+
const connection = await this.connections.acquire();
|
|
52
|
+
let locked = false;
|
|
53
|
+
try {
|
|
54
|
+
const transactional = await this.allTransactional(connection, tables);
|
|
55
|
+
if (!transactional && options.requireTransaction)
|
|
56
|
+
throw new Error("MySQL delivery cleanup requires transactional record tables.");
|
|
57
|
+
if (transactional)
|
|
58
|
+
return await this.commitTransaction(connection, work);
|
|
59
|
+
await this.acquireLock(connection, key);
|
|
60
|
+
locked = true;
|
|
61
|
+
return await work(connection, false);
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
if (locked)
|
|
65
|
+
await connection.execute("SELECT RELEASE_LOCK(?)", [key]).catch(() => undefined);
|
|
66
|
+
this.connections.release(connection);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Determines whether every participating table supports transactions.
|
|
71
|
+
*
|
|
72
|
+
* @param connection Provides the connection used for metadata inspection.
|
|
73
|
+
* @param tables Lists participating physical tables.
|
|
74
|
+
* @returns Resolves whether every table uses InnoDB.
|
|
75
|
+
*/
|
|
76
|
+
async allTransactional(connection, tables) {
|
|
77
|
+
const [rows] = await connection.query("SELECT engine AS engine FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name IN (?)", [tables]);
|
|
78
|
+
return (rows.length === tables.length && rows.every((row) => row.engine?.toLowerCase() === "innodb"));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Commits transactional work and retries one deadlock.
|
|
82
|
+
*
|
|
83
|
+
* @param connection Provides the transaction connection.
|
|
84
|
+
* @param work Performs the connection-bound mutation.
|
|
85
|
+
* @typeParam T The mutation result type.
|
|
86
|
+
* @returns Resolves to the mutation result.
|
|
87
|
+
*/
|
|
88
|
+
async commitTransaction(connection, work) {
|
|
89
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
90
|
+
try {
|
|
91
|
+
await connection.beginTransaction();
|
|
92
|
+
const result = await work(connection, true);
|
|
93
|
+
await connection.commit();
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
await connection.rollback().catch(() => undefined);
|
|
98
|
+
if (attempt === 0 && isDeadlock(error))
|
|
99
|
+
continue;
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
throw new Error("Unreachable InnoDB commit retry.");
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Acquires the advisory lock for a non-transactional commit.
|
|
107
|
+
*
|
|
108
|
+
* @param connection Provides the lock connection.
|
|
109
|
+
* @param key Identifies the advisory lock.
|
|
110
|
+
* @returns Resolves after the lock is acquired.
|
|
111
|
+
*/
|
|
112
|
+
async acquireLock(connection, key) {
|
|
113
|
+
const [rows] = await connection.execute("SELECT GET_LOCK(?, ?) AS acquired", [key, 30]);
|
|
114
|
+
if (rows[0]?.acquired !== 1 && rows[0]?.acquired !== "1")
|
|
115
|
+
throw new Error("Unable to acquire MySQL entity lock.");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function isDeadlock(error) {
|
|
119
|
+
return (typeof error === "object" &&
|
|
120
|
+
error !== null &&
|
|
121
|
+
error.code === "ER_LOCK_DEADLOCK");
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=entity-commit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-commit.js","sourceRoot":"","sources":["../../src/mysql/entity-commit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { type Message } from "@bufbuild/protobuf";
|
|
2
|
+
import type { Event } from "@spine-event-engine/proto";
|
|
3
|
+
import type { EntityRecord } from "@spine-event-engine/proto/generated/spine/server/entity/entity_pb.js";
|
|
4
|
+
import { RecordSpec } from "@spine-event-engine/storage";
|
|
5
|
+
import { type EntityEventHistoryPort, type EntityRecordStorage, type EntityStateHistoryPort, type EntityStorageInput } from "@spine-event-engine/storage/provider";
|
|
6
|
+
import { MysqlRecordStorage } from "./record-storage.js";
|
|
7
|
+
interface EntityFamilyCommitCapability<I> {
|
|
8
|
+
prepare(): Promise<void>;
|
|
9
|
+
tableNames(): readonly string[];
|
|
10
|
+
withConnection<T>(connection: import("mysql2/promise").PoolConnection, work: () => Promise<T>): Promise<T>;
|
|
11
|
+
readCurrentLocked(id: I): Promise<EntityRecord | undefined>;
|
|
12
|
+
preflightImmutable(states: readonly EntityRecord[], diagnostics: readonly Event[]): Promise<void>;
|
|
13
|
+
appendStateImmutable(record: EntityRecord): Promise<void>;
|
|
14
|
+
appendDiagnosticImmutable(record: Event): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Describes MySQL-backed Entity record-family handles.
|
|
18
|
+
*/
|
|
19
|
+
export interface MysqlEntityStorageHandle<I, S extends Message> {
|
|
20
|
+
/**
|
|
21
|
+
* Exposes current Entity records.
|
|
22
|
+
*/
|
|
23
|
+
readonly current: EntityRecordStorage<I>;
|
|
24
|
+
/**
|
|
25
|
+
* Exposes Entity state history records.
|
|
26
|
+
*/
|
|
27
|
+
readonly states: EntityStateHistoryPort<I, S>;
|
|
28
|
+
/**
|
|
29
|
+
* Exposes Entity event history records.
|
|
30
|
+
*/
|
|
31
|
+
readonly events: EntityEventHistoryPort<I>;
|
|
32
|
+
/**
|
|
33
|
+
* Returns whether this Entity storage handle accepts operations.
|
|
34
|
+
*
|
|
35
|
+
* @returns Returns whether the handle is open.
|
|
36
|
+
*/
|
|
37
|
+
isOpen(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Closes the history record-family handles.
|
|
40
|
+
*/
|
|
41
|
+
close(): void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Provides MySQL-backed Entity current and history storage.
|
|
45
|
+
*/
|
|
46
|
+
export declare class MysqlEntityStorage<I, S extends Message> implements MysqlEntityStorageHandle<I, S> {
|
|
47
|
+
#private;
|
|
48
|
+
private readonly onClose;
|
|
49
|
+
/**
|
|
50
|
+
* Exposes current Entity records.
|
|
51
|
+
*/
|
|
52
|
+
readonly current: EntityRecordStorage<I>;
|
|
53
|
+
/**
|
|
54
|
+
* Exposes Entity state history records.
|
|
55
|
+
*/
|
|
56
|
+
readonly states: EntityStateHistoryPort<I, S>;
|
|
57
|
+
/**
|
|
58
|
+
* Exposes Entity event history records.
|
|
59
|
+
*/
|
|
60
|
+
readonly events: EntityEventHistoryPort<I>;
|
|
61
|
+
/**
|
|
62
|
+
* Creates MySQL-backed Entity storage handles.
|
|
63
|
+
*
|
|
64
|
+
* @param input Configures the Entity storage families.
|
|
65
|
+
* @param open Opens one record-family storage handle.
|
|
66
|
+
* @param onClose Removes this Entity handle from its factory.
|
|
67
|
+
*/
|
|
68
|
+
constructor(input: EntityStorageInput<I, S>, open: <Id, R extends Message>(spec: RecordSpec<Id, R>, group?: import("@spine-event-engine/storage").StorageGroup) => MysqlRecordStorage<Id, R>, onClose?: () => void);
|
|
69
|
+
/**
|
|
70
|
+
* Reads the current Entity record while the coordinator owns its row lock.
|
|
71
|
+
*
|
|
72
|
+
* @param id Identifies the Entity.
|
|
73
|
+
* @returns Resolves to the current record when present.
|
|
74
|
+
*/
|
|
75
|
+
readCurrentLocked(id: I): Promise<EntityRecord | undefined>;
|
|
76
|
+
/**
|
|
77
|
+
* Returns whether this Entity storage handle accepts operations.
|
|
78
|
+
*
|
|
79
|
+
* @returns Returns whether the handle is open.
|
|
80
|
+
*/
|
|
81
|
+
isOpen(): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Closes the history record-family handles.
|
|
84
|
+
*/
|
|
85
|
+
close(): void;
|
|
86
|
+
/**
|
|
87
|
+
* Binds all Entity handles to one connection for work.
|
|
88
|
+
*
|
|
89
|
+
* @param connection Provides the coordinator-owned connection.
|
|
90
|
+
* @param work Performs the bound storage work.
|
|
91
|
+
* @returns Returns the work result.
|
|
92
|
+
*/
|
|
93
|
+
withConnection<T>(connection: import("mysql2/promise").PoolConnection, work: () => Promise<T>): Promise<T>;
|
|
94
|
+
/**
|
|
95
|
+
* Returns the physical tables used by the Entity families.
|
|
96
|
+
*
|
|
97
|
+
* @returns Returns the resolved table names.
|
|
98
|
+
*/
|
|
99
|
+
tableNames(): readonly string[];
|
|
100
|
+
/**
|
|
101
|
+
* Prepares every Entity record-family table.
|
|
102
|
+
*
|
|
103
|
+
* @returns Resolves after the tables are ready.
|
|
104
|
+
*/
|
|
105
|
+
prepare(): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* Checks immutable state and diagnostic records before a nontransactional write.
|
|
108
|
+
*
|
|
109
|
+
* @param states Lists state history records to check.
|
|
110
|
+
* @param diagnostics Lists diagnostic history records to check.
|
|
111
|
+
* @returns Resolves when every record is compatible.
|
|
112
|
+
*/
|
|
113
|
+
preflightImmutable(states: readonly EntityRecord[], diagnostics: readonly Event[]): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* Exposes the private MySQL operations required by atomic Entity commit.
|
|
116
|
+
*
|
|
117
|
+
* @internal
|
|
118
|
+
* @returns Returns the private Entity-family commit capability.
|
|
119
|
+
*/
|
|
120
|
+
commitCapability(): EntityFamilyCommitCapability<I>;
|
|
121
|
+
}
|
|
122
|
+
export {};
|
|
123
|
+
//# sourceMappingURL=entity-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-history.d.ts","sourceRoot":"","sources":["../../src/mysql/entity-history.ts"],"names":[],"mappings":"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"}
|