Skip to content

Commit d684c2a

Browse files
committed
wip: withConsolidated helper
1 parent f2cc822 commit d684c2a

File tree

1 file changed

+82
-53
lines changed

1 file changed

+82
-53
lines changed

packages/core/src/consolidated.ts

+82-53
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
1-
import type { AbsolutePath, Readable } from "@zarrita/storage";
1+
import { FetchStore, type AbsolutePath, type Readable } from "@zarrita/storage";
22

3-
import { Array, Group, Location } from "./hierarchy.js";
3+
import { Array, Group } from "./hierarchy.js";
44
import {
55
json_decode_object,
6+
json_encode_object,
67
v2_to_v3_array_metadata,
78
v2_to_v3_group_metadata,
89
} from "./util.js";
9-
import type { ArrayMetadataV2, DataType, GroupMetadataV2 } from "./metadata.js";
10-
import { NodeNotFoundError } from "./errors.js";
10+
import type {
11+
ArrayMetadata,
12+
ArrayMetadataV2,
13+
GroupMetadata,
14+
GroupMetadataV2,
15+
Attributes,
16+
} from "./metadata.js";
1117

1218
type ConsolidatedMetadata = {
13-
metadata: Record<string, any>;
19+
metadata: Record<string, ArrayMetadataV2 | GroupMetadataV2>;
1420
zarr_consolidated_format: 1;
1521
};
1622

23+
type Listable<Store extends Readable> = {
24+
get(...args: Parameters<Store["get"]>): Promise<Uint8Array | undefined>;
25+
contents(): { path: AbsolutePath; kind: "array" | "group" }[];
26+
};
27+
1728
async function get_consolidated_metadata(
1829
store: Readable,
1930
): Promise<ConsolidatedMetadata> {
@@ -26,13 +37,72 @@ async function get_consolidated_metadata(
2637
return meta;
2738
}
2839

29-
/** Proxies requests to the underlying store. */
30-
export async function openConsolidated<Store extends Readable>(
40+
type Metadata =
41+
| ArrayMetadataV2
42+
| GroupMetadataV2
43+
| ArrayMetadata
44+
| GroupMetadata
45+
| Attributes;
46+
47+
function is_meta_key(key: string): boolean {
48+
return (
49+
key.endsWith(".zarray") ||
50+
key.endsWith(".zgroup") ||
51+
key.endsWith(".zattrs") ||
52+
key.endsWith("zarr.json")
53+
);
54+
}
55+
56+
function is_v3(meta: Metadata): meta is ArrayMetadata | GroupMetadata {
57+
return "zarr_format" in meta && meta.zarr_format === 3;
58+
}
59+
60+
async function withConsolidated<Store extends Readable>(
3161
store: Store,
32-
) {
33-
let { metadata } = await get_consolidated_metadata(store);
34-
let meta_nodes = Object
35-
.entries(metadata)
62+
): Promise<Listable<Store>> {
63+
let known_meta: Record<AbsolutePath, Metadata> =
64+
await get_consolidated_metadata(store)
65+
.then((meta) => {
66+
let new_meta: Record<AbsolutePath, Metadata> = {};
67+
for (let [key, value] of Object.entries(meta.metadata)) {
68+
new_meta[`/${key}`] = value;
69+
}
70+
return new_meta;
71+
})
72+
.catch(() => ({}));
73+
74+
return {
75+
async get(...args: Parameters<Store["get"]>): Promise<Uint8Array | undefined> {
76+
let [key, opts] = args;
77+
if (known_meta[key]) {
78+
return json_encode_object(known_meta[key]);
79+
}
80+
let maybe_bytes = await store.get(key, opts);
81+
if (is_meta_key(key) && maybe_bytes) {
82+
let meta = json_decode_object(maybe_bytes);
83+
known_meta[key] = meta;
84+
}
85+
return maybe_bytes;
86+
},
87+
contents(): { path: AbsolutePath; kind: "array" | "group" }[] {
88+
let contents: { path: AbsolutePath, kind: "array" | "group" }[] = [];
89+
for (let [key, value] of Object.entries(known_meta)) {
90+
let path = key as AbsolutePath;
91+
if (key.endsWith(".zarray")) contents.push({ path, kind: "array" });
92+
if (key.endsWith(".zgroup")) contents.push({ path, kind: "group" });
93+
if (is_v3(value)) contents.push({ path, kind: value.node_type });
94+
}
95+
return contents;
96+
}
97+
};
98+
}
99+
100+
async function openListable<Store extends Readable>(store: Listable<Store>) {
101+
let metadata = await Promise.all(
102+
store.contents().map(({ path }) => [path, store.get(path)] as const)
103+
);
104+
105+
metadata
36106
.reduce(
37107
(acc, [path, content]) => {
38108
let parts = path.split("/");
@@ -56,47 +126,6 @@ export async function openConsolidated<Store extends Readable>(
56126
}
57127
>,
58128
);
59-
let nodes = new Map<AbsolutePath, Array<DataType, Store> | Group<Store>>();
60-
for (let [path, { meta, attrs }] of Object.entries(meta_nodes)) {
61-
if (!meta) throw new Error("missing metadata");
62-
let node: Array<DataType, Store> | Group<Store>;
63-
if ("shape" in meta) {
64-
let metadata = v2_to_v3_array_metadata(meta, attrs);
65-
node = new Array(store, path as AbsolutePath, metadata);
66-
} else {
67-
let metadata = v2_to_v3_group_metadata(meta, attrs);
68-
node = new Group(store, path as AbsolutePath, metadata);
69-
}
70-
nodes.set(path as AbsolutePath, node);
71-
}
72-
return new ConsolidatedHierarchy(nodes);
73-
}
74129

75-
class ConsolidatedHierarchy<Store extends Readable> {
76-
constructor(
77-
public contents: Map<AbsolutePath, Array<DataType, Store> | Group<Store>>,
78-
) {}
79-
open(
80-
where: AbsolutePath | Location<unknown>,
81-
options: { kind: "group" },
82-
): Group<Store>;
83-
open(
84-
where: AbsolutePath | Location<unknown>,
85-
options: { kind: "array" },
86-
): Array<DataType, Store>;
87-
open(
88-
where: AbsolutePath | Location<unknown>,
89-
): Array<DataType, Store> | Group<Store>;
90-
open(
91-
where: AbsolutePath | Location<unknown>,
92-
options: { kind?: "array" | "group" } = {},
93-
) {
94-
let path = typeof where === "string" ? where : where.path;
95-
let node = this.contents.get(path);
96-
if (node && (!options.kind || options.kind == node.kind)) return node;
97-
throw new NodeNotFoundError(path);
98-
}
99-
root() {
100-
return this.open("/", { kind: "group" });
101-
}
130+
102131
}

0 commit comments

Comments
 (0)