This is an automated email from the ASF dual-hosted git repository.
piotr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git
The following commit(s) were added to refs/heads/master by this push:
new 3f69440a feat(js): return message id as bigint instead of uuid string
(#1902)
3f69440a is described below
commit 3f69440a7e8b62667ccb0820086c91364f263131
Author: T1B0 <[email protected]>
AuthorDate: Mon Jun 23 08:42:21 2025 +0200
feat(js): return message id as bigint instead of uuid string (#1902)
return polled messages id as Bigint instead of uuid string
---
foreign/node/src/bdd/message.ts | 11 +++++++----
foreign/node/src/tcp.sm.utils.ts | 17 +++++++++++++++--
foreign/node/src/wire/message/iggy-header.utils.ts | 10 +++++++---
foreign/node/src/wire/message/message.utils.ts | 19 +++++--------------
.../src/wire/message/send-messages.command.test.ts | 20 ++++++++++++++------
foreign/node/src/wire/number.utils.ts | 14 ++++++++++++--
6 files changed, 60 insertions(+), 31 deletions(-)
diff --git a/foreign/node/src/bdd/message.ts b/foreign/node/src/bdd/message.ts
index 892e8b52..f26d1c00 100644
--- a/foreign/node/src/bdd/message.ts
+++ b/foreign/node/src/bdd/message.ts
@@ -88,8 +88,8 @@ Then(
Then(
'the messages should have sequential offsets from {int} to {int}',
- function (this: TestWorld,from: number, to: number) {
- for(let i = from; i < to; i++) {
+ function (this: TestWorld, from: number, to: number) {
+ for (let i = from; i < to; i++) {
assert.equal(BigInt(i), this.polledMessages[i].headers.offset)
}
}
@@ -100,8 +100,10 @@ Then(
function (this: TestWorld) {
this.sendMessages.forEach((msg, i) => {
assert.deepEqual(msg.payload.toString(),
this.polledMessages[i].payload.toString());
+ assert.equal(BigInt(msg.id || 0), this.polledMessages[i].headers.id)
})
-});
+ }
+);
Then(
'the last polled message should match the last sent message',
@@ -110,4 +112,5 @@ Then(
const lastPoll = this.polledMessages[this.polledMessages.length - 1];
assert.deepEqual(lastSent.payload.toString(), lastPoll.payload.toString());
assert.deepEqual(lastSent.headers || {}, lastPoll.userHeaders);
-});
+ }
+);
diff --git a/foreign/node/src/tcp.sm.utils.ts b/foreign/node/src/tcp.sm.utils.ts
index 7eefb842..c68eda45 100644
--- a/foreign/node/src/tcp.sm.utils.ts
+++ b/foreign/node/src/tcp.sm.utils.ts
@@ -20,7 +20,7 @@
import assert from 'node:assert/strict';
import { v7 } from './wire/uuid.utils.js';
-import { sendMessages, type Partitioning, HeaderValue } from './wire/index.js';
+import { sendMessages, type Partitioning, HeaderValue, type Message } from
'./wire/index.js';
import type { ClientProvider } from './client/client.type.js';
import type { Id } from './wire/identifier.utils.js';
@@ -48,7 +48,6 @@ export const generateMessages = (count = 1) => {
return [...Array(count)].map(() => ({ id: v7(), ...someMessageContent() }));
}
-
export const sendSomeMessages = (s: ClientProvider) =>
async (streamId: Id, topicId: Id, partition: Partitioning) => {
const rSend = await sendMessages(s)({
@@ -57,3 +56,17 @@ export const sendSomeMessages = (s: ClientProvider) =>
assert.ok(rSend);
return rSend;
};
+
+
+export const formatPolledMessages = (msgs: Message[]) =>
+ msgs.map(m => {
+ const { headers: { id, offset, timestamp, checksum }, payload, userHeaders
} = m;
+ return {
+ id,
+ offset,
+ headers: userHeaders,
+ payload: payload.toString(),
+ timestamp,
+ checksum
+ };
+ });
diff --git a/foreign/node/src/wire/message/iggy-header.utils.ts
b/foreign/node/src/wire/message/iggy-header.utils.ts
index 2f43e8e2..e5f3335e 100644
--- a/foreign/node/src/wire/message/iggy-header.utils.ts
+++ b/foreign/node/src/wire/message/iggy-header.utils.ts
@@ -17,11 +17,13 @@
* under the License.
*/
-import { deserializeUUID, toDate } from "../serialize.utils.js";
+import { toDate } from "../serialize.utils.js";
+import { u128LEBufToBigint } from "../number.utils.js";
+
export type IggyMessageHeader = {
checksum: bigint,
- id: string | 0 | 0n,
+ id: string | BigInt,
offset: bigint,
timestamp: Date,
originTimestamp: Date,
@@ -48,6 +50,8 @@ export const serializeIggyMessageHeader = (
return b;
};
+export const deserialiseMessageId = (b: Buffer) => u128LEBufToBigint(b);
+
export const deserializeIggyMessageHeaders = (b: Buffer) => {
if(b.length !== IGGY_MESSAGE_HEADER_SIZE)
throw new Error(
@@ -56,7 +60,7 @@ export const deserializeIggyMessageHeaders = (b: Buffer) => {
);
const headers: IggyMessageHeader = {
checksum: b.readBigUInt64LE(0),
- id: deserializeUUID(b.subarray(8, 24)),
+ id: deserialiseMessageId(b.subarray(8, 24)),
offset: b.readBigUInt64LE(24),
timestamp: toDate(b.readBigUInt64LE(32)),
originTimestamp: toDate(b.readBigUInt64LE(40)),
diff --git a/foreign/node/src/wire/message/message.utils.ts
b/foreign/node/src/wire/message/message.utils.ts
index 71382246..d2e4da6a 100644
--- a/foreign/node/src/wire/message/message.utils.ts
+++ b/foreign/node/src/wire/message/message.utils.ts
@@ -19,7 +19,7 @@
import Debug from 'debug';
-import { uint32ToBuf } from '../number.utils.js';
+import { uint32ToBuf, u128ToBuf } from '../number.utils.js';
import { serializeHeaders, type Headers } from './header.utils.js';
import { serializeIdentifier, type Id } from '../identifier.utils.js';
import { serializePartitioning, type Partitioning } from
'./partitioning.utils.js';
@@ -31,7 +31,7 @@ const debug = Debug('iggy:client');
/** index size per messages in bit */
const INDEX_SIZE = 16;
-export type MessageIdKind = 0 | 0n | number | bigint | string;
+export type MessageIdKind = number | bigint | string;
export type CreateMessage = {
id?: MessageIdKind,
@@ -40,7 +40,7 @@ export type CreateMessage = {
};
export const isValidMessageId = (x?: unknown): x is MessageIdKind =>
- x === undefined || x === 0 || x === 0n ||
+ x === undefined ||
'string' === typeof x ||
'bigint' === typeof x ||
'number' === typeof x;
@@ -57,17 +57,8 @@ export const serializeMessageId = (id?: unknown) => {
if (id < 0)
throw new Error(`invalid message id: '${id}' (numeric id must be >= 0)`)
- if ('number' === typeof id) {
- const b = Buffer.alloc(16, 0);
- b.writeUInt32LE(id)
- return b; // id_u32 + 0u96
- }
-
- if ('bigint' === typeof id) {
- const b = Buffer.alloc(16, 0);
- b.writeBigUInt64LE(id)
- return b; // id_u64 + 0u64
- }
+ const idValue = 'number' === typeof id ? BigInt(id) : id;
+ return u128ToBuf(idValue);
}
try {
diff --git a/foreign/node/src/wire/message/send-messages.command.test.ts
b/foreign/node/src/wire/message/send-messages.command.test.ts
index 46329b63..e4945b65 100644
--- a/foreign/node/src/wire/message/send-messages.command.test.ts
+++ b/foreign/node/src/wire/message/send-messages.command.test.ts
@@ -22,7 +22,6 @@ import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { uuidv7, uuidv4 } from 'uuidv7'
import { SEND_MESSAGES, type SendMessages } from './send-messages.command.js';
-import type { MessageIdKind } from './message.utils.js';
import { HeaderValue } from './header.utils.js';
describe('SendMessages', () => {
@@ -34,8 +33,10 @@ describe('SendMessages', () => {
topicId: 213,
messages: [
{ payload: 'a' },
- { id: 0 as const, payload: 'b' },
- { id: 0n as const, payload: 'c' },
+ { id: 0, payload: 'b' },
+ { id: 123, payload: 'X' },
+ { id: 0n, payload: 'c' },
+ { id: 1236234534554n, payload: 'X' },
{ id: uuidv4(), payload: 'd' },
{ id: uuidv7(), payload: 'e' },
],
@@ -44,7 +45,7 @@ describe('SendMessages', () => {
it('serialize SendMessages into a buffer', () => {
assert.deepEqual(
SEND_MESSAGES.serialize(t1).length,
- 387
+ 533
);
});
@@ -56,14 +57,21 @@ describe('SendMessages', () => {
it('does not throw on number message id', () => {
- const t = { ...t1, messages: [{ id: 42 as MessageIdKind, payload: 'm' }]
};
+ const t = { ...t1, messages: [{ id: 42, payload: 'm' }] };
assert.doesNotThrow(
() => SEND_MESSAGES.serialize(t)
);
});
it('does not throw on bigint message id', () => {
- const t = { ...t1, messages: [{ id: 123n as MessageIdKind, payload: 'm'
}] };
+ const t = { ...t1, messages: [{ id: 123n, payload: 'm' }] };
+ assert.doesNotThrow(
+ () => SEND_MESSAGES.serialize(t)
+ );
+ });
+
+ it('does not throw on uuid message id', () => {
+ const t = { ...t1, messages: [{ id: uuidv4(), payload: 'uuid' }] };
assert.doesNotThrow(
() => SEND_MESSAGES.serialize(t)
);
diff --git a/foreign/node/src/wire/number.utils.ts
b/foreign/node/src/wire/number.utils.ts
index ad390b71..7ab9d790 100644
--- a/foreign/node/src/wire/number.utils.ts
+++ b/foreign/node/src/wire/number.utils.ts
@@ -84,6 +84,16 @@ export const doubleToBuf = (v: number) => {
return b;
}
+// bigint => u128 LE
+export function u128ToBuf(num: bigint, width = 16): Buffer {
+ const hex = num.toString(16);
+ const b = Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2),
'hex');
+ return b.reverse();
+}
+
+// u128 LE => Bigint
+export function u128LEBufToBigint(b: Buffer): bigint {
+ const hex = b.reverse().toString('hex');
+ return hex.length === 0 ? BigInt(0) : BigInt(`0x${hex}`);
+}
-// no js support ... use buffer or dataview or arraybuffer ?
-// const uint128ToBuf = (v: Buffer) => { }