lakeql 0.1.7 → 0.1.8

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/dist/node.js CHANGED
@@ -1,10 +1,110 @@
1
- export { IcebergRestCatalog, IcebergTable, IcebergUnsupportedCatalog, InMemoryRowsScanner, InMemoryRowsStore, ObjectStoreIcebergCommitCatalog, PACKAGE, applyIcebergDeletes, createInMemoryLake, icebergGlueCatalog, icebergNessieCatalog, icebergRestCatalog, inMemoryRowsScanner, loadIcebergTable, loadIcebergTableFromObjectStore, loadIcebergTableFromRest, loadTable, planFiles, scanBatches, scanPlannedIcebergRows, scanRows, vectorHashJoin } from './chunk-BFLGC6Y5.js';
2
- export { AggregationBuilder, CacheApiCache, Lake, MemoryCache, MemoryCheckpointAdapter, MemoryObjectStore, MemorySpillAdapter, ParquetScanAdapter, QueryBuilder, QueryResult, ResumedQuery, SharedMemoryCache, add, advanceTaskCheckpoint, aggregateParquetGroupTask, aggregateParquetGroupTasks, aggregateParquetGroupTasksBatch, aggregateParquetTask, aggregateParquetTasks, and, assertBookmarkMatches, asyncBufferFromStore, batchExprValues, batchFromColumns, batchFromVectors, bboxMayIntersect, between, broadcastJoin, buildBBoxIndex, buildMinMaxIndex, cacheApiCache, cachedObjectStore, classifyPredicate, col, concatBatches, createBookmark, createParquetLake as createLake, createOutputManifest, createOutputManifestFromCheckpoints, createParquetLake, createParquetTableAs, createTaskManifest, createVectorAggregateStates, createVectorGroupByState, deserializeAggregateOperatorState, deserializeSortOperatorState, deserializeTopKOperatorState, div, enforceVectorGroupByBudget, eq, fanInWorkUnits, finalizeVectorAggregateStates, finalizeVectorGroupByBatch, finalizeVectorGroupByRows, fingerprint, fn, gatherBatch, getOrCreateVectorGroup, gt, gte, ilike, isIn, isNotNull, isNull, jsonWorkUnitBoundary, like, lit, lookupJoin, lt, lte, materializeBatchRows, materializeSelectedBatchRows, memoryCache, memoryCheckpointAdapter, memorySpillAdapter, memoryStore, mergeVectorAggregateStateSnapshots, mergeVectorAggregateStates, mergeVectorGroupByStates, mod, mul, ne, not, notIn, or, parquetScanner, parseHivePartitions, parseJsonQuery, partitionedParquetOutputEntries, planParquetTaskWorkUnits, planRowGroups, planRowGroupsFromMetadata, predicateSelection, pruneFilesWithIndex, readControlSignal, readIcebergParquetDeletes, readOutputManifest, readParquetColumnBatches, readParquetMetadata, readParquetObjectBatches, readParquetObjects, rejectUnsupportedParquetSchema, restoreVectorAggregateStates, restoreVectorGroupByState, rowGroupMayMatch, rowGroupMustMatch, scalarVectorValue, scanParquetTaskBatches, scanParquetTaskColumnBatches, selectedRowCount, selectedRowIndices, serializeAggregateOperatorState, serializeSortOperatorState, serializeTopKOperatorState, signPaginationToken, snapshotVectorAggregateStates, snapshotVectorGroupByState, stableStringify, sub, throwIfAborted, transitionTaskCheckpoint, tryPredicateSelection, updateVectorAggregateStateValue, updateVectorAggregateStates, updateVectorGroupAggregateValue, updateVectorGroupByState, vectorAggregateBatch, vectorFromValues, vectorGroupByBatch, vectorLength, vectorOrderByBatch, vectorProjectBatch, vectorSortIndices, vectorTopKBatch, vectorTopKIndices, vectorValue, verifyPaginationToken, withObjectStoreReadControls, writeOutputManifest, writeParquet, writePartitionedParquet, writePartitionedParquetTask } from './chunk-RZL45ZSN.js';
1
+ import { objectStoreJsonCache } from './chunk-5K5JMJ2M.js';
2
+ export { IcebergRestCatalog, IcebergTable, IcebergUnsupportedCatalog, InMemoryRowsScanner, InMemoryRowsStore, ObjectStoreIcebergCommitCatalog, ObjectStoreJsonCache, PACKAGE, applyIcebergDeletes, createInMemoryLake, icebergGlueCatalog, icebergNessieCatalog, icebergRestCatalog, inMemoryRowsScanner, loadIcebergTable, loadIcebergTableFromObjectStore, loadIcebergTableFromRest, loadTable, objectStoreJsonCache, planFiles, scanBatches, scanPlannedIcebergRows, scanRows, vectorHashJoin } from './chunk-5K5JMJ2M.js';
3
+ export { AggregationBuilder, CacheApiCache, Lake, MemoryCache, MemoryCheckpointAdapter, MemoryObjectStore, MemorySpillAdapter, ParquetScanAdapter, QueryBuilder, QueryResult, ResumedQuery, SharedMemoryCache, add, advanceTaskCheckpoint, aggregateParquetGroupTask, aggregateParquetGroupTasks, aggregateParquetGroupTasksBatch, aggregateParquetTask, aggregateParquetTasks, and, assertBookmarkMatches, asyncBufferFromStore, batchExprValues, batchFromColumns, batchFromVectors, bboxMayIntersect, between, broadcastJoin, buildBBoxIndex, buildMinMaxIndex, cacheApiCache, cachedObjectStore, classifyPredicate, col, concatBatches, createBookmark, createParquetLake as createLake, createOutputManifest, createOutputManifestFromCheckpoints, createParquetLake, createParquetTableAs, createTaskManifest, createVectorAggregateStates, createVectorGroupByState, deserializeAggregateOperatorState, deserializeSortOperatorState, deserializeTopKOperatorState, div, enforceVectorGroupByBudget, eq, fanInWorkUnits, finalizeVectorAggregateStates, finalizeVectorGroupByBatch, finalizeVectorGroupByRows, fingerprint, fn, gatherBatch, getOrCreateVectorGroup, gt, gte, ilike, isIn, isNotNull, isNull, jsonWorkUnitBoundary, like, lit, lookupJoin, lt, lte, materializeBatchRows, materializeSelectedBatchRows, memoryCache, memoryCheckpointAdapter, memorySpillAdapter, memoryStore, mergeVectorAggregateStateSnapshots, mergeVectorAggregateStates, mergeVectorGroupByStates, mod, mul, ne, not, notIn, or, parquetScanner, parseHivePartitions, parseJsonQuery, partitionedParquetOutputEntries, planParquetTaskWorkUnits, planRowGroups, planRowGroupsFromMetadata, predicateSelection, pruneFilesWithIndex, readControlSignal, readIcebergParquetDeletes, readOutputManifest, readParquetColumnBatches, readParquetMetadata, readParquetObjectBatches, readParquetObjects, rejectUnsupportedParquetSchema, restoreVectorAggregateStates, restoreVectorGroupByState, rowGroupMayMatch, rowGroupMustMatch, scalarVectorValue, scanParquetTaskBatches, scanParquetTaskColumnBatches, selectedRowCount, selectedRowIndices, serializeAggregateOperatorState, serializeSortOperatorState, serializeTopKOperatorState, signPaginationToken, snapshotVectorAggregateStates, snapshotVectorGroupByState, stableStringify, sub, throwIfAborted, transitionTaskCheckpoint, tryPredicateSelection, updateVectorAggregateStateValue, updateVectorAggregateStates, updateVectorGroupAggregateValue, updateVectorGroupByState, uriObjectStore, vectorAggregateBatch, vectorFromValues, vectorGroupByBatch, vectorLength, vectorOrderByBatch, vectorProjectBatch, vectorSortIndices, vectorTopKBatch, vectorTopKIndices, vectorValue, verifyPaginationToken, withObjectStoreReadControls, writeOutputManifest, writeParquet, writePartitionedParquet, writePartitionedParquetTask } from './chunk-MXGEAVHL.js';
3
4
  import { LakeqlError } from './chunk-TFD5RFKB.js';
