Skip to content

Commit dc3d45a

Browse files
authored
chore(zero-cache): Make RowID immutable (rocicorp#2015)
and cache the hash value in a WeakMap.
1 parent c1904f4 commit dc3d45a

File tree

1 file changed

+16
-5
lines changed

1 file changed

+16
-5
lines changed

packages/zero-cache/src/types/row-key.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import type postgres from 'postgres';
22
import {stringify, type JSONValue} from './bigint-json.js';
33
import {h64} from './xxhash.js';
44

5-
export type ColumnType = {typeOid: number};
6-
export type RowKeyType = Record<string, ColumnType>;
7-
export type RowKey = Record<string, postgres.SerializableParameter<JSONValue>>;
5+
export type ColumnType = {readonly typeOid: number};
6+
export type RowKeyType = Readonly<Record<string, ColumnType>>;
7+
export type RowKey = Readonly<
8+
Record<string, postgres.SerializableParameter<JSONValue>>
9+
>;
810

9-
export type RowID = {schema: string; table: string; rowKey: RowKey};
11+
export type RowID = Readonly<{schema: string; table: string; rowKey: RowKey}>;
1012

1113
// Aliased for documentation purposes when dealing with full rows vs row keys.
1214
// The actual structure of the objects is the same.
@@ -27,6 +29,8 @@ function tuples(key: RowKey) {
2729
.flat();
2830
}
2931

32+
const rowIDHashes = new WeakMap<RowID, string>();
33+
3034
/**
3135
* A RowIDHash is a 128-bit column-order-agnostic hash of the schema, table name, and
3236
* column name / value tuples of a row key. It serves as a compact identifier for
@@ -40,14 +44,21 @@ function tuples(key: RowKey) {
4044
* The hash is encoded in `base36`, with the maximum 128-bit value being 25 characters long.
4145
*/
4246
export function rowIDHash(id: RowID): string {
47+
let hash = rowIDHashes.get(id);
48+
if (hash) {
49+
return hash;
50+
}
51+
4352
const str = stringify([id.schema, id.table, ...tuples(id.rowKey)]);
4453

4554
// xxhash only computes 64-bit values. Run it on the forward and reverse string
4655
// to get better collision resistance.
4756
const forward = h64(str);
4857
const backward = h64(reverse(str));
4958
const full = (forward << 64n) + backward;
50-
return full.toString(36);
59+
hash = full.toString(36);
60+
rowIDHashes.set(id, hash);
61+
return hash;
5162
}
5263

5364
function reverse(str: string): string {

0 commit comments

Comments
 (0)