4
5
  export { ERROR_CODES, LakeqlError, TimestampValue, bboxIntersects, compareTimestampValues, encodeJsonLine, ensureGeoBackendForExprs, envelopeFromGeometry, envelopeOf, evaluate, isLakeqlError, isTimestampValue, jsonSafeValue, loadGeoBackend, matches, parseGeometry, requireGeoBackend, setGeoBackend, timestampEpochForUnit, timestampFromEpoch, timestampToIsoString, timestampValueFromIso, toGeometry } from './chunk-TFD5RFKB.js';
6
+ import { readFile, mkdir, writeFile, rm } from 'fs/promises';
7
+ import { join } from 'path';
5
8
  import { AwsClient } from 'aws4fetch';
6
9
  import { XMLParser } from 'fast-xml-parser';
7
10
 
11
+ function fsJsonCache(options) {
12
+ return new FsJsonCache(options);
13
+ }
14
+ var FsJsonCache = class {
15
+ root;
16
+ prefix;
17
+ ttlMs;
18
+ now;
19
+ space;
20
+ constructor(options) {
21
+ this.root = options.root;
22
+ this.prefix = normalizedPrefix(options.prefix ?? "lakeql");
23
+ this.ttlMs = options.ttlMs;
24
+ this.now = options.now ?? Date.now;
25
+ this.space = options.space;
26
+ }
27
+ async get(key) {
28
+ const path = this.pathFor(key);
29
+ let bytes;
30
+ try {
31
+ bytes = await readFile(path);
32
+ } catch (cause) {
33
+ if (isNodeError(cause) && cause.code === "ENOENT")
34
+ return void 0;
35
+ throw cause;
36
+ }
37
+ const parsed = JSON.parse(bytes.toString("utf8"));
38
+ if (!isStoredFsJsonCacheEntry(parsed)) {
39
+ throw new LakeqlError("LAKEQL_CATALOG_ERROR", `Invalid filesystem cache entry at ${path}`, {
40
+ path
41
+ });
42
+ }
43
+ if (parsed.expiresAt !== void 0 && parsed.expiresAt <= this.now()) {
44
+ await this.delete(key);
45
+ return void 0;
46
+ }
47
+ const entry = { value: parsed.value };
48
+ if (parsed.expiresAt !== void 0)
49
+ entry.expiresAt = parsed.expiresAt;
50
+ return entry;
51
+ }
52
+ async set(key, entry) {
53
+ const path = this.pathFor(key);
54
+ await mkdir(join(this.root, this.prefix), { recursive: true });
55
+ const stored = { value: entry.value };
56
+ if (entry.expiresAt !== void 0) {
57
+ stored.expiresAt = entry.expiresAt;
58
+ } else if (this.ttlMs !== void 0) {
59
+ stored.expiresAt = this.now() + this.ttlMs;
60
+ }
61
+ await writeFile(path, jsonCacheValue(stored, key, this.space));
62
+ }
63
+ async delete(key) {
64
+ await rm(this.pathFor(key), { force: true });
65
+ }
66
+ pathFor(key) {
67
+ if (key.length === 0) {
68
+ throw new LakeqlError("LAKEQL_VALIDATION_ERROR", "filesystem cache key must not be empty");
69
+ }
70
+ return join(this.root, this.prefix, `${encodeURIComponent(key)}.json`);
71
+ }
72
+ };
73
+ function normalizedPrefix(prefix) {
74
+ const parts = prefix.split("/").filter((part) => part.length > 0);
75
+ if (parts.length === 0 || parts.some((part) => part === "." || part === "..")) {
76
+ throw new LakeqlError("LAKEQL_VALIDATION_ERROR", "filesystem cache prefix must be relative", {
77
+ prefix
78
+ });
79
+ }
80
+ return parts.join("/");
81
+ }
82
+ function isStoredFsJsonCacheEntry(value) {
83
+ return typeof value === "object" && value !== null && "value" in value;
84
+ }
85
+ function jsonCacheValue(value, key, space) {
86
+ if (value.value === void 0) {
87
+ throw new LakeqlError("LAKEQL_TYPE_ERROR", "filesystem JSON cache value is not JSON serializable", { key });
88
+ }
89
+ try {
90
+ const json = JSON.stringify(value, void 0, space);
91
+ if (json === void 0) {
92
+ throw new LakeqlError("LAKEQL_TYPE_ERROR", "filesystem JSON cache value is not JSON serializable", { key });
93
+ }
94
+ return json;
95
+ } catch (cause) {
96
+ if (cause instanceof LakeqlError)
97
+ throw cause;
98
+ throw new LakeqlError("LAKEQL_TYPE_ERROR", "filesystem JSON cache value is not JSON serializable", {
99
+ key,
100
+ cause
101
+ });
102
+ }
103
+ }
104
+ function isNodeError(value) {
105
+ return value instanceof Error && "code" in value;
106
+ }
107
+
8
108
  // ../http/dist/index.js
9
109
  function httpStore(options) {
10
110
  return new HttpObjectStore(options);
@@ -173,25 +273,26 @@ function bodyInit(body) {
173
273
  function s3Store(options) {
174
274
  return new S3ObjectStore(options);
175
275
  }
276
+ function s3JsonCache(options) {
277
+ return objectStoreJsonCache({
278
+ store: s3Store(options),
279
+ prefix: options.prefix,
280
+ ...options.ttlMs !== void 0 ? { ttlMs: options.ttlMs } : {}
281
+ });
282
+ }
176
283
  var S3ObjectStore = class {
177
284
  options;
178
285
  fetchImpl;
179
286
  now;
180
- aws;
287
+ credentialsSnapshot;
288
+ credentialsPromise;
181
289
  constructor(options) {
182
290
  this.options = options;
183
291
  this.fetchImpl = options.fetch ?? fetch;
184
292
  this.now = options.now ?? (() => /* @__PURE__ */ new Date());
185
- const awsOptions = {
186
- accessKeyId: options.accessKeyId,
187
- secretAccessKey: options.secretAccessKey,
188
- region: options.region,
189
- service: "s3",
190
- retries: 0
191
- };
192
- if (options.sessionToken !== void 0)
193
- awsOptions.sessionToken = options.sessionToken;
194
- this.aws = new AwsClient(awsOptions);
293
+ if (options.credentials === void 0) {
294
+ this.credentialsSnapshot = staticCredentials(options);
295
+ }
195
296
  }
196
297
  async get(path) {
197
298
  const response = await this.request("GET", path);
@@ -286,19 +387,41 @@ var S3ObjectStore = class {
286
387
  url,
287
388
  headers,
288
389
  region: this.options.region,
289
- accessKeyId: this.options.accessKeyId,
290
- secretAccessKey: this.options.secretAccessKey,
390
+ ...await this.currentCredentials(),
291
391
  now: this.now()
292
392
  };
293
- if (this.options.sessionToken !== void 0)
294
- signRequest.sessionToken = this.options.sessionToken;
295
393
  const requestBody = body === void 0 ? void 0 : bodyInit2(body);
296
- const signed = await signS3Request(signRequest, this.aws, requestBody);
394
+ const signed = await signS3Request(signRequest, void 0, requestBody);
297
395
  const init = { method, headers: signed };
298
396
  if (requestBody !== void 0)
299
397
  init.body = requestBody;
300
398
  return this.fetchImpl(url, init);
301
399
  }
400
+ async currentCredentials() {
401
+ if (this.options.credentials === void 0) {
402
+ if (this.credentialsSnapshot === void 0)
403
+ this.credentialsSnapshot = staticCredentials(this.options);
404
+ return this.credentialsSnapshot;
405
+ }
406
+ if (this.credentialsSnapshot !== void 0 && !credentialsNeedRefresh(this.credentialsSnapshot, this.now(), this.credentialRefreshWindowMs())) {
407
+ return this.credentialsSnapshot;
408
+ }
409
+ if (this.credentialsPromise === void 0) {
410
+ this.credentialsPromise = Promise.resolve(this.options.credentials()).then((credentials) => {
411
+ const normalized = validateCredentials(credentials);
412
+ this.credentialsSnapshot = normalized;
413
+ this.credentialsPromise = void 0;
414
+ return normalized;
415
+ }).catch((cause) => {
416
+ this.credentialsPromise = void 0;
417
+ throw cause;
418
+ });
419
+ }
420
+ return await this.credentialsPromise;
421
+ }
422
+ credentialRefreshWindowMs() {
423
+ return this.options.credentialRefreshWindowMs ?? 3e5;
424
+ }
302
425
  };
303
426
  async function signS3Request(request, client = s3SignerClient(request), body) {
304
427
  const headers = new Headers(request.headers);
@@ -329,6 +452,39 @@ function s3SignerClient(request) {
329
452
  options.sessionToken = request.sessionToken;
330
453
  return new AwsClient(options);
331
454
  }
455
+ function staticCredentials(options) {
456
+ if (options.accessKeyId === void 0 || options.secretAccessKey === void 0) {
457
+ throw new LakeqlError("LAKEQL_VALIDATION_ERROR", "S3 credentials are required", {
458
+ bucket: options.bucket
459
+ });
460
+ }
461
+ return validateCredentials({
462
+ accessKeyId: options.accessKeyId,
463
+ secretAccessKey: options.secretAccessKey,
464
+ ...options.sessionToken !== void 0 ? { sessionToken: options.sessionToken } : {}
465
+ });
466
+ }
467
+ function validateCredentials(credentials) {
468
+ const accessKeyId = credentials.accessKeyId.trim();
469
+ const secretAccessKey = credentials.secretAccessKey.trim();
470
+ if (accessKeyId === "" || secretAccessKey === "") {
471
+ throw new LakeqlError("LAKEQL_VALIDATION_ERROR", "S3 credentials are required");
472
+ }
473
+ const normalized = {
474
+ accessKeyId,
475
+ secretAccessKey
476
+ };
477
+ if (credentials.sessionToken !== void 0)
478
+ normalized.sessionToken = credentials.sessionToken;
479
+ if (credentials.expiresAt !== void 0)
480
+ normalized.expiresAt = credentials.expiresAt;
481
+ return normalized;
482
+ }
483
+ function credentialsNeedRefresh(credentials, now, refreshWindowMs) {
484
+ if (credentials.expiresAt === void 0)
485
+ return false;
486
+ return credentials.expiresAt.getTime() - now.getTime() <= refreshWindowMs;
487
+ }
332
488
  var listObjectsParser = new XMLParser({
333
489
  ignoreAttributes: true,
334
490
  parseTagValue: false,
@@ -424,4 +580,4 @@ function arrayBuffer(bytes) {
424
580
  return copy.buffer;
425
581
  }
426
582
 
427
- export { httpStore, s3Store };
583
+ export { fsJsonCache, httpStore, s3JsonCache, s3Store };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lakeql",
3
3
  "sideEffects": false,
4
- "version": "0.1.7",
4
+ "version": "0.1.8",
5
5
  "description": "lakeql: lightweight TypeScript query engine for Iceberg + Parquet on object storage",
6
6
  "keywords": [
7
7
  "lakehouse",
@@ -55,6 +55,7 @@
55
55
  "avsc": "^5.7.9",
56
56
  "aws4fetch": "^1.0.20",
57
57
  "fast-xml-parser": "^5.9.0",
58
+ "fzstd": "^0.1.1",
58
59
  "h3-js": "^4.4.0",
59
60
  "hyparquet": "^1.26.0",
60
61
  "hyparquet-writer": "^0.15.6"
@@ -62,13 +63,14 @@
62
63
  "devDependencies": {
63
64
  "tsup": "^8.5.0",
64
65
  "lakeql-fixtures": "0.0.1",
65
- "lakeql-core": "0.1.2",
66
- "lakeql-http": "0.0.4",
67
- "lakeql-iceberg": "0.0.4",
68
- "lakeql-parquet": "0.0.4",
69
- "lakeql-r2": "0.0.4",
70
- "lakeql-s3": "0.0.4",
71
- "lakeql-sql": "0.0.4"
66
+ "lakeql-core": "0.1.3",
67
+ "lakeql-fs": "0.0.2",
68
+ "lakeql-iceberg": "0.0.5",
69
+ "lakeql-parquet": "0.0.5",
70
+ "lakeql-http": "0.0.5",
71
+ "lakeql-r2": "0.0.5",
72
+ "lakeql-s3": "0.0.5",
73
+ "lakeql-sql": "0.0.5"
72
74
  },
73
75
  "scripts": {
74
76
  "build": "tsup"