@walkthru-earth/objex-utils 1.0.0 → 1.2.0
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/README.md +99 -0
- package/dist/index.cjs +1224 -956
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +230 -7
- package/dist/index.d.ts +230 -7
- package/dist/index.js +1202 -957
- package/dist/index.js.map +1 -1
- package/docs/README.md +102 -0
- package/docs/cog.md +303 -0
- package/docs/errors.md +34 -0
- package/docs/file-sort.md +67 -0
- package/docs/file-types.md +141 -0
- package/docs/formatting.md +192 -0
- package/docs/geometry.md +198 -0
- package/docs/local-storage.md +51 -0
- package/docs/markdown-sql.md +109 -0
- package/docs/parquet-metadata.md +133 -0
- package/docs/query-engine.md +140 -0
- package/docs/storage.md +251 -0
- package/docs/types-constants.md +173 -0
- package/package.json +9 -3
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
require('@developmentseed/epsg/all');
|
|
4
|
+
require('@developmentseed/epsg/all.csv.gz?url');
|
|
5
|
+
require('@developmentseed/geotiff');
|
|
6
|
+
require('@developmentseed/proj');
|
|
7
|
+
require('proj4');
|
|
3
8
|
var apacheArrow = require('apache-arrow');
|
|
4
9
|
|
|
5
10
|
// ../../src/lib/constants.ts
|
|
@@ -9,7 +14,7 @@ var STORAGE_KEYS = {
|
|
|
9
14
|
QUERY_HISTORY: "obstore-explore-query-history"
|
|
10
15
|
};
|
|
11
16
|
var WGS84_CODES = /* @__PURE__ */ new Set([4326, 4979]);
|
|
12
|
-
var DEFAULT_TARGET_CRS = "
|
|
17
|
+
var DEFAULT_TARGET_CRS = "OGC:CRS84";
|
|
13
18
|
var DUCKDB_INIT_TIMEOUT_MS = 3e4;
|
|
14
19
|
var MAX_QUERY_HISTORY_ENTRIES = 200;
|
|
15
20
|
var SQL_PREVIEW_LENGTH = 120;
|
|
@@ -889,6 +894,16 @@ var EXTENSIONS = {
|
|
|
889
894
|
duckdbReadFn: null,
|
|
890
895
|
mimeType: "application/octet-stream"
|
|
891
896
|
},
|
|
897
|
+
".ducklake": {
|
|
898
|
+
icon: "Database",
|
|
899
|
+
color: "text-teal-600 dark:text-teal-400",
|
|
900
|
+
label: "DuckLake",
|
|
901
|
+
category: "database",
|
|
902
|
+
viewer: "database",
|
|
903
|
+
queryable: true,
|
|
904
|
+
duckdbReadFn: null,
|
|
905
|
+
mimeType: "application/octet-stream"
|
|
906
|
+
},
|
|
892
907
|
".sqlite": {
|
|
893
908
|
icon: "Database",
|
|
894
909
|
color: "text-sky-600 dark:text-sky-400",
|
|
@@ -1036,7 +1051,7 @@ function buildDuckDbSource(pathOrExt, url) {
|
|
|
1036
1051
|
const readFn = EXTENSIONS[ext]?.duckdbReadFn ?? "read_parquet";
|
|
1037
1052
|
return `${readFn}('${url}')`;
|
|
1038
1053
|
}
|
|
1039
|
-
var CLOUD_NATIVE_EXTS = /* @__PURE__ */ new Set([".parquet", ".geoparquet", ".gpq", ".gparquet"]);
|
|
1054
|
+
var CLOUD_NATIVE_EXTS = /* @__PURE__ */ new Set([".parquet", ".geoparquet", ".gpq", ".gparquet", ".ducklake"]);
|
|
1040
1055
|
function isCloudNativeFormat(pathOrExt) {
|
|
1041
1056
|
const ext = pathOrExt.includes(".") ? `.${pathOrExt.split(".").pop().toLowerCase()}` : "";
|
|
1042
1057
|
return CLOUD_NATIVE_EXTS.has(ext);
|
|
@@ -1059,959 +1074,6 @@ var QueryCancelledError = class extends Error {
|
|
|
1059
1074
|
}
|
|
1060
1075
|
};
|
|
1061
1076
|
|
|
1062
|
-
// ../../src/lib/storage/url-adapter.ts
|
|
1063
|
-
var UrlAdapter = class {
|
|
1064
|
-
supportsWrite = false;
|
|
1065
|
-
async read(url, offset, length, signal) {
|
|
1066
|
-
const headers = {};
|
|
1067
|
-
if (offset !== void 0 && length !== void 0) {
|
|
1068
|
-
headers.Range = `bytes=${offset}-${offset + length - 1}`;
|
|
1069
|
-
} else if (offset !== void 0) {
|
|
1070
|
-
headers.Range = `bytes=${offset}-`;
|
|
1071
|
-
}
|
|
1072
|
-
const res = await fetch(url, { headers, signal });
|
|
1073
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
1074
|
-
return new Uint8Array(await res.arrayBuffer());
|
|
1075
|
-
}
|
|
1076
|
-
async head(url, signal) {
|
|
1077
|
-
const res = await fetch(url, { method: "HEAD", signal });
|
|
1078
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
1079
|
-
const name = url.split("/").pop()?.split("?")[0] || "file";
|
|
1080
|
-
const ext = name.includes(".") ? name.split(".").pop().toLowerCase() : "";
|
|
1081
|
-
return {
|
|
1082
|
-
name,
|
|
1083
|
-
path: url,
|
|
1084
|
-
is_dir: false,
|
|
1085
|
-
size: Number(res.headers.get("content-length") || 0),
|
|
1086
|
-
modified: new Date(res.headers.get("last-modified") || 0).getTime(),
|
|
1087
|
-
extension: ext
|
|
1088
|
-
};
|
|
1089
|
-
}
|
|
1090
|
-
async list() {
|
|
1091
|
-
return [];
|
|
1092
|
-
}
|
|
1093
|
-
async put() {
|
|
1094
|
-
throw new Error("Write not supported for direct URL sources");
|
|
1095
|
-
}
|
|
1096
|
-
async delete() {
|
|
1097
|
-
throw new Error("Delete not supported for direct URL sources");
|
|
1098
|
-
}
|
|
1099
|
-
async deletePrefix() {
|
|
1100
|
-
throw new Error("Delete not supported for direct URL sources");
|
|
1101
|
-
}
|
|
1102
|
-
async copy() {
|
|
1103
|
-
throw new Error("Copy not supported for direct URL sources");
|
|
1104
|
-
}
|
|
1105
|
-
};
|
|
1106
|
-
|
|
1107
|
-
// ../../src/lib/utils/column-types.ts
|
|
1108
|
-
var NUMBER_TYPES = [
|
|
1109
|
-
"TINYINT",
|
|
1110
|
-
"SMALLINT",
|
|
1111
|
-
"INTEGER",
|
|
1112
|
-
"BIGINT",
|
|
1113
|
-
"HUGEINT",
|
|
1114
|
-
"UTINYINT",
|
|
1115
|
-
"USMALLINT",
|
|
1116
|
-
"UINTEGER",
|
|
1117
|
-
"UBIGINT",
|
|
1118
|
-
"FLOAT",
|
|
1119
|
-
"DOUBLE",
|
|
1120
|
-
"DECIMAL",
|
|
1121
|
-
"NUMERIC",
|
|
1122
|
-
"REAL",
|
|
1123
|
-
"INT",
|
|
1124
|
-
"INT1",
|
|
1125
|
-
"INT2",
|
|
1126
|
-
"INT4",
|
|
1127
|
-
"INT8",
|
|
1128
|
-
"SIGNED",
|
|
1129
|
-
"SHORT",
|
|
1130
|
-
"LONG"
|
|
1131
|
-
];
|
|
1132
|
-
var STRING_TYPES = ["VARCHAR", "TEXT", "STRING", "CHAR", "BPCHAR", "NAME", "UUID", "ENUM"];
|
|
1133
|
-
var DATE_TYPES = [
|
|
1134
|
-
"DATE",
|
|
1135
|
-
"TIME",
|
|
1136
|
-
"TIMESTAMP",
|
|
1137
|
-
"TIMESTAMP_S",
|
|
1138
|
-
"TIMESTAMP_MS",
|
|
1139
|
-
"TIMESTAMP_NS",
|
|
1140
|
-
"TIMESTAMP WITH TIME ZONE",
|
|
1141
|
-
"TIMESTAMPTZ",
|
|
1142
|
-
"INTERVAL",
|
|
1143
|
-
"TIMESTAMP_TZ"
|
|
1144
|
-
];
|
|
1145
|
-
var BOOLEAN_TYPES = ["BOOLEAN", "BOOL", "LOGICAL"];
|
|
1146
|
-
var GEO_TYPES = [
|
|
1147
|
-
"GEOMETRY",
|
|
1148
|
-
"POINT",
|
|
1149
|
-
"LINESTRING",
|
|
1150
|
-
"POLYGON",
|
|
1151
|
-
"MULTIPOINT",
|
|
1152
|
-
"MULTILINESTRING",
|
|
1153
|
-
"MULTIPOLYGON",
|
|
1154
|
-
"GEOMETRYCOLLECTION",
|
|
1155
|
-
"WKB_GEOMETRY"
|
|
1156
|
-
];
|
|
1157
|
-
var BINARY_TYPES = ["BLOB", "BYTEA", "BINARY", "VARBINARY"];
|
|
1158
|
-
var JSON_TYPES = ["JSON", "JSONB"];
|
|
1159
|
-
function classifyType(duckdbType) {
|
|
1160
|
-
const upper = duckdbType.toUpperCase().trim();
|
|
1161
|
-
const base = upper.replace(/\(.*\)/, "").trim();
|
|
1162
|
-
if (NUMBER_TYPES.includes(base)) return "number";
|
|
1163
|
-
if (STRING_TYPES.includes(base)) return "string";
|
|
1164
|
-
if (DATE_TYPES.includes(base)) return "date";
|
|
1165
|
-
if (BOOLEAN_TYPES.includes(base)) return "boolean";
|
|
1166
|
-
if (GEO_TYPES.includes(base)) return "geo";
|
|
1167
|
-
if (BINARY_TYPES.includes(base)) return "binary";
|
|
1168
|
-
if (JSON_TYPES.includes(base)) return "json";
|
|
1169
|
-
if (base.startsWith("STRUCT") || base.startsWith("MAP") || base.startsWith("UNION"))
|
|
1170
|
-
return "json";
|
|
1171
|
-
if (base.endsWith("[]") || base.startsWith("LIST")) return "json";
|
|
1172
|
-
if (upper.includes("INT") || upper.includes("FLOAT") || upper.includes("DOUBLE") || upper.includes("DECIMAL") || upper.includes("NUMERIC"))
|
|
1173
|
-
return "number";
|
|
1174
|
-
if (upper.includes("CHAR") || upper.includes("TEXT") || upper.includes("STRING")) return "string";
|
|
1175
|
-
if (upper.includes("TIME") || upper.includes("DATE")) return "date";
|
|
1176
|
-
if (upper.includes("BOOL")) return "boolean";
|
|
1177
|
-
if (upper.includes("GEOMETRY") || upper.includes("GEO") || upper.includes("WKB")) return "geo";
|
|
1178
|
-
if (upper.includes("BLOB") || upper.includes("BINARY")) return "binary";
|
|
1179
|
-
if (upper.includes("JSON") || upper.includes("STRUCT") || upper.includes("MAP") || upper.includes("LIST"))
|
|
1180
|
-
return "json";
|
|
1181
|
-
return "other";
|
|
1182
|
-
}
|
|
1183
|
-
var TYPE_COLORS = {
|
|
1184
|
-
number: "text-blue-500",
|
|
1185
|
-
string: "text-green-500",
|
|
1186
|
-
date: "text-amber-500",
|
|
1187
|
-
boolean: "text-purple-500",
|
|
1188
|
-
geo: "text-teal-500",
|
|
1189
|
-
binary: "text-zinc-500",
|
|
1190
|
-
json: "text-orange-500",
|
|
1191
|
-
other: "text-zinc-400"
|
|
1192
|
-
};
|
|
1193
|
-
var TYPE_BADGE_CLASSES = {
|
|
1194
|
-
number: "bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20",
|
|
1195
|
-
string: "bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20",
|
|
1196
|
-
date: "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20",
|
|
1197
|
-
boolean: "bg-purple-500/10 text-purple-600 dark:text-purple-400 border-purple-500/20",
|
|
1198
|
-
geo: "bg-teal-500/10 text-teal-600 dark:text-teal-400 border-teal-500/20",
|
|
1199
|
-
binary: "bg-zinc-500/10 text-zinc-600 dark:text-zinc-400 border-zinc-500/20",
|
|
1200
|
-
json: "bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/20",
|
|
1201
|
-
other: "bg-zinc-500/10 text-zinc-500 dark:text-zinc-400 border-zinc-500/20"
|
|
1202
|
-
};
|
|
1203
|
-
var TYPE_LABELS = {
|
|
1204
|
-
number: "#",
|
|
1205
|
-
string: "Aa",
|
|
1206
|
-
date: "dt",
|
|
1207
|
-
boolean: "T/F",
|
|
1208
|
-
geo: "geo",
|
|
1209
|
-
binary: "01",
|
|
1210
|
-
json: "{}",
|
|
1211
|
-
other: "?"
|
|
1212
|
-
};
|
|
1213
|
-
function typeColor(category) {
|
|
1214
|
-
return TYPE_COLORS[category];
|
|
1215
|
-
}
|
|
1216
|
-
function typeBadgeClass(category) {
|
|
1217
|
-
return TYPE_BADGE_CLASSES[category];
|
|
1218
|
-
}
|
|
1219
|
-
function typeLabel(category) {
|
|
1220
|
-
return TYPE_LABELS[category];
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
// ../../src/lib/utils/error.ts
|
|
1224
|
-
function handleLoadError(err) {
|
|
1225
|
-
if (err instanceof DOMException && err.name === "AbortError") return null;
|
|
1226
|
-
return err instanceof Error ? err.message : String(err);
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
// ../../src/lib/utils/format.ts
|
|
1230
|
-
function formatFileSize(bytes) {
|
|
1231
|
-
if (bytes < 0) return "0 B";
|
|
1232
|
-
if (bytes === 0) return "0 B";
|
|
1233
|
-
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
1234
|
-
const base = 1024;
|
|
1235
|
-
const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(base)), units.length - 1);
|
|
1236
|
-
const value = bytes / base ** exponent;
|
|
1237
|
-
if (exponent === 0) return `${bytes} B`;
|
|
1238
|
-
return `${value.toFixed(1)} ${units[exponent]}`;
|
|
1239
|
-
}
|
|
1240
|
-
function formatDate(timestamp) {
|
|
1241
|
-
if (!timestamp || timestamp <= 0 || !Number.isFinite(timestamp)) return "--";
|
|
1242
|
-
const date = new Date(timestamp);
|
|
1243
|
-
const now = Date.now();
|
|
1244
|
-
const diffMs = now - timestamp;
|
|
1245
|
-
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
1246
|
-
const diffMinutes = Math.floor(diffSeconds / 60);
|
|
1247
|
-
const diffHours = Math.floor(diffMinutes / 60);
|
|
1248
|
-
const diffDays = Math.floor(diffHours / 24);
|
|
1249
|
-
if (diffSeconds < 60) return "Just now";
|
|
1250
|
-
if (diffMinutes < 60) return `${diffMinutes}m ago`;
|
|
1251
|
-
if (diffHours < 24) return `${diffHours}h ago`;
|
|
1252
|
-
if (diffDays < 7) return `${diffDays}d ago`;
|
|
1253
|
-
return date.toLocaleDateString(void 0, {
|
|
1254
|
-
year: "numeric",
|
|
1255
|
-
month: "short",
|
|
1256
|
-
day: "numeric"
|
|
1257
|
-
});
|
|
1258
|
-
}
|
|
1259
|
-
function getFileExtension(filename) {
|
|
1260
|
-
const lastDot = filename.lastIndexOf(".");
|
|
1261
|
-
if (lastDot <= 0) return "";
|
|
1262
|
-
return filename.slice(lastDot).toLowerCase();
|
|
1263
|
-
}
|
|
1264
|
-
function jsonReplacerBigInt(_key, value) {
|
|
1265
|
-
return typeof value === "bigint" ? value.toString() : value;
|
|
1266
|
-
}
|
|
1267
|
-
function formatValue(value) {
|
|
1268
|
-
if (value === null || value === void 0) return "NULL";
|
|
1269
|
-
if (value instanceof Date) return value.toISOString();
|
|
1270
|
-
if (typeof value === "bigint") return value.toString();
|
|
1271
|
-
if (typeof value === "object") return JSON.stringify(value, jsonReplacerBigInt);
|
|
1272
|
-
return String(value);
|
|
1273
|
-
}
|
|
1274
|
-
function normalizeGeomType(raw) {
|
|
1275
|
-
const s = raw.toUpperCase().replace(/\s+/g, "");
|
|
1276
|
-
if (s === "POINT") return "point";
|
|
1277
|
-
if (s === "LINESTRING") return "linestring";
|
|
1278
|
-
if (s === "POLYGON") return "polygon";
|
|
1279
|
-
if (s === "MULTIPOINT") return "multipoint";
|
|
1280
|
-
if (s === "MULTILINESTRING") return "multilinestring";
|
|
1281
|
-
if (s === "MULTIPOLYGON") return "multipolygon";
|
|
1282
|
-
return "polygon";
|
|
1283
|
-
}
|
|
1284
|
-
var EXTENSION_NAMES = {
|
|
1285
|
-
point: "geoarrow.point",
|
|
1286
|
-
linestring: "geoarrow.linestring",
|
|
1287
|
-
polygon: "geoarrow.polygon",
|
|
1288
|
-
multipoint: "geoarrow.multipoint",
|
|
1289
|
-
multilinestring: "geoarrow.multilinestring",
|
|
1290
|
-
multipolygon: "geoarrow.multipolygon"
|
|
1291
|
-
};
|
|
1292
|
-
function readWkbHeader(wkb) {
|
|
1293
|
-
if (wkb.length < 5) return null;
|
|
1294
|
-
const le = wkb[0] === 1;
|
|
1295
|
-
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1296
|
-
const rawType = dv.getUint32(1, le);
|
|
1297
|
-
let headerSize = 5;
|
|
1298
|
-
if ((rawType & 536870912) !== 0) headerSize += 4;
|
|
1299
|
-
const ewkbZ = (rawType & 2147483648) !== 0;
|
|
1300
|
-
const ewkbM = (rawType & 1073741824) !== 0;
|
|
1301
|
-
let type = rawType & 268435455;
|
|
1302
|
-
let isoZ = false;
|
|
1303
|
-
let isoM = false;
|
|
1304
|
-
if (type > 3e3) {
|
|
1305
|
-
isoZ = true;
|
|
1306
|
-
isoM = true;
|
|
1307
|
-
type -= 3e3;
|
|
1308
|
-
} else if (type > 2e3) {
|
|
1309
|
-
isoM = true;
|
|
1310
|
-
type -= 2e3;
|
|
1311
|
-
} else if (type > 1e3) {
|
|
1312
|
-
isoZ = true;
|
|
1313
|
-
type -= 1e3;
|
|
1314
|
-
}
|
|
1315
|
-
const dims = (ewkbZ || isoZ ? 1 : 0) + (ewkbM || isoM ? 1 : 0);
|
|
1316
|
-
const coordStride = (2 + dims) * 8;
|
|
1317
|
-
return { type, le, coordStride, dataOffset: headerSize };
|
|
1318
|
-
}
|
|
1319
|
-
function classifyWkbType(wkb) {
|
|
1320
|
-
const h = readWkbHeader(wkb);
|
|
1321
|
-
if (!h) return null;
|
|
1322
|
-
switch (h.type) {
|
|
1323
|
-
case 1:
|
|
1324
|
-
return "point";
|
|
1325
|
-
case 2:
|
|
1326
|
-
return "linestring";
|
|
1327
|
-
case 3:
|
|
1328
|
-
return "polygon";
|
|
1329
|
-
case 4:
|
|
1330
|
-
return "multipoint";
|
|
1331
|
-
case 5:
|
|
1332
|
-
return "multilinestring";
|
|
1333
|
-
case 6:
|
|
1334
|
-
return "multipolygon";
|
|
1335
|
-
default:
|
|
1336
|
-
return null;
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
function newBounds() {
|
|
1340
|
-
return { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity };
|
|
1341
|
-
}
|
|
1342
|
-
function expandBounds(b, x, y) {
|
|
1343
|
-
if (Number.isNaN(x) || Number.isNaN(y)) return;
|
|
1344
|
-
if (x < b.minX) b.minX = x;
|
|
1345
|
-
if (y < b.minY) b.minY = y;
|
|
1346
|
-
if (x > b.maxX) b.maxX = x;
|
|
1347
|
-
if (y > b.maxY) b.maxY = y;
|
|
1348
|
-
}
|
|
1349
|
-
var coordField = new apacheArrow.Field("xy", new apacheArrow.Float64());
|
|
1350
|
-
var coordType = new apacheArrow.FixedSizeList(2, coordField);
|
|
1351
|
-
function makeCoordData(coords, numPoints) {
|
|
1352
|
-
const floatData = apacheArrow.makeData({ type: new apacheArrow.Float64(), length: coords.length, data: coords });
|
|
1353
|
-
return apacheArrow.makeData({ type: coordType, length: numPoints, nullCount: 0, child: floatData });
|
|
1354
|
-
}
|
|
1355
|
-
function buildPointData(wkbs, b) {
|
|
1356
|
-
const n = wkbs.length;
|
|
1357
|
-
const coords = new Float64Array(n * 2);
|
|
1358
|
-
for (let i = 0; i < n; i++) {
|
|
1359
|
-
const wkb = wkbs[i];
|
|
1360
|
-
const h = readWkbHeader(wkb);
|
|
1361
|
-
if (!h || h.type !== 1) {
|
|
1362
|
-
coords[i * 2] = 0;
|
|
1363
|
-
coords[i * 2 + 1] = 0;
|
|
1364
|
-
continue;
|
|
1365
|
-
}
|
|
1366
|
-
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1367
|
-
const x = dv.getFloat64(h.dataOffset, h.le);
|
|
1368
|
-
const y = dv.getFloat64(h.dataOffset + 8, h.le);
|
|
1369
|
-
coords[i * 2] = x;
|
|
1370
|
-
coords[i * 2 + 1] = y;
|
|
1371
|
-
expandBounds(b, x, y);
|
|
1372
|
-
}
|
|
1373
|
-
return makeCoordData(coords, n);
|
|
1374
|
-
}
|
|
1375
|
-
function buildLineStringData(wkbs, b) {
|
|
1376
|
-
const n = wkbs.length;
|
|
1377
|
-
const geomOffsets = new Int32Array(n + 1);
|
|
1378
|
-
let totalCoords = 0;
|
|
1379
|
-
for (let i = 0; i < n; i++) {
|
|
1380
|
-
geomOffsets[i] = totalCoords;
|
|
1381
|
-
const h = readWkbHeader(wkbs[i]);
|
|
1382
|
-
if (!h || h.type !== 2) continue;
|
|
1383
|
-
const dv = new DataView(wkbs[i].buffer, wkbs[i].byteOffset, wkbs[i].byteLength);
|
|
1384
|
-
const numPts = dv.getUint32(h.dataOffset, h.le);
|
|
1385
|
-
totalCoords += numPts;
|
|
1386
|
-
}
|
|
1387
|
-
geomOffsets[n] = totalCoords;
|
|
1388
|
-
const coords = new Float64Array(totalCoords * 2);
|
|
1389
|
-
let ci = 0;
|
|
1390
|
-
for (const wkb of wkbs) {
|
|
1391
|
-
const h = readWkbHeader(wkb);
|
|
1392
|
-
if (!h || h.type !== 2) continue;
|
|
1393
|
-
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1394
|
-
const numPts = dv.getUint32(h.dataOffset, h.le);
|
|
1395
|
-
let off = h.dataOffset + 4;
|
|
1396
|
-
for (let j = 0; j < numPts; j++) {
|
|
1397
|
-
const x = dv.getFloat64(off, h.le);
|
|
1398
|
-
const y = dv.getFloat64(off + 8, h.le);
|
|
1399
|
-
coords[ci++] = x;
|
|
1400
|
-
coords[ci++] = y;
|
|
1401
|
-
expandBounds(b, x, y);
|
|
1402
|
-
off += h.coordStride;
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
const fslData = makeCoordData(coords, totalCoords);
|
|
1406
|
-
const listType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1407
|
-
return apacheArrow.makeData({
|
|
1408
|
-
type: listType,
|
|
1409
|
-
length: n,
|
|
1410
|
-
nullCount: 0,
|
|
1411
|
-
valueOffsets: geomOffsets,
|
|
1412
|
-
child: fslData
|
|
1413
|
-
});
|
|
1414
|
-
}
|
|
1415
|
-
function buildPolygonData(wkbs, b) {
|
|
1416
|
-
const n = wkbs.length;
|
|
1417
|
-
const geomOffsets = new Int32Array(n + 1);
|
|
1418
|
-
let totalRings = 0;
|
|
1419
|
-
let totalCoords = 0;
|
|
1420
|
-
for (let i = 0; i < n; i++) {
|
|
1421
|
-
geomOffsets[i] = totalRings;
|
|
1422
|
-
const h = readWkbHeader(wkbs[i]);
|
|
1423
|
-
if (!h || h.type !== 3) continue;
|
|
1424
|
-
const dv = new DataView(wkbs[i].buffer, wkbs[i].byteOffset, wkbs[i].byteLength);
|
|
1425
|
-
const numRings = dv.getUint32(h.dataOffset, h.le);
|
|
1426
|
-
let off = h.dataOffset + 4;
|
|
1427
|
-
for (let r = 0; r < numRings; r++) {
|
|
1428
|
-
const numPts = dv.getUint32(off, h.le);
|
|
1429
|
-
off += 4 + numPts * h.coordStride;
|
|
1430
|
-
totalCoords += numPts;
|
|
1431
|
-
totalRings++;
|
|
1432
|
-
}
|
|
1433
|
-
}
|
|
1434
|
-
geomOffsets[n] = totalRings;
|
|
1435
|
-
const ringOffsets = new Int32Array(totalRings + 1);
|
|
1436
|
-
const coords = new Float64Array(totalCoords * 2);
|
|
1437
|
-
let ri = 0;
|
|
1438
|
-
let ci = 0;
|
|
1439
|
-
for (const wkb of wkbs) {
|
|
1440
|
-
const h = readWkbHeader(wkb);
|
|
1441
|
-
if (!h || h.type !== 3) continue;
|
|
1442
|
-
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1443
|
-
const numRings = dv.getUint32(h.dataOffset, h.le);
|
|
1444
|
-
let off = h.dataOffset + 4;
|
|
1445
|
-
for (let r = 0; r < numRings; r++) {
|
|
1446
|
-
ringOffsets[ri++] = ci >> 1;
|
|
1447
|
-
const numPts = dv.getUint32(off, h.le);
|
|
1448
|
-
off += 4;
|
|
1449
|
-
for (let j = 0; j < numPts; j++) {
|
|
1450
|
-
const x = dv.getFloat64(off, h.le);
|
|
1451
|
-
const y = dv.getFloat64(off + 8, h.le);
|
|
1452
|
-
coords[ci++] = x;
|
|
1453
|
-
coords[ci++] = y;
|
|
1454
|
-
expandBounds(b, x, y);
|
|
1455
|
-
off += h.coordStride;
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
ringOffsets[totalRings] = ci >> 1;
|
|
1460
|
-
const coordCount = ci >> 1;
|
|
1461
|
-
const fslData = makeCoordData(coords, coordCount);
|
|
1462
|
-
const ringListType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1463
|
-
const ringListData = apacheArrow.makeData({
|
|
1464
|
-
type: ringListType,
|
|
1465
|
-
length: totalRings,
|
|
1466
|
-
nullCount: 0,
|
|
1467
|
-
valueOffsets: ringOffsets,
|
|
1468
|
-
child: fslData
|
|
1469
|
-
});
|
|
1470
|
-
const polyType = new apacheArrow.List(new apacheArrow.Field("rings", ringListType));
|
|
1471
|
-
return apacheArrow.makeData({
|
|
1472
|
-
type: polyType,
|
|
1473
|
-
length: n,
|
|
1474
|
-
nullCount: 0,
|
|
1475
|
-
valueOffsets: geomOffsets,
|
|
1476
|
-
child: ringListData
|
|
1477
|
-
});
|
|
1478
|
-
}
|
|
1479
|
-
function buildMultiPointData(wkbs, b) {
|
|
1480
|
-
const n = wkbs.length;
|
|
1481
|
-
const geomOffsets = new Int32Array(n + 1);
|
|
1482
|
-
let totalCoords = 0;
|
|
1483
|
-
for (let i = 0; i < n; i++) {
|
|
1484
|
-
geomOffsets[i] = totalCoords;
|
|
1485
|
-
const h = readWkbHeader(wkbs[i]);
|
|
1486
|
-
if (!h || h.type !== 4) continue;
|
|
1487
|
-
const dv = new DataView(wkbs[i].buffer, wkbs[i].byteOffset, wkbs[i].byteLength);
|
|
1488
|
-
totalCoords += dv.getUint32(h.dataOffset, h.le);
|
|
1489
|
-
}
|
|
1490
|
-
geomOffsets[n] = totalCoords;
|
|
1491
|
-
const coords = new Float64Array(totalCoords * 2);
|
|
1492
|
-
let ci = 0;
|
|
1493
|
-
for (const wkb of wkbs) {
|
|
1494
|
-
const h = readWkbHeader(wkb);
|
|
1495
|
-
if (!h || h.type !== 4) continue;
|
|
1496
|
-
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1497
|
-
const numPts = dv.getUint32(h.dataOffset, h.le);
|
|
1498
|
-
let off = h.dataOffset + 4;
|
|
1499
|
-
for (let j = 0; j < numPts; j++) {
|
|
1500
|
-
const innerH = readWkbHeader(
|
|
1501
|
-
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1502
|
-
);
|
|
1503
|
-
if (innerH) {
|
|
1504
|
-
const x = dv.getFloat64(off + innerH.dataOffset, innerH.le);
|
|
1505
|
-
const y = dv.getFloat64(off + innerH.dataOffset + 8, innerH.le);
|
|
1506
|
-
coords[ci++] = x;
|
|
1507
|
-
coords[ci++] = y;
|
|
1508
|
-
expandBounds(b, x, y);
|
|
1509
|
-
off += innerH.dataOffset + innerH.coordStride;
|
|
1510
|
-
} else {
|
|
1511
|
-
coords[ci++] = 0;
|
|
1512
|
-
coords[ci++] = 0;
|
|
1513
|
-
off += 21;
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
const fslData = makeCoordData(coords, totalCoords);
|
|
1518
|
-
const listType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1519
|
-
return apacheArrow.makeData({
|
|
1520
|
-
type: listType,
|
|
1521
|
-
length: n,
|
|
1522
|
-
nullCount: 0,
|
|
1523
|
-
valueOffsets: geomOffsets,
|
|
1524
|
-
child: fslData
|
|
1525
|
-
});
|
|
1526
|
-
}
|
|
1527
|
-
function buildMultiLineStringData(wkbs, b) {
|
|
1528
|
-
const n = wkbs.length;
|
|
1529
|
-
const geomOffsetsArr = [0];
|
|
1530
|
-
let totalLines = 0;
|
|
1531
|
-
let totalCoords = 0;
|
|
1532
|
-
for (const wkb of wkbs) {
|
|
1533
|
-
const h = readWkbHeader(wkb);
|
|
1534
|
-
if (!h || h.type !== 5) {
|
|
1535
|
-
geomOffsetsArr.push(totalLines);
|
|
1536
|
-
continue;
|
|
1537
|
-
}
|
|
1538
|
-
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1539
|
-
const numLines = dv.getUint32(h.dataOffset, h.le);
|
|
1540
|
-
let off = h.dataOffset + 4;
|
|
1541
|
-
for (let l = 0; l < numLines; l++) {
|
|
1542
|
-
const innerH = readWkbHeader(
|
|
1543
|
-
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1544
|
-
);
|
|
1545
|
-
if (!innerH) break;
|
|
1546
|
-
const innerDv = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off);
|
|
1547
|
-
const numPts = innerDv.getUint32(innerH.dataOffset, innerH.le);
|
|
1548
|
-
totalCoords += numPts;
|
|
1549
|
-
off += innerH.dataOffset + 4 + numPts * innerH.coordStride;
|
|
1550
|
-
totalLines++;
|
|
1551
|
-
}
|
|
1552
|
-
geomOffsetsArr.push(totalLines);
|
|
1553
|
-
}
|
|
1554
|
-
const geomOffsets = new Int32Array(geomOffsetsArr);
|
|
1555
|
-
const lineOffsets = new Int32Array(totalLines + 1);
|
|
1556
|
-
const coords = new Float64Array(totalCoords * 2);
|
|
1557
|
-
let li = 0;
|
|
1558
|
-
let ci = 0;
|
|
1559
|
-
for (const wkb of wkbs) {
|
|
1560
|
-
const h = readWkbHeader(wkb);
|
|
1561
|
-
if (!h || h.type !== 5) continue;
|
|
1562
|
-
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1563
|
-
const numLines = dv.getUint32(h.dataOffset, h.le);
|
|
1564
|
-
let off = h.dataOffset + 4;
|
|
1565
|
-
for (let l = 0; l < numLines; l++) {
|
|
1566
|
-
lineOffsets[li++] = ci >> 1;
|
|
1567
|
-
const innerH = readWkbHeader(
|
|
1568
|
-
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1569
|
-
);
|
|
1570
|
-
if (!innerH) break;
|
|
1571
|
-
const numPts = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off).getUint32(
|
|
1572
|
-
innerH.dataOffset,
|
|
1573
|
-
innerH.le
|
|
1574
|
-
);
|
|
1575
|
-
let ptOff = off + innerH.dataOffset + 4;
|
|
1576
|
-
for (let j = 0; j < numPts; j++) {
|
|
1577
|
-
const x = dv.getFloat64(ptOff, innerH.le);
|
|
1578
|
-
const y = dv.getFloat64(ptOff + 8, innerH.le);
|
|
1579
|
-
coords[ci++] = x;
|
|
1580
|
-
coords[ci++] = y;
|
|
1581
|
-
expandBounds(b, x, y);
|
|
1582
|
-
ptOff += innerH.coordStride;
|
|
1583
|
-
}
|
|
1584
|
-
off = ptOff;
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
lineOffsets[totalLines] = ci >> 1;
|
|
1588
|
-
const fslData = makeCoordData(coords, ci >> 1);
|
|
1589
|
-
const lineListType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1590
|
-
const lineListData = apacheArrow.makeData({
|
|
1591
|
-
type: lineListType,
|
|
1592
|
-
length: totalLines,
|
|
1593
|
-
nullCount: 0,
|
|
1594
|
-
valueOffsets: lineOffsets,
|
|
1595
|
-
child: fslData
|
|
1596
|
-
});
|
|
1597
|
-
const multiLineType = new apacheArrow.List(new apacheArrow.Field("lines", lineListType));
|
|
1598
|
-
return apacheArrow.makeData({
|
|
1599
|
-
type: multiLineType,
|
|
1600
|
-
length: n,
|
|
1601
|
-
nullCount: 0,
|
|
1602
|
-
valueOffsets: geomOffsets,
|
|
1603
|
-
child: lineListData
|
|
1604
|
-
});
|
|
1605
|
-
}
|
|
1606
|
-
function buildMultiPolygonData(wkbs, b) {
|
|
1607
|
-
const n = wkbs.length;
|
|
1608
|
-
const geomOffsetsArr = [0];
|
|
1609
|
-
let totalPolys = 0;
|
|
1610
|
-
let totalRings = 0;
|
|
1611
|
-
let totalCoords = 0;
|
|
1612
|
-
for (const wkb of wkbs) {
|
|
1613
|
-
const h = readWkbHeader(wkb);
|
|
1614
|
-
if (!h || h.type !== 6) {
|
|
1615
|
-
geomOffsetsArr.push(totalPolys);
|
|
1616
|
-
continue;
|
|
1617
|
-
}
|
|
1618
|
-
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1619
|
-
const numPolys = dv.getUint32(h.dataOffset, h.le);
|
|
1620
|
-
let off = h.dataOffset + 4;
|
|
1621
|
-
for (let p = 0; p < numPolys; p++) {
|
|
1622
|
-
const innerH = readWkbHeader(
|
|
1623
|
-
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1624
|
-
);
|
|
1625
|
-
if (!innerH) break;
|
|
1626
|
-
const innerDv = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off);
|
|
1627
|
-
const numRings = innerDv.getUint32(innerH.dataOffset, innerH.le);
|
|
1628
|
-
let ringOff = innerH.dataOffset + 4;
|
|
1629
|
-
for (let r = 0; r < numRings; r++) {
|
|
1630
|
-
const numPts = innerDv.getUint32(ringOff, innerH.le);
|
|
1631
|
-
ringOff += 4 + numPts * innerH.coordStride;
|
|
1632
|
-
totalCoords += numPts;
|
|
1633
|
-
totalRings++;
|
|
1634
|
-
}
|
|
1635
|
-
off += ringOff;
|
|
1636
|
-
totalPolys++;
|
|
1637
|
-
}
|
|
1638
|
-
geomOffsetsArr.push(totalPolys);
|
|
1639
|
-
}
|
|
1640
|
-
const geomOffsets = new Int32Array(geomOffsetsArr);
|
|
1641
|
-
const polyOffsets = new Int32Array(totalPolys + 1);
|
|
1642
|
-
const ringOffsets = new Int32Array(totalRings + 1);
|
|
1643
|
-
const coords = new Float64Array(totalCoords * 2);
|
|
1644
|
-
let pi = 0;
|
|
1645
|
-
let ri = 0;
|
|
1646
|
-
let ci = 0;
|
|
1647
|
-
for (const wkb of wkbs) {
|
|
1648
|
-
const h = readWkbHeader(wkb);
|
|
1649
|
-
if (!h || h.type !== 6) continue;
|
|
1650
|
-
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1651
|
-
const numPolys = dv.getUint32(h.dataOffset, h.le);
|
|
1652
|
-
let off = h.dataOffset + 4;
|
|
1653
|
-
for (let p = 0; p < numPolys; p++) {
|
|
1654
|
-
polyOffsets[pi++] = ri;
|
|
1655
|
-
const innerH = readWkbHeader(
|
|
1656
|
-
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1657
|
-
);
|
|
1658
|
-
if (!innerH) break;
|
|
1659
|
-
const innerDv = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off);
|
|
1660
|
-
const numRings = innerDv.getUint32(innerH.dataOffset, innerH.le);
|
|
1661
|
-
let ringOff = off + innerH.dataOffset + 4;
|
|
1662
|
-
for (let r = 0; r < numRings; r++) {
|
|
1663
|
-
ringOffsets[ri++] = ci >> 1;
|
|
1664
|
-
const numPts = dv.getUint32(ringOff, innerH.le);
|
|
1665
|
-
ringOff += 4;
|
|
1666
|
-
for (let j = 0; j < numPts; j++) {
|
|
1667
|
-
const x = dv.getFloat64(ringOff, innerH.le);
|
|
1668
|
-
const y = dv.getFloat64(ringOff + 8, innerH.le);
|
|
1669
|
-
coords[ci++] = x;
|
|
1670
|
-
coords[ci++] = y;
|
|
1671
|
-
expandBounds(b, x, y);
|
|
1672
|
-
ringOff += innerH.coordStride;
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
off = ringOff;
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
polyOffsets[totalPolys] = ri;
|
|
1679
|
-
ringOffsets[totalRings] = ci >> 1;
|
|
1680
|
-
const fslData = makeCoordData(coords, ci >> 1);
|
|
1681
|
-
const ringListType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1682
|
-
const ringListData = apacheArrow.makeData({
|
|
1683
|
-
type: ringListType,
|
|
1684
|
-
length: totalRings,
|
|
1685
|
-
nullCount: 0,
|
|
1686
|
-
valueOffsets: ringOffsets,
|
|
1687
|
-
child: fslData
|
|
1688
|
-
});
|
|
1689
|
-
const polyListType = new apacheArrow.List(new apacheArrow.Field("rings", ringListType));
|
|
1690
|
-
const polyListData = apacheArrow.makeData({
|
|
1691
|
-
type: polyListType,
|
|
1692
|
-
length: totalPolys,
|
|
1693
|
-
nullCount: 0,
|
|
1694
|
-
valueOffsets: polyOffsets,
|
|
1695
|
-
child: ringListData
|
|
1696
|
-
});
|
|
1697
|
-
const multiPolyType = new apacheArrow.List(new apacheArrow.Field("polygons", polyListType));
|
|
1698
|
-
return apacheArrow.makeData({
|
|
1699
|
-
type: multiPolyType,
|
|
1700
|
-
length: n,
|
|
1701
|
-
nullCount: 0,
|
|
1702
|
-
valueOffsets: geomOffsets,
|
|
1703
|
-
child: polyListData
|
|
1704
|
-
});
|
|
1705
|
-
}
|
|
1706
|
-
function buildAttributeColumns(indices, attributes) {
|
|
1707
|
-
const n = indices.length;
|
|
1708
|
-
const fields = [];
|
|
1709
|
-
const dataArr = [];
|
|
1710
|
-
for (const [name, col] of attributes) {
|
|
1711
|
-
const { values } = col;
|
|
1712
|
-
let isNumeric = true;
|
|
1713
|
-
const sampleEnd = Math.min(n, 100);
|
|
1714
|
-
for (let i = 0; i < sampleEnd; i++) {
|
|
1715
|
-
if (values[indices[i]] != null && typeof values[indices[i]] !== "number") {
|
|
1716
|
-
isNumeric = false;
|
|
1717
|
-
break;
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
if (isNumeric) {
|
|
1721
|
-
const arr = new Float64Array(n);
|
|
1722
|
-
for (let i = 0; i < n; i++) arr[i] = values[indices[i]] ?? NaN;
|
|
1723
|
-
const data = apacheArrow.makeData({ type: new apacheArrow.Float64(), length: n, data: arr });
|
|
1724
|
-
fields.push(new apacheArrow.Field(name, new apacheArrow.Float64(), true));
|
|
1725
|
-
dataArr.push(data);
|
|
1726
|
-
} else {
|
|
1727
|
-
const encoder = new TextEncoder();
|
|
1728
|
-
const offsets = new Int32Array(n + 1);
|
|
1729
|
-
let totalBytes = 0;
|
|
1730
|
-
const strParts = [];
|
|
1731
|
-
for (let i = 0; i < n; i++) {
|
|
1732
|
-
offsets[i] = totalBytes;
|
|
1733
|
-
const s = values[indices[i]] != null ? String(values[indices[i]]) : "";
|
|
1734
|
-
const encoded = encoder.encode(s);
|
|
1735
|
-
strParts.push(encoded);
|
|
1736
|
-
totalBytes += encoded.length;
|
|
1737
|
-
}
|
|
1738
|
-
offsets[n] = totalBytes;
|
|
1739
|
-
const valueBuffer = new Uint8Array(totalBytes);
|
|
1740
|
-
let pos = 0;
|
|
1741
|
-
for (const sv of strParts) {
|
|
1742
|
-
valueBuffer.set(sv, pos);
|
|
1743
|
-
pos += sv.length;
|
|
1744
|
-
}
|
|
1745
|
-
const data = apacheArrow.makeData({
|
|
1746
|
-
type: new apacheArrow.Utf8(),
|
|
1747
|
-
length: n,
|
|
1748
|
-
valueOffsets: offsets,
|
|
1749
|
-
data: valueBuffer
|
|
1750
|
-
});
|
|
1751
|
-
fields.push(new apacheArrow.Field(name, new apacheArrow.Utf8(), true));
|
|
1752
|
-
dataArr.push(data);
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
return { fields, data: dataArr };
|
|
1756
|
-
}
|
|
1757
|
-
function buildSingleTable(geomType, wkbs, indices, attributes, b) {
|
|
1758
|
-
const n = wkbs.length;
|
|
1759
|
-
let geomData;
|
|
1760
|
-
switch (geomType) {
|
|
1761
|
-
case "point":
|
|
1762
|
-
geomData = buildPointData(wkbs, b);
|
|
1763
|
-
break;
|
|
1764
|
-
case "linestring":
|
|
1765
|
-
geomData = buildLineStringData(wkbs, b);
|
|
1766
|
-
break;
|
|
1767
|
-
case "polygon":
|
|
1768
|
-
geomData = buildPolygonData(wkbs, b);
|
|
1769
|
-
break;
|
|
1770
|
-
case "multipoint":
|
|
1771
|
-
geomData = buildMultiPointData(wkbs, b);
|
|
1772
|
-
break;
|
|
1773
|
-
case "multilinestring":
|
|
1774
|
-
geomData = buildMultiLineStringData(wkbs, b);
|
|
1775
|
-
break;
|
|
1776
|
-
case "multipolygon":
|
|
1777
|
-
geomData = buildMultiPolygonData(wkbs, b);
|
|
1778
|
-
break;
|
|
1779
|
-
}
|
|
1780
|
-
const extensionName = EXTENSION_NAMES[geomType];
|
|
1781
|
-
const geomMetadata = /* @__PURE__ */ new Map([
|
|
1782
|
-
["ARROW:extension:name", extensionName],
|
|
1783
|
-
[
|
|
1784
|
-
"ARROW:extension:metadata",
|
|
1785
|
-
JSON.stringify({
|
|
1786
|
-
crs: {
|
|
1787
|
-
type: "name",
|
|
1788
|
-
properties: { name: "urn:ogc:def:crs:OGC:1.3:CRS84" }
|
|
1789
|
-
}
|
|
1790
|
-
})
|
|
1791
|
-
]
|
|
1792
|
-
]);
|
|
1793
|
-
const geomField = new apacheArrow.Field("geometry", geomData.type, false, geomMetadata);
|
|
1794
|
-
const attrCols = buildAttributeColumns(indices, attributes);
|
|
1795
|
-
const fields = [geomField, ...attrCols.fields];
|
|
1796
|
-
const childrenData = [geomData, ...attrCols.data];
|
|
1797
|
-
const arrowSchema = new apacheArrow.Schema(fields);
|
|
1798
|
-
const structType = new apacheArrow.Struct(fields);
|
|
1799
|
-
const structData = apacheArrow.makeData({
|
|
1800
|
-
type: structType,
|
|
1801
|
-
length: n,
|
|
1802
|
-
nullCount: 0,
|
|
1803
|
-
children: childrenData
|
|
1804
|
-
});
|
|
1805
|
-
const batch = new apacheArrow.RecordBatch(arrowSchema, structData);
|
|
1806
|
-
const table = new apacheArrow.Table(arrowSchema, batch);
|
|
1807
|
-
return {
|
|
1808
|
-
table,
|
|
1809
|
-
geometryType: geomType,
|
|
1810
|
-
bounds: [b.minX, b.minY, b.maxX, b.maxY],
|
|
1811
|
-
sourceIndices: indices
|
|
1812
|
-
};
|
|
1813
|
-
}
|
|
1814
|
-
function buildGeoArrowTables(wkbArrays, attributes, knownGeomType) {
|
|
1815
|
-
if (wkbArrays.length === 0) return [];
|
|
1816
|
-
if (knownGeomType) {
|
|
1817
|
-
const globalBounds2 = newBounds();
|
|
1818
|
-
const indices = Array.from({ length: wkbArrays.length }, (_, i) => i);
|
|
1819
|
-
const result = buildSingleTable(knownGeomType, wkbArrays, indices, attributes, globalBounds2);
|
|
1820
|
-
return [result];
|
|
1821
|
-
}
|
|
1822
|
-
const groups = /* @__PURE__ */ new Map();
|
|
1823
|
-
for (let i = 0; i < wkbArrays.length; i++) {
|
|
1824
|
-
const geomType = classifyWkbType(wkbArrays[i]);
|
|
1825
|
-
if (!geomType) continue;
|
|
1826
|
-
let group = groups.get(geomType);
|
|
1827
|
-
if (!group) {
|
|
1828
|
-
group = { wkbs: [], indices: [] };
|
|
1829
|
-
groups.set(geomType, group);
|
|
1830
|
-
}
|
|
1831
|
-
group.wkbs.push(wkbArrays[i]);
|
|
1832
|
-
group.indices.push(i);
|
|
1833
|
-
}
|
|
1834
|
-
if (groups.size === 0) return [];
|
|
1835
|
-
const globalBounds = newBounds();
|
|
1836
|
-
const results = [];
|
|
1837
|
-
for (const [geomType, { wkbs, indices }] of groups) {
|
|
1838
|
-
const result = buildSingleTable(geomType, wkbs, indices, attributes, globalBounds);
|
|
1839
|
-
results.push(result);
|
|
1840
|
-
}
|
|
1841
|
-
const mergedBounds = [
|
|
1842
|
-
globalBounds.minX,
|
|
1843
|
-
globalBounds.minY,
|
|
1844
|
-
globalBounds.maxX,
|
|
1845
|
-
globalBounds.maxY
|
|
1846
|
-
];
|
|
1847
|
-
for (const r of results) r.bounds = mergedBounds;
|
|
1848
|
-
return results;
|
|
1849
|
-
}
|
|
1850
|
-
|
|
1851
|
-
// ../../src/lib/utils/hex.ts
|
|
1852
|
-
function generateHexDump(data, bytesPerRow = 16) {
|
|
1853
|
-
const rows = [];
|
|
1854
|
-
for (let i = 0; i < data.length; i += bytesPerRow) {
|
|
1855
|
-
const slice = data.slice(i, i + bytesPerRow);
|
|
1856
|
-
const offset = i.toString(16).padStart(8, "0");
|
|
1857
|
-
const hex = [];
|
|
1858
|
-
for (let j = 0; j < bytesPerRow; j++) {
|
|
1859
|
-
if (j < slice.length) {
|
|
1860
|
-
hex.push(slice[j].toString(16).padStart(2, "0"));
|
|
1861
|
-
} else {
|
|
1862
|
-
hex.push(" ");
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
let ascii = "";
|
|
1866
|
-
for (let j = 0; j < slice.length; j++) {
|
|
1867
|
-
const byte = slice[j];
|
|
1868
|
-
ascii += byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : ".";
|
|
1869
|
-
}
|
|
1870
|
-
rows.push({ offset, hex, ascii });
|
|
1871
|
-
}
|
|
1872
|
-
return rows;
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
|
-
// ../../src/lib/utils/parquet-metadata.ts
|
|
1876
|
-
function mapParquetType(col) {
|
|
1877
|
-
const lt = col.logical_type;
|
|
1878
|
-
if (lt) {
|
|
1879
|
-
if (lt.type === "GEOMETRY" || lt.type === "GEOGRAPHY") return "GEOMETRY";
|
|
1880
|
-
if (lt.type === "STRING" || lt.type === "UTF8") return "VARCHAR";
|
|
1881
|
-
if (lt.type === "JSON") return "JSON";
|
|
1882
|
-
if (lt.type === "UUID") return "UUID";
|
|
1883
|
-
if (lt.type === "ENUM") return "VARCHAR";
|
|
1884
|
-
if (lt.type === "INT" || lt.type === "INTEGER") {
|
|
1885
|
-
const bits = lt.bitWidth ?? 32;
|
|
1886
|
-
const signed = lt.isSigned !== false;
|
|
1887
|
-
if (bits <= 8) return signed ? "TINYINT" : "UTINYINT";
|
|
1888
|
-
if (bits <= 16) return signed ? "SMALLINT" : "USMALLINT";
|
|
1889
|
-
if (bits <= 32) return signed ? "INTEGER" : "UINTEGER";
|
|
1890
|
-
return signed ? "BIGINT" : "UBIGINT";
|
|
1891
|
-
}
|
|
1892
|
-
if (lt.type === "DECIMAL") return `DECIMAL(${lt.precision ?? 18},${lt.scale ?? 0})`;
|
|
1893
|
-
if (lt.type === "DATE") return "DATE";
|
|
1894
|
-
if (lt.type === "TIME") return "TIME";
|
|
1895
|
-
if (lt.type === "TIMESTAMP") return "TIMESTAMP";
|
|
1896
|
-
if (lt.type === "BSON") return "BLOB";
|
|
1897
|
-
}
|
|
1898
|
-
const ct = col.converted_type;
|
|
1899
|
-
if (ct === "UTF8") return "VARCHAR";
|
|
1900
|
-
if (ct === "JSON") return "JSON";
|
|
1901
|
-
if (ct === "DATE") return "DATE";
|
|
1902
|
-
if (ct === "TIMESTAMP_MILLIS" || ct === "TIMESTAMP_MICROS") return "TIMESTAMP";
|
|
1903
|
-
if (ct === "DECIMAL") return `DECIMAL(${col.precision ?? 18},${col.scale ?? 0})`;
|
|
1904
|
-
if (ct === "INT_8") return "TINYINT";
|
|
1905
|
-
if (ct === "INT_16") return "SMALLINT";
|
|
1906
|
-
if (ct === "INT_32") return "INTEGER";
|
|
1907
|
-
if (ct === "INT_64") return "BIGINT";
|
|
1908
|
-
if (ct === "UINT_8") return "UTINYINT";
|
|
1909
|
-
if (ct === "UINT_16") return "USMALLINT";
|
|
1910
|
-
if (ct === "UINT_32") return "UINTEGER";
|
|
1911
|
-
if (ct === "UINT_64") return "UBIGINT";
|
|
1912
|
-
const pt = col.type;
|
|
1913
|
-
if (pt === "BOOLEAN") return "BOOLEAN";
|
|
1914
|
-
if (pt === "INT32") return "INTEGER";
|
|
1915
|
-
if (pt === "INT64") return "BIGINT";
|
|
1916
|
-
if (pt === "INT96") return "TIMESTAMP";
|
|
1917
|
-
if (pt === "FLOAT") return "FLOAT";
|
|
1918
|
-
if (pt === "DOUBLE") return "DOUBLE";
|
|
1919
|
-
if (pt === "BYTE_ARRAY") return "BLOB";
|
|
1920
|
-
if (pt === "FIXED_LEN_BYTE_ARRAY") return "BLOB";
|
|
1921
|
-
return "VARCHAR";
|
|
1922
|
-
}
|
|
1923
|
-
async function readParquetMetadata(url) {
|
|
1924
|
-
const { parquetMetadataAsync, asyncBufferFromUrl } = await import('hyparquet');
|
|
1925
|
-
const file = await asyncBufferFromUrl({ url });
|
|
1926
|
-
const metadata = await parquetMetadataAsync(file);
|
|
1927
|
-
const rowCount = metadata.row_groups.reduce(
|
|
1928
|
-
(sum, rg) => sum + Number(rg.num_rows),
|
|
1929
|
-
0
|
|
1930
|
-
);
|
|
1931
|
-
const schema = metadata.schema.slice(1).filter((col) => col.num_children === void 0).map((col) => ({
|
|
1932
|
-
name: col.name,
|
|
1933
|
-
type: mapParquetType(col)
|
|
1934
|
-
}));
|
|
1935
|
-
let geo = null;
|
|
1936
|
-
let legacyGeoParquet = false;
|
|
1937
|
-
const geoKv = metadata.key_value_metadata?.find((kv) => kv.key === "geo");
|
|
1938
|
-
if (geoKv) {
|
|
1939
|
-
try {
|
|
1940
|
-
const geoJson = JSON.parse(geoKv.value ?? "");
|
|
1941
|
-
if (geoJson.schema_version && !geoJson.version) {
|
|
1942
|
-
legacyGeoParquet = true;
|
|
1943
|
-
}
|
|
1944
|
-
geo = {
|
|
1945
|
-
primaryColumn: geoJson.primary_column ?? "geometry",
|
|
1946
|
-
columns: {}
|
|
1947
|
-
};
|
|
1948
|
-
if (geoJson.columns) {
|
|
1949
|
-
for (const [colName, colMeta] of Object.entries(geoJson.columns)) {
|
|
1950
|
-
geo.columns[colName] = {
|
|
1951
|
-
encoding: colMeta.encoding ?? "WKB",
|
|
1952
|
-
geometryTypes: colMeta.geometry_types ?? [],
|
|
1953
|
-
crs: colMeta.crs ?? null,
|
|
1954
|
-
bbox: colMeta.bbox
|
|
1955
|
-
};
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
} catch {
|
|
1959
|
-
}
|
|
1960
|
-
}
|
|
1961
|
-
const createdBy = metadata.created_by ?? null;
|
|
1962
|
-
const numRowGroups = metadata.row_groups.length;
|
|
1963
|
-
let compression = null;
|
|
1964
|
-
if (numRowGroups > 0 && metadata.row_groups[0].columns) {
|
|
1965
|
-
const codecs = /* @__PURE__ */ new Set();
|
|
1966
|
-
for (const col of metadata.row_groups[0].columns) {
|
|
1967
|
-
const codec = col.meta_data?.codec;
|
|
1968
|
-
if (codec) codecs.add(codec);
|
|
1969
|
-
}
|
|
1970
|
-
if (codecs.size === 1) {
|
|
1971
|
-
compression = [...codecs][0];
|
|
1972
|
-
} else if (codecs.size > 1) {
|
|
1973
|
-
compression = [...codecs].join(", ");
|
|
1974
|
-
}
|
|
1975
|
-
}
|
|
1976
|
-
return { rowCount, schema, geo, legacyGeoParquet, createdBy, numRowGroups, compression };
|
|
1977
|
-
}
|
|
1978
|
-
function extractEpsgFromGeoMeta(geo) {
|
|
1979
|
-
const primaryCol = geo.columns[geo.primaryColumn];
|
|
1980
|
-
if (!primaryCol?.crs) return null;
|
|
1981
|
-
const crs = primaryCol.crs;
|
|
1982
|
-
if (crs.type === "name" && crs.properties?.name?.includes("CRS84")) return null;
|
|
1983
|
-
if (crs.id?.authority === "EPSG") {
|
|
1984
|
-
const code = crs.id.code;
|
|
1985
|
-
if (WGS84_CODES.has(code)) return null;
|
|
1986
|
-
return `EPSG:${code}`;
|
|
1987
|
-
}
|
|
1988
|
-
return null;
|
|
1989
|
-
}
|
|
1990
|
-
function extractGeometryTypes(geo) {
|
|
1991
|
-
const primaryCol = geo.columns[geo.primaryColumn];
|
|
1992
|
-
if (!primaryCol?.geometryTypes?.length) return [];
|
|
1993
|
-
const typeMap = {
|
|
1994
|
-
Point: "point",
|
|
1995
|
-
LineString: "linestring",
|
|
1996
|
-
Polygon: "polygon",
|
|
1997
|
-
MultiPoint: "multipoint",
|
|
1998
|
-
MultiLineString: "multilinestring",
|
|
1999
|
-
MultiPolygon: "multipolygon"
|
|
2000
|
-
};
|
|
2001
|
-
const types = [];
|
|
2002
|
-
for (const raw of primaryCol.geometryTypes) {
|
|
2003
|
-
const base = raw.split(" ")[0];
|
|
2004
|
-
const mapped = typeMap[base];
|
|
2005
|
-
if (mapped && !types.includes(mapped)) types.push(mapped);
|
|
2006
|
-
}
|
|
2007
|
-
return types;
|
|
2008
|
-
}
|
|
2009
|
-
function extractBounds(geo) {
|
|
2010
|
-
const primaryCol = geo.columns[geo.primaryColumn];
|
|
2011
|
-
if (!primaryCol?.bbox || primaryCol.bbox.length < 4) return null;
|
|
2012
|
-
return [primaryCol.bbox[0], primaryCol.bbox[1], primaryCol.bbox[2], primaryCol.bbox[3]];
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
1077
|
// ../../src/lib/storage/providers.ts
|
|
2016
1078
|
var PROVIDERS = {
|
|
2017
1079
|
s3: {
|
|
@@ -2271,7 +1333,1190 @@ var PROVIDERS = {
|
|
|
2271
1333
|
endpointPlaceholder: "https://s3.gra.io.cloud.ovh.net",
|
|
2272
1334
|
schemes: []
|
|
2273
1335
|
}
|
|
2274
|
-
};
|
|
1336
|
+
};
|
|
1337
|
+
var PROVIDER_IDS = [
|
|
1338
|
+
"s3",
|
|
1339
|
+
"gcs",
|
|
1340
|
+
"r2",
|
|
1341
|
+
"azure",
|
|
1342
|
+
"b2",
|
|
1343
|
+
"digitalocean",
|
|
1344
|
+
"wasabi",
|
|
1345
|
+
"storj",
|
|
1346
|
+
"hetzner",
|
|
1347
|
+
"contabo",
|
|
1348
|
+
"linode",
|
|
1349
|
+
"ovhcloud",
|
|
1350
|
+
"minio"
|
|
1351
|
+
];
|
|
1352
|
+
function getProvider(id) {
|
|
1353
|
+
return PROVIDERS[id] ?? PROVIDERS.s3;
|
|
1354
|
+
}
|
|
1355
|
+
function buildEndpointFromTemplate(id, region) {
|
|
1356
|
+
const def = PROVIDERS[id];
|
|
1357
|
+
if (!def?.endpointTemplate) return "";
|
|
1358
|
+
return def.endpointTemplate.replace("{region}", region);
|
|
1359
|
+
}
|
|
1360
|
+
function buildProviderBaseUrl(provider, endpoint, bucket, region) {
|
|
1361
|
+
if (endpoint) {
|
|
1362
|
+
return `${endpoint.replace(/\/$/, "")}/${bucket}`;
|
|
1363
|
+
}
|
|
1364
|
+
const def = PROVIDERS[provider];
|
|
1365
|
+
if (def?.endpointTemplate) {
|
|
1366
|
+
const resolved = def.endpointTemplate.replace("{region}", region || def.defaultRegion);
|
|
1367
|
+
return `${resolved}/${bucket}`;
|
|
1368
|
+
}
|
|
1369
|
+
return `https://s3.${region || "us-east-1"}.amazonaws.com/${bucket}`;
|
|
1370
|
+
}
|
|
1371
|
+
function isGcsProvider(provider, endpoint) {
|
|
1372
|
+
return provider === "gcs" || !!endpoint && /storage\.googleapis\.com/i.test(endpoint);
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// ../../src/lib/storage/url-adapter.ts
|
|
1376
|
+
var UrlAdapter = class {
|
|
1377
|
+
supportsWrite = false;
|
|
1378
|
+
async read(url, offset, length, signal) {
|
|
1379
|
+
const headers = {};
|
|
1380
|
+
if (offset !== void 0 && length !== void 0) {
|
|
1381
|
+
headers.Range = `bytes=${offset}-${offset + length - 1}`;
|
|
1382
|
+
} else if (offset !== void 0) {
|
|
1383
|
+
headers.Range = `bytes=${offset}-`;
|
|
1384
|
+
}
|
|
1385
|
+
const res = await fetch(url, { headers, signal });
|
|
1386
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
1387
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
1388
|
+
}
|
|
1389
|
+
async head(url, signal) {
|
|
1390
|
+
const res = await fetch(url, { method: "HEAD", signal });
|
|
1391
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
1392
|
+
const name = url.split("/").pop()?.split("?")[0] || "file";
|
|
1393
|
+
const ext = name.includes(".") ? name.split(".").pop().toLowerCase() : "";
|
|
1394
|
+
return {
|
|
1395
|
+
name,
|
|
1396
|
+
path: url,
|
|
1397
|
+
is_dir: false,
|
|
1398
|
+
size: Number(res.headers.get("content-length") || 0),
|
|
1399
|
+
modified: new Date(res.headers.get("last-modified") || 0).getTime(),
|
|
1400
|
+
extension: ext
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
async list() {
|
|
1404
|
+
return [];
|
|
1405
|
+
}
|
|
1406
|
+
async put() {
|
|
1407
|
+
throw new Error("Write not supported for direct URL sources");
|
|
1408
|
+
}
|
|
1409
|
+
async delete() {
|
|
1410
|
+
throw new Error("Delete not supported for direct URL sources");
|
|
1411
|
+
}
|
|
1412
|
+
async deletePrefix() {
|
|
1413
|
+
throw new Error("Delete not supported for direct URL sources");
|
|
1414
|
+
}
|
|
1415
|
+
async copy() {
|
|
1416
|
+
throw new Error("Copy not supported for direct URL sources");
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
// ../../src/lib/utils/cloud-url.ts
|
|
1421
|
+
var AWS_REGION_RE = /^(us|eu|ap|sa|ca|me|af|il)-(north|south|east|west|central|northeast|southeast|northwest|southwest)-\d+/;
|
|
1422
|
+
function getNativeScheme(provider) {
|
|
1423
|
+
const def = PROVIDERS[provider];
|
|
1424
|
+
if (def?.schemes.length) return def.schemes[0];
|
|
1425
|
+
return "s3";
|
|
1426
|
+
}
|
|
1427
|
+
function safeDecodeURIComponent(s) {
|
|
1428
|
+
try {
|
|
1429
|
+
return decodeURIComponent(s);
|
|
1430
|
+
} catch {
|
|
1431
|
+
return s;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
function resolveCloudUrl(url) {
|
|
1435
|
+
const s3Match = url.match(/^s3[an]?:\/\/([^/]+)\/?(.*)$/);
|
|
1436
|
+
if (s3Match) {
|
|
1437
|
+
const [, bucket, key] = s3Match;
|
|
1438
|
+
const regionMatch = bucket.match(AWS_REGION_RE);
|
|
1439
|
+
const region = regionMatch ? regionMatch[0] : "us-east-1";
|
|
1440
|
+
const base = buildProviderBaseUrl("s3", "", bucket, region);
|
|
1441
|
+
return key ? `${base}/${key}` : base;
|
|
1442
|
+
}
|
|
1443
|
+
const gcsMatch = url.match(/^gcs?:\/\/([^/]+)\/?(.*)$/);
|
|
1444
|
+
if (gcsMatch) {
|
|
1445
|
+
const [, bucket, key] = gcsMatch;
|
|
1446
|
+
const base = buildProviderBaseUrl("gcs", "", bucket, "");
|
|
1447
|
+
return key ? `${base}/${key}` : base;
|
|
1448
|
+
}
|
|
1449
|
+
return url;
|
|
1450
|
+
}
|
|
1451
|
+
var SF_LABELS = {
|
|
1452
|
+
1: "uint",
|
|
1453
|
+
2: "int",
|
|
1454
|
+
3: "float",
|
|
1455
|
+
4: "void",
|
|
1456
|
+
5: "complex int",
|
|
1457
|
+
6: "complex float"
|
|
1458
|
+
};
|
|
1459
|
+
function safeClamp(v, lo, hi, fallback) {
|
|
1460
|
+
return Number.isFinite(v) ? Math.max(lo, Math.min(hi, v)) : fallback;
|
|
1461
|
+
}
|
|
1462
|
+
function clampBounds(b) {
|
|
1463
|
+
return {
|
|
1464
|
+
west: safeClamp(b.west, -180, 180, -180),
|
|
1465
|
+
south: safeClamp(b.south, -85.051129, 85.051129, -85.051129),
|
|
1466
|
+
east: safeClamp(b.east, -180, 180, 180),
|
|
1467
|
+
north: safeClamp(b.north, -85.051129, 85.051129, 85.051129)
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
function buildDataTypeLabel(sampleFormat, bitsPerSample) {
|
|
1471
|
+
return `${SF_LABELS[sampleFormat] ?? `sf${sampleFormat}`}${bitsPerSample ?? ""}`;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
// ../../src/lib/utils/column-types.ts
|
|
1475
|
+
var NUMBER_TYPES = [
|
|
1476
|
+
"TINYINT",
|
|
1477
|
+
"SMALLINT",
|
|
1478
|
+
"INTEGER",
|
|
1479
|
+
"BIGINT",
|
|
1480
|
+
"HUGEINT",
|
|
1481
|
+
"UTINYINT",
|
|
1482
|
+
"USMALLINT",
|
|
1483
|
+
"UINTEGER",
|
|
1484
|
+
"UBIGINT",
|
|
1485
|
+
"FLOAT",
|
|
1486
|
+
"DOUBLE",
|
|
1487
|
+
"DECIMAL",
|
|
1488
|
+
"NUMERIC",
|
|
1489
|
+
"REAL",
|
|
1490
|
+
"INT",
|
|
1491
|
+
"INT1",
|
|
1492
|
+
"INT2",
|
|
1493
|
+
"INT4",
|
|
1494
|
+
"INT8",
|
|
1495
|
+
"SIGNED",
|
|
1496
|
+
"SHORT",
|
|
1497
|
+
"LONG"
|
|
1498
|
+
];
|
|
1499
|
+
var STRING_TYPES = ["VARCHAR", "TEXT", "STRING", "CHAR", "BPCHAR", "NAME", "UUID", "ENUM"];
|
|
1500
|
+
var DATE_TYPES = [
|
|
1501
|
+
"DATE",
|
|
1502
|
+
"TIME",
|
|
1503
|
+
"TIMESTAMP",
|
|
1504
|
+
"TIMESTAMP_S",
|
|
1505
|
+
"TIMESTAMP_MS",
|
|
1506
|
+
"TIMESTAMP_NS",
|
|
1507
|
+
"TIMESTAMP WITH TIME ZONE",
|
|
1508
|
+
"TIMESTAMPTZ",
|
|
1509
|
+
"INTERVAL",
|
|
1510
|
+
"TIMESTAMP_TZ"
|
|
1511
|
+
];
|
|
1512
|
+
var BOOLEAN_TYPES = ["BOOLEAN", "BOOL", "LOGICAL"];
|
|
1513
|
+
var GEO_TYPES = [
|
|
1514
|
+
"GEOMETRY",
|
|
1515
|
+
"POINT",
|
|
1516
|
+
"LINESTRING",
|
|
1517
|
+
"POLYGON",
|
|
1518
|
+
"MULTIPOINT",
|
|
1519
|
+
"MULTILINESTRING",
|
|
1520
|
+
"MULTIPOLYGON",
|
|
1521
|
+
"GEOMETRYCOLLECTION",
|
|
1522
|
+
"WKB_GEOMETRY"
|
|
1523
|
+
];
|
|
1524
|
+
var BINARY_TYPES = ["BLOB", "BYTEA", "BINARY", "VARBINARY"];
|
|
1525
|
+
var JSON_TYPES = ["JSON", "JSONB"];
|
|
1526
|
+
function classifyType(duckdbType) {
|
|
1527
|
+
const upper = duckdbType.toUpperCase().trim();
|
|
1528
|
+
const base = upper.replace(/\(.*\)/, "").trim();
|
|
1529
|
+
if (NUMBER_TYPES.includes(base)) return "number";
|
|
1530
|
+
if (STRING_TYPES.includes(base)) return "string";
|
|
1531
|
+
if (DATE_TYPES.includes(base)) return "date";
|
|
1532
|
+
if (BOOLEAN_TYPES.includes(base)) return "boolean";
|
|
1533
|
+
if (GEO_TYPES.includes(base)) return "geo";
|
|
1534
|
+
if (BINARY_TYPES.includes(base)) return "binary";
|
|
1535
|
+
if (JSON_TYPES.includes(base)) return "json";
|
|
1536
|
+
if (base.startsWith("STRUCT") || base.startsWith("MAP") || base.startsWith("UNION"))
|
|
1537
|
+
return "json";
|
|
1538
|
+
if (base.endsWith("[]") || base.startsWith("LIST")) return "json";
|
|
1539
|
+
if (upper.includes("INT") || upper.includes("FLOAT") || upper.includes("DOUBLE") || upper.includes("DECIMAL") || upper.includes("NUMERIC"))
|
|
1540
|
+
return "number";
|
|
1541
|
+
if (upper.includes("CHAR") || upper.includes("TEXT") || upper.includes("STRING")) return "string";
|
|
1542
|
+
if (upper.includes("TIME") || upper.includes("DATE")) return "date";
|
|
1543
|
+
if (upper.includes("BOOL")) return "boolean";
|
|
1544
|
+
if (upper.includes("GEOMETRY") || upper.includes("GEO") || upper.includes("WKB")) return "geo";
|
|
1545
|
+
if (upper.includes("BLOB") || upper.includes("BINARY")) return "binary";
|
|
1546
|
+
if (upper.includes("JSON") || upper.includes("STRUCT") || upper.includes("MAP") || upper.includes("LIST"))
|
|
1547
|
+
return "json";
|
|
1548
|
+
return "other";
|
|
1549
|
+
}
|
|
1550
|
+
var TYPE_COLORS = {
|
|
1551
|
+
number: "text-blue-500",
|
|
1552
|
+
string: "text-green-500",
|
|
1553
|
+
date: "text-amber-500",
|
|
1554
|
+
boolean: "text-purple-500",
|
|
1555
|
+
geo: "text-teal-500",
|
|
1556
|
+
binary: "text-zinc-500",
|
|
1557
|
+
json: "text-orange-500",
|
|
1558
|
+
other: "text-zinc-400"
|
|
1559
|
+
};
|
|
1560
|
+
var TYPE_BADGE_CLASSES = {
|
|
1561
|
+
number: "bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20",
|
|
1562
|
+
string: "bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20",
|
|
1563
|
+
date: "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20",
|
|
1564
|
+
boolean: "bg-purple-500/10 text-purple-600 dark:text-purple-400 border-purple-500/20",
|
|
1565
|
+
geo: "bg-teal-500/10 text-teal-600 dark:text-teal-400 border-teal-500/20",
|
|
1566
|
+
binary: "bg-zinc-500/10 text-zinc-600 dark:text-zinc-400 border-zinc-500/20",
|
|
1567
|
+
json: "bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/20",
|
|
1568
|
+
other: "bg-zinc-500/10 text-zinc-500 dark:text-zinc-400 border-zinc-500/20"
|
|
1569
|
+
};
|
|
1570
|
+
var TYPE_LABELS = {
|
|
1571
|
+
number: "#",
|
|
1572
|
+
string: "Aa",
|
|
1573
|
+
date: "dt",
|
|
1574
|
+
boolean: "T/F",
|
|
1575
|
+
geo: "geo",
|
|
1576
|
+
binary: "01",
|
|
1577
|
+
json: "{}",
|
|
1578
|
+
other: "?"
|
|
1579
|
+
};
|
|
1580
|
+
function typeColor(category) {
|
|
1581
|
+
return TYPE_COLORS[category];
|
|
1582
|
+
}
|
|
1583
|
+
function typeBadgeClass(category) {
|
|
1584
|
+
return TYPE_BADGE_CLASSES[category];
|
|
1585
|
+
}
|
|
1586
|
+
function typeLabel(category) {
|
|
1587
|
+
return TYPE_LABELS[category];
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
// ../../src/lib/utils/error.ts
|
|
1591
|
+
function handleLoadError(err) {
|
|
1592
|
+
if (err instanceof DOMException && err.name === "AbortError") return null;
|
|
1593
|
+
return err instanceof Error ? err.message : String(err);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
// ../../src/lib/utils/format.ts
|
|
1597
|
+
function formatFileSize(bytes) {
|
|
1598
|
+
if (bytes < 0) return "0 B";
|
|
1599
|
+
if (bytes === 0) return "0 B";
|
|
1600
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
1601
|
+
const base = 1024;
|
|
1602
|
+
const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(base)), units.length - 1);
|
|
1603
|
+
const value = bytes / base ** exponent;
|
|
1604
|
+
if (exponent === 0) return `${bytes} B`;
|
|
1605
|
+
return `${value.toFixed(1)} ${units[exponent]}`;
|
|
1606
|
+
}
|
|
1607
|
+
function formatDate(timestamp) {
|
|
1608
|
+
if (!timestamp || timestamp <= 0 || !Number.isFinite(timestamp)) return "--";
|
|
1609
|
+
const date = new Date(timestamp);
|
|
1610
|
+
const now = Date.now();
|
|
1611
|
+
const diffMs = now - timestamp;
|
|
1612
|
+
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
1613
|
+
const diffMinutes = Math.floor(diffSeconds / 60);
|
|
1614
|
+
const diffHours = Math.floor(diffMinutes / 60);
|
|
1615
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
1616
|
+
if (diffSeconds < 60) return "Just now";
|
|
1617
|
+
if (diffMinutes < 60) return `${diffMinutes}m ago`;
|
|
1618
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
1619
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
1620
|
+
return date.toLocaleDateString(void 0, {
|
|
1621
|
+
year: "numeric",
|
|
1622
|
+
month: "short",
|
|
1623
|
+
day: "numeric"
|
|
1624
|
+
});
|
|
1625
|
+
}
|
|
1626
|
+
function getFileExtension(filename) {
|
|
1627
|
+
const lastDot = filename.lastIndexOf(".");
|
|
1628
|
+
if (lastDot <= 0) return "";
|
|
1629
|
+
return filename.slice(lastDot).toLowerCase();
|
|
1630
|
+
}
|
|
1631
|
+
function jsonReplacerBigInt(_key, value) {
|
|
1632
|
+
return typeof value === "bigint" ? value.toString() : value;
|
|
1633
|
+
}
|
|
1634
|
+
function formatValue(value) {
|
|
1635
|
+
if (value === null || value === void 0) return "NULL";
|
|
1636
|
+
if (value instanceof Date) return value.toISOString();
|
|
1637
|
+
if (typeof value === "bigint") return value.toString();
|
|
1638
|
+
if (typeof value === "object") return JSON.stringify(value, jsonReplacerBigInt);
|
|
1639
|
+
return String(value);
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
// ../../src/lib/utils/export.ts
|
|
1643
|
+
function formatCellValue(value) {
|
|
1644
|
+
if (value === null || value === void 0) return "";
|
|
1645
|
+
if (value instanceof Date) return value.toISOString();
|
|
1646
|
+
if (typeof value === "bigint") return value.toString();
|
|
1647
|
+
if (typeof value === "object") return JSON.stringify(value, jsonReplacerBigInt);
|
|
1648
|
+
return String(value);
|
|
1649
|
+
}
|
|
1650
|
+
function escapeCsvField(value) {
|
|
1651
|
+
if (value.includes(",") || value.includes('"') || value.includes("\n") || value.includes("\r")) {
|
|
1652
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
1653
|
+
}
|
|
1654
|
+
return value;
|
|
1655
|
+
}
|
|
1656
|
+
function serializeToCsv(columns, rows) {
|
|
1657
|
+
const header = columns.map(escapeCsvField).join(",");
|
|
1658
|
+
const body = rows.map((row) => columns.map((col) => escapeCsvField(formatCellValue(row[col]))).join(",")).join("\n");
|
|
1659
|
+
return `${header}
|
|
1660
|
+
${body}`;
|
|
1661
|
+
}
|
|
1662
|
+
function serializeToJson(columns, rows) {
|
|
1663
|
+
const data = rows.map((row) => {
|
|
1664
|
+
const obj = {};
|
|
1665
|
+
for (const col of columns) {
|
|
1666
|
+
const val = row[col];
|
|
1667
|
+
if (val instanceof Date) {
|
|
1668
|
+
obj[col] = val.toISOString();
|
|
1669
|
+
} else {
|
|
1670
|
+
obj[col] = val ?? null;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
return obj;
|
|
1674
|
+
});
|
|
1675
|
+
return JSON.stringify(data, jsonReplacerBigInt, 2);
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
// ../../src/lib/utils/file-sort.ts
|
|
1679
|
+
function sortFileEntries(entries, config) {
|
|
1680
|
+
const sorted = [...entries];
|
|
1681
|
+
const dir = config.direction === "asc" ? 1 : -1;
|
|
1682
|
+
sorted.sort((a, b) => {
|
|
1683
|
+
if (a.is_dir && !b.is_dir) return -1;
|
|
1684
|
+
if (!a.is_dir && b.is_dir) return 1;
|
|
1685
|
+
switch (config.field) {
|
|
1686
|
+
case "name":
|
|
1687
|
+
return dir * a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
1688
|
+
case "size":
|
|
1689
|
+
return dir * (a.size - b.size);
|
|
1690
|
+
case "modified":
|
|
1691
|
+
return dir * (a.modified - b.modified);
|
|
1692
|
+
case "extension":
|
|
1693
|
+
return dir * a.extension.localeCompare(b.extension, void 0, { sensitivity: "base" });
|
|
1694
|
+
default:
|
|
1695
|
+
return 0;
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
return sorted;
|
|
1699
|
+
}
|
|
1700
|
+
function toggleSortField(current, field) {
|
|
1701
|
+
if (current.field === field) {
|
|
1702
|
+
return { field, direction: current.direction === "asc" ? "desc" : "asc" };
|
|
1703
|
+
}
|
|
1704
|
+
return { field, direction: "asc" };
|
|
1705
|
+
}
|
|
1706
|
+
function normalizeGeomType(raw) {
|
|
1707
|
+
const s = raw.toUpperCase().replace(/\s+/g, "");
|
|
1708
|
+
if (s === "POINT") return "point";
|
|
1709
|
+
if (s === "LINESTRING") return "linestring";
|
|
1710
|
+
if (s === "POLYGON") return "polygon";
|
|
1711
|
+
if (s === "MULTIPOINT") return "multipoint";
|
|
1712
|
+
if (s === "MULTILINESTRING") return "multilinestring";
|
|
1713
|
+
if (s === "MULTIPOLYGON") return "multipolygon";
|
|
1714
|
+
return "polygon";
|
|
1715
|
+
}
|
|
1716
|
+
var EXTENSION_NAMES = {
|
|
1717
|
+
point: "geoarrow.point",
|
|
1718
|
+
linestring: "geoarrow.linestring",
|
|
1719
|
+
polygon: "geoarrow.polygon",
|
|
1720
|
+
multipoint: "geoarrow.multipoint",
|
|
1721
|
+
multilinestring: "geoarrow.multilinestring",
|
|
1722
|
+
multipolygon: "geoarrow.multipolygon"
|
|
1723
|
+
};
|
|
1724
|
+
function readWkbHeader(wkb) {
|
|
1725
|
+
if (wkb.length < 5) return null;
|
|
1726
|
+
const le = wkb[0] === 1;
|
|
1727
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1728
|
+
const rawType = dv.getUint32(1, le);
|
|
1729
|
+
let headerSize = 5;
|
|
1730
|
+
if ((rawType & 536870912) !== 0) headerSize += 4;
|
|
1731
|
+
const ewkbZ = (rawType & 2147483648) !== 0;
|
|
1732
|
+
const ewkbM = (rawType & 1073741824) !== 0;
|
|
1733
|
+
let type = rawType & 268435455;
|
|
1734
|
+
let isoZ = false;
|
|
1735
|
+
let isoM = false;
|
|
1736
|
+
if (type > 3e3) {
|
|
1737
|
+
isoZ = true;
|
|
1738
|
+
isoM = true;
|
|
1739
|
+
type -= 3e3;
|
|
1740
|
+
} else if (type > 2e3) {
|
|
1741
|
+
isoM = true;
|
|
1742
|
+
type -= 2e3;
|
|
1743
|
+
} else if (type > 1e3) {
|
|
1744
|
+
isoZ = true;
|
|
1745
|
+
type -= 1e3;
|
|
1746
|
+
}
|
|
1747
|
+
const dims = (ewkbZ || isoZ ? 1 : 0) + (ewkbM || isoM ? 1 : 0);
|
|
1748
|
+
const coordStride = (2 + dims) * 8;
|
|
1749
|
+
return { type, le, coordStride, dataOffset: headerSize };
|
|
1750
|
+
}
|
|
1751
|
+
function classifyWkbType(wkb) {
|
|
1752
|
+
const h = readWkbHeader(wkb);
|
|
1753
|
+
if (!h) return null;
|
|
1754
|
+
switch (h.type) {
|
|
1755
|
+
case 1:
|
|
1756
|
+
return "point";
|
|
1757
|
+
case 2:
|
|
1758
|
+
return "linestring";
|
|
1759
|
+
case 3:
|
|
1760
|
+
return "polygon";
|
|
1761
|
+
case 4:
|
|
1762
|
+
return "multipoint";
|
|
1763
|
+
case 5:
|
|
1764
|
+
return "multilinestring";
|
|
1765
|
+
case 6:
|
|
1766
|
+
return "multipolygon";
|
|
1767
|
+
default:
|
|
1768
|
+
return null;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
function newBounds() {
|
|
1772
|
+
return { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity };
|
|
1773
|
+
}
|
|
1774
|
+
function expandBounds(b, x, y) {
|
|
1775
|
+
if (Number.isNaN(x) || Number.isNaN(y)) return;
|
|
1776
|
+
if (x < b.minX) b.minX = x;
|
|
1777
|
+
if (y < b.minY) b.minY = y;
|
|
1778
|
+
if (x > b.maxX) b.maxX = x;
|
|
1779
|
+
if (y > b.maxY) b.maxY = y;
|
|
1780
|
+
}
|
|
1781
|
+
var coordField = new apacheArrow.Field("xy", new apacheArrow.Float64());
|
|
1782
|
+
var coordType = new apacheArrow.FixedSizeList(2, coordField);
|
|
1783
|
+
function makeCoordData(coords, numPoints) {
|
|
1784
|
+
const floatData = apacheArrow.makeData({ type: new apacheArrow.Float64(), length: coords.length, data: coords });
|
|
1785
|
+
return apacheArrow.makeData({ type: coordType, length: numPoints, nullCount: 0, child: floatData });
|
|
1786
|
+
}
|
|
1787
|
+
function buildPointData(wkbs, b) {
|
|
1788
|
+
const n = wkbs.length;
|
|
1789
|
+
const coords = new Float64Array(n * 2);
|
|
1790
|
+
for (let i = 0; i < n; i++) {
|
|
1791
|
+
const wkb = wkbs[i];
|
|
1792
|
+
const h = readWkbHeader(wkb);
|
|
1793
|
+
if (!h || h.type !== 1) {
|
|
1794
|
+
coords[i * 2] = 0;
|
|
1795
|
+
coords[i * 2 + 1] = 0;
|
|
1796
|
+
continue;
|
|
1797
|
+
}
|
|
1798
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1799
|
+
const x = dv.getFloat64(h.dataOffset, h.le);
|
|
1800
|
+
const y = dv.getFloat64(h.dataOffset + 8, h.le);
|
|
1801
|
+
coords[i * 2] = x;
|
|
1802
|
+
coords[i * 2 + 1] = y;
|
|
1803
|
+
expandBounds(b, x, y);
|
|
1804
|
+
}
|
|
1805
|
+
return makeCoordData(coords, n);
|
|
1806
|
+
}
|
|
1807
|
+
function buildLineStringData(wkbs, b) {
|
|
1808
|
+
const n = wkbs.length;
|
|
1809
|
+
const geomOffsets = new Int32Array(n + 1);
|
|
1810
|
+
let totalCoords = 0;
|
|
1811
|
+
for (let i = 0; i < n; i++) {
|
|
1812
|
+
geomOffsets[i] = totalCoords;
|
|
1813
|
+
const h = readWkbHeader(wkbs[i]);
|
|
1814
|
+
if (!h || h.type !== 2) continue;
|
|
1815
|
+
const dv = new DataView(wkbs[i].buffer, wkbs[i].byteOffset, wkbs[i].byteLength);
|
|
1816
|
+
const numPts = dv.getUint32(h.dataOffset, h.le);
|
|
1817
|
+
totalCoords += numPts;
|
|
1818
|
+
}
|
|
1819
|
+
geomOffsets[n] = totalCoords;
|
|
1820
|
+
const coords = new Float64Array(totalCoords * 2);
|
|
1821
|
+
let ci = 0;
|
|
1822
|
+
for (const wkb of wkbs) {
|
|
1823
|
+
const h = readWkbHeader(wkb);
|
|
1824
|
+
if (!h || h.type !== 2) continue;
|
|
1825
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1826
|
+
const numPts = dv.getUint32(h.dataOffset, h.le);
|
|
1827
|
+
let off = h.dataOffset + 4;
|
|
1828
|
+
for (let j = 0; j < numPts; j++) {
|
|
1829
|
+
const x = dv.getFloat64(off, h.le);
|
|
1830
|
+
const y = dv.getFloat64(off + 8, h.le);
|
|
1831
|
+
coords[ci++] = x;
|
|
1832
|
+
coords[ci++] = y;
|
|
1833
|
+
expandBounds(b, x, y);
|
|
1834
|
+
off += h.coordStride;
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
const fslData = makeCoordData(coords, totalCoords);
|
|
1838
|
+
const listType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1839
|
+
return apacheArrow.makeData({
|
|
1840
|
+
type: listType,
|
|
1841
|
+
length: n,
|
|
1842
|
+
nullCount: 0,
|
|
1843
|
+
valueOffsets: geomOffsets,
|
|
1844
|
+
child: fslData
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1847
|
+
function buildPolygonData(wkbs, b) {
|
|
1848
|
+
const n = wkbs.length;
|
|
1849
|
+
const geomOffsets = new Int32Array(n + 1);
|
|
1850
|
+
let totalRings = 0;
|
|
1851
|
+
let totalCoords = 0;
|
|
1852
|
+
for (let i = 0; i < n; i++) {
|
|
1853
|
+
geomOffsets[i] = totalRings;
|
|
1854
|
+
const h = readWkbHeader(wkbs[i]);
|
|
1855
|
+
if (!h || h.type !== 3) continue;
|
|
1856
|
+
const dv = new DataView(wkbs[i].buffer, wkbs[i].byteOffset, wkbs[i].byteLength);
|
|
1857
|
+
const numRings = dv.getUint32(h.dataOffset, h.le);
|
|
1858
|
+
let off = h.dataOffset + 4;
|
|
1859
|
+
for (let r = 0; r < numRings; r++) {
|
|
1860
|
+
const numPts = dv.getUint32(off, h.le);
|
|
1861
|
+
off += 4 + numPts * h.coordStride;
|
|
1862
|
+
totalCoords += numPts;
|
|
1863
|
+
totalRings++;
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
geomOffsets[n] = totalRings;
|
|
1867
|
+
const ringOffsets = new Int32Array(totalRings + 1);
|
|
1868
|
+
const coords = new Float64Array(totalCoords * 2);
|
|
1869
|
+
let ri = 0;
|
|
1870
|
+
let ci = 0;
|
|
1871
|
+
for (const wkb of wkbs) {
|
|
1872
|
+
const h = readWkbHeader(wkb);
|
|
1873
|
+
if (!h || h.type !== 3) continue;
|
|
1874
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1875
|
+
const numRings = dv.getUint32(h.dataOffset, h.le);
|
|
1876
|
+
let off = h.dataOffset + 4;
|
|
1877
|
+
for (let r = 0; r < numRings; r++) {
|
|
1878
|
+
ringOffsets[ri++] = ci >> 1;
|
|
1879
|
+
const numPts = dv.getUint32(off, h.le);
|
|
1880
|
+
off += 4;
|
|
1881
|
+
for (let j = 0; j < numPts; j++) {
|
|
1882
|
+
const x = dv.getFloat64(off, h.le);
|
|
1883
|
+
const y = dv.getFloat64(off + 8, h.le);
|
|
1884
|
+
coords[ci++] = x;
|
|
1885
|
+
coords[ci++] = y;
|
|
1886
|
+
expandBounds(b, x, y);
|
|
1887
|
+
off += h.coordStride;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
ringOffsets[totalRings] = ci >> 1;
|
|
1892
|
+
const coordCount = ci >> 1;
|
|
1893
|
+
const fslData = makeCoordData(coords, coordCount);
|
|
1894
|
+
const ringListType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1895
|
+
const ringListData = apacheArrow.makeData({
|
|
1896
|
+
type: ringListType,
|
|
1897
|
+
length: totalRings,
|
|
1898
|
+
nullCount: 0,
|
|
1899
|
+
valueOffsets: ringOffsets,
|
|
1900
|
+
child: fslData
|
|
1901
|
+
});
|
|
1902
|
+
const polyType = new apacheArrow.List(new apacheArrow.Field("rings", ringListType));
|
|
1903
|
+
return apacheArrow.makeData({
|
|
1904
|
+
type: polyType,
|
|
1905
|
+
length: n,
|
|
1906
|
+
nullCount: 0,
|
|
1907
|
+
valueOffsets: geomOffsets,
|
|
1908
|
+
child: ringListData
|
|
1909
|
+
});
|
|
1910
|
+
}
|
|
1911
|
+
function buildMultiPointData(wkbs, b) {
|
|
1912
|
+
const n = wkbs.length;
|
|
1913
|
+
const geomOffsets = new Int32Array(n + 1);
|
|
1914
|
+
let totalCoords = 0;
|
|
1915
|
+
for (let i = 0; i < n; i++) {
|
|
1916
|
+
geomOffsets[i] = totalCoords;
|
|
1917
|
+
const h = readWkbHeader(wkbs[i]);
|
|
1918
|
+
if (!h || h.type !== 4) continue;
|
|
1919
|
+
const dv = new DataView(wkbs[i].buffer, wkbs[i].byteOffset, wkbs[i].byteLength);
|
|
1920
|
+
totalCoords += dv.getUint32(h.dataOffset, h.le);
|
|
1921
|
+
}
|
|
1922
|
+
geomOffsets[n] = totalCoords;
|
|
1923
|
+
const coords = new Float64Array(totalCoords * 2);
|
|
1924
|
+
let ci = 0;
|
|
1925
|
+
for (const wkb of wkbs) {
|
|
1926
|
+
const h = readWkbHeader(wkb);
|
|
1927
|
+
if (!h || h.type !== 4) continue;
|
|
1928
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1929
|
+
const numPts = dv.getUint32(h.dataOffset, h.le);
|
|
1930
|
+
let off = h.dataOffset + 4;
|
|
1931
|
+
for (let j = 0; j < numPts; j++) {
|
|
1932
|
+
const innerH = readWkbHeader(
|
|
1933
|
+
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1934
|
+
);
|
|
1935
|
+
if (innerH) {
|
|
1936
|
+
const x = dv.getFloat64(off + innerH.dataOffset, innerH.le);
|
|
1937
|
+
const y = dv.getFloat64(off + innerH.dataOffset + 8, innerH.le);
|
|
1938
|
+
coords[ci++] = x;
|
|
1939
|
+
coords[ci++] = y;
|
|
1940
|
+
expandBounds(b, x, y);
|
|
1941
|
+
off += innerH.dataOffset + innerH.coordStride;
|
|
1942
|
+
} else {
|
|
1943
|
+
coords[ci++] = 0;
|
|
1944
|
+
coords[ci++] = 0;
|
|
1945
|
+
off += 21;
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
const fslData = makeCoordData(coords, totalCoords);
|
|
1950
|
+
const listType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
1951
|
+
return apacheArrow.makeData({
|
|
1952
|
+
type: listType,
|
|
1953
|
+
length: n,
|
|
1954
|
+
nullCount: 0,
|
|
1955
|
+
valueOffsets: geomOffsets,
|
|
1956
|
+
child: fslData
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
function buildMultiLineStringData(wkbs, b) {
|
|
1960
|
+
const n = wkbs.length;
|
|
1961
|
+
const geomOffsetsArr = [0];
|
|
1962
|
+
let totalLines = 0;
|
|
1963
|
+
let totalCoords = 0;
|
|
1964
|
+
for (const wkb of wkbs) {
|
|
1965
|
+
const h = readWkbHeader(wkb);
|
|
1966
|
+
if (!h || h.type !== 5) {
|
|
1967
|
+
geomOffsetsArr.push(totalLines);
|
|
1968
|
+
continue;
|
|
1969
|
+
}
|
|
1970
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1971
|
+
const numLines = dv.getUint32(h.dataOffset, h.le);
|
|
1972
|
+
let off = h.dataOffset + 4;
|
|
1973
|
+
for (let l = 0; l < numLines; l++) {
|
|
1974
|
+
const innerH = readWkbHeader(
|
|
1975
|
+
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
1976
|
+
);
|
|
1977
|
+
if (!innerH) break;
|
|
1978
|
+
const innerDv = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off);
|
|
1979
|
+
const numPts = innerDv.getUint32(innerH.dataOffset, innerH.le);
|
|
1980
|
+
totalCoords += numPts;
|
|
1981
|
+
off += innerH.dataOffset + 4 + numPts * innerH.coordStride;
|
|
1982
|
+
totalLines++;
|
|
1983
|
+
}
|
|
1984
|
+
geomOffsetsArr.push(totalLines);
|
|
1985
|
+
}
|
|
1986
|
+
const geomOffsets = new Int32Array(geomOffsetsArr);
|
|
1987
|
+
const lineOffsets = new Int32Array(totalLines + 1);
|
|
1988
|
+
const coords = new Float64Array(totalCoords * 2);
|
|
1989
|
+
let li = 0;
|
|
1990
|
+
let ci = 0;
|
|
1991
|
+
for (const wkb of wkbs) {
|
|
1992
|
+
const h = readWkbHeader(wkb);
|
|
1993
|
+
if (!h || h.type !== 5) continue;
|
|
1994
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
1995
|
+
const numLines = dv.getUint32(h.dataOffset, h.le);
|
|
1996
|
+
let off = h.dataOffset + 4;
|
|
1997
|
+
for (let l = 0; l < numLines; l++) {
|
|
1998
|
+
lineOffsets[li++] = ci >> 1;
|
|
1999
|
+
const innerH = readWkbHeader(
|
|
2000
|
+
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
2001
|
+
);
|
|
2002
|
+
if (!innerH) break;
|
|
2003
|
+
const numPts = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off).getUint32(
|
|
2004
|
+
innerH.dataOffset,
|
|
2005
|
+
innerH.le
|
|
2006
|
+
);
|
|
2007
|
+
let ptOff = off + innerH.dataOffset + 4;
|
|
2008
|
+
for (let j = 0; j < numPts; j++) {
|
|
2009
|
+
const x = dv.getFloat64(ptOff, innerH.le);
|
|
2010
|
+
const y = dv.getFloat64(ptOff + 8, innerH.le);
|
|
2011
|
+
coords[ci++] = x;
|
|
2012
|
+
coords[ci++] = y;
|
|
2013
|
+
expandBounds(b, x, y);
|
|
2014
|
+
ptOff += innerH.coordStride;
|
|
2015
|
+
}
|
|
2016
|
+
off = ptOff;
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
lineOffsets[totalLines] = ci >> 1;
|
|
2020
|
+
const fslData = makeCoordData(coords, ci >> 1);
|
|
2021
|
+
const lineListType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
2022
|
+
const lineListData = apacheArrow.makeData({
|
|
2023
|
+
type: lineListType,
|
|
2024
|
+
length: totalLines,
|
|
2025
|
+
nullCount: 0,
|
|
2026
|
+
valueOffsets: lineOffsets,
|
|
2027
|
+
child: fslData
|
|
2028
|
+
});
|
|
2029
|
+
const multiLineType = new apacheArrow.List(new apacheArrow.Field("lines", lineListType));
|
|
2030
|
+
return apacheArrow.makeData({
|
|
2031
|
+
type: multiLineType,
|
|
2032
|
+
length: n,
|
|
2033
|
+
nullCount: 0,
|
|
2034
|
+
valueOffsets: geomOffsets,
|
|
2035
|
+
child: lineListData
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
function buildMultiPolygonData(wkbs, b) {
|
|
2039
|
+
const n = wkbs.length;
|
|
2040
|
+
const geomOffsetsArr = [0];
|
|
2041
|
+
let totalPolys = 0;
|
|
2042
|
+
let totalRings = 0;
|
|
2043
|
+
let totalCoords = 0;
|
|
2044
|
+
for (const wkb of wkbs) {
|
|
2045
|
+
const h = readWkbHeader(wkb);
|
|
2046
|
+
if (!h || h.type !== 6) {
|
|
2047
|
+
geomOffsetsArr.push(totalPolys);
|
|
2048
|
+
continue;
|
|
2049
|
+
}
|
|
2050
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
2051
|
+
const numPolys = dv.getUint32(h.dataOffset, h.le);
|
|
2052
|
+
let off = h.dataOffset + 4;
|
|
2053
|
+
for (let p = 0; p < numPolys; p++) {
|
|
2054
|
+
const innerH = readWkbHeader(
|
|
2055
|
+
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
2056
|
+
);
|
|
2057
|
+
if (!innerH) break;
|
|
2058
|
+
const innerDv = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off);
|
|
2059
|
+
const numRings = innerDv.getUint32(innerH.dataOffset, innerH.le);
|
|
2060
|
+
let ringOff = innerH.dataOffset + 4;
|
|
2061
|
+
for (let r = 0; r < numRings; r++) {
|
|
2062
|
+
const numPts = innerDv.getUint32(ringOff, innerH.le);
|
|
2063
|
+
ringOff += 4 + numPts * innerH.coordStride;
|
|
2064
|
+
totalCoords += numPts;
|
|
2065
|
+
totalRings++;
|
|
2066
|
+
}
|
|
2067
|
+
off += ringOff;
|
|
2068
|
+
totalPolys++;
|
|
2069
|
+
}
|
|
2070
|
+
geomOffsetsArr.push(totalPolys);
|
|
2071
|
+
}
|
|
2072
|
+
const geomOffsets = new Int32Array(geomOffsetsArr);
|
|
2073
|
+
const polyOffsets = new Int32Array(totalPolys + 1);
|
|
2074
|
+
const ringOffsets = new Int32Array(totalRings + 1);
|
|
2075
|
+
const coords = new Float64Array(totalCoords * 2);
|
|
2076
|
+
let pi = 0;
|
|
2077
|
+
let ri = 0;
|
|
2078
|
+
let ci = 0;
|
|
2079
|
+
for (const wkb of wkbs) {
|
|
2080
|
+
const h = readWkbHeader(wkb);
|
|
2081
|
+
if (!h || h.type !== 6) continue;
|
|
2082
|
+
const dv = new DataView(wkb.buffer, wkb.byteOffset, wkb.byteLength);
|
|
2083
|
+
const numPolys = dv.getUint32(h.dataOffset, h.le);
|
|
2084
|
+
let off = h.dataOffset + 4;
|
|
2085
|
+
for (let p = 0; p < numPolys; p++) {
|
|
2086
|
+
polyOffsets[pi++] = ri;
|
|
2087
|
+
const innerH = readWkbHeader(
|
|
2088
|
+
new Uint8Array(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off)
|
|
2089
|
+
);
|
|
2090
|
+
if (!innerH) break;
|
|
2091
|
+
const innerDv = new DataView(wkb.buffer, wkb.byteOffset + off, wkb.byteLength - off);
|
|
2092
|
+
const numRings = innerDv.getUint32(innerH.dataOffset, innerH.le);
|
|
2093
|
+
let ringOff = off + innerH.dataOffset + 4;
|
|
2094
|
+
for (let r = 0; r < numRings; r++) {
|
|
2095
|
+
ringOffsets[ri++] = ci >> 1;
|
|
2096
|
+
const numPts = dv.getUint32(ringOff, innerH.le);
|
|
2097
|
+
ringOff += 4;
|
|
2098
|
+
for (let j = 0; j < numPts; j++) {
|
|
2099
|
+
const x = dv.getFloat64(ringOff, innerH.le);
|
|
2100
|
+
const y = dv.getFloat64(ringOff + 8, innerH.le);
|
|
2101
|
+
coords[ci++] = x;
|
|
2102
|
+
coords[ci++] = y;
|
|
2103
|
+
expandBounds(b, x, y);
|
|
2104
|
+
ringOff += innerH.coordStride;
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
off = ringOff;
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
polyOffsets[totalPolys] = ri;
|
|
2111
|
+
ringOffsets[totalRings] = ci >> 1;
|
|
2112
|
+
const fslData = makeCoordData(coords, ci >> 1);
|
|
2113
|
+
const ringListType = new apacheArrow.List(new apacheArrow.Field("vertices", coordType));
|
|
2114
|
+
const ringListData = apacheArrow.makeData({
|
|
2115
|
+
type: ringListType,
|
|
2116
|
+
length: totalRings,
|
|
2117
|
+
nullCount: 0,
|
|
2118
|
+
valueOffsets: ringOffsets,
|
|
2119
|
+
child: fslData
|
|
2120
|
+
});
|
|
2121
|
+
const polyListType = new apacheArrow.List(new apacheArrow.Field("rings", ringListType));
|
|
2122
|
+
const polyListData = apacheArrow.makeData({
|
|
2123
|
+
type: polyListType,
|
|
2124
|
+
length: totalPolys,
|
|
2125
|
+
nullCount: 0,
|
|
2126
|
+
valueOffsets: polyOffsets,
|
|
2127
|
+
child: ringListData
|
|
2128
|
+
});
|
|
2129
|
+
const multiPolyType = new apacheArrow.List(new apacheArrow.Field("polygons", polyListType));
|
|
2130
|
+
return apacheArrow.makeData({
|
|
2131
|
+
type: multiPolyType,
|
|
2132
|
+
length: n,
|
|
2133
|
+
nullCount: 0,
|
|
2134
|
+
valueOffsets: geomOffsets,
|
|
2135
|
+
child: polyListData
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
function buildAttributeColumns(indices, attributes) {
|
|
2139
|
+
const n = indices.length;
|
|
2140
|
+
const fields = [];
|
|
2141
|
+
const dataArr = [];
|
|
2142
|
+
for (const [name, col] of attributes) {
|
|
2143
|
+
const { values } = col;
|
|
2144
|
+
let isNumeric = true;
|
|
2145
|
+
const sampleEnd = Math.min(n, 100);
|
|
2146
|
+
for (let i = 0; i < sampleEnd; i++) {
|
|
2147
|
+
if (values[indices[i]] != null && typeof values[indices[i]] !== "number") {
|
|
2148
|
+
isNumeric = false;
|
|
2149
|
+
break;
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
if (isNumeric) {
|
|
2153
|
+
const arr = new Float64Array(n);
|
|
2154
|
+
for (let i = 0; i < n; i++) arr[i] = values[indices[i]] ?? NaN;
|
|
2155
|
+
const data = apacheArrow.makeData({ type: new apacheArrow.Float64(), length: n, data: arr });
|
|
2156
|
+
fields.push(new apacheArrow.Field(name, new apacheArrow.Float64(), true));
|
|
2157
|
+
dataArr.push(data);
|
|
2158
|
+
} else {
|
|
2159
|
+
const encoder = new TextEncoder();
|
|
2160
|
+
const offsets = new Int32Array(n + 1);
|
|
2161
|
+
let totalBytes = 0;
|
|
2162
|
+
const strParts = [];
|
|
2163
|
+
for (let i = 0; i < n; i++) {
|
|
2164
|
+
offsets[i] = totalBytes;
|
|
2165
|
+
const s = values[indices[i]] != null ? String(values[indices[i]]) : "";
|
|
2166
|
+
const encoded = encoder.encode(s);
|
|
2167
|
+
strParts.push(encoded);
|
|
2168
|
+
totalBytes += encoded.length;
|
|
2169
|
+
}
|
|
2170
|
+
offsets[n] = totalBytes;
|
|
2171
|
+
const valueBuffer = new Uint8Array(totalBytes);
|
|
2172
|
+
let pos = 0;
|
|
2173
|
+
for (const sv of strParts) {
|
|
2174
|
+
valueBuffer.set(sv, pos);
|
|
2175
|
+
pos += sv.length;
|
|
2176
|
+
}
|
|
2177
|
+
const data = apacheArrow.makeData({
|
|
2178
|
+
type: new apacheArrow.Utf8(),
|
|
2179
|
+
length: n,
|
|
2180
|
+
valueOffsets: offsets,
|
|
2181
|
+
data: valueBuffer
|
|
2182
|
+
});
|
|
2183
|
+
fields.push(new apacheArrow.Field(name, new apacheArrow.Utf8(), true));
|
|
2184
|
+
dataArr.push(data);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
return { fields, data: dataArr };
|
|
2188
|
+
}
|
|
2189
|
+
function buildSingleTable(geomType, wkbs, indices, attributes, b) {
|
|
2190
|
+
const n = wkbs.length;
|
|
2191
|
+
let geomData;
|
|
2192
|
+
switch (geomType) {
|
|
2193
|
+
case "point":
|
|
2194
|
+
geomData = buildPointData(wkbs, b);
|
|
2195
|
+
break;
|
|
2196
|
+
case "linestring":
|
|
2197
|
+
geomData = buildLineStringData(wkbs, b);
|
|
2198
|
+
break;
|
|
2199
|
+
case "polygon":
|
|
2200
|
+
geomData = buildPolygonData(wkbs, b);
|
|
2201
|
+
break;
|
|
2202
|
+
case "multipoint":
|
|
2203
|
+
geomData = buildMultiPointData(wkbs, b);
|
|
2204
|
+
break;
|
|
2205
|
+
case "multilinestring":
|
|
2206
|
+
geomData = buildMultiLineStringData(wkbs, b);
|
|
2207
|
+
break;
|
|
2208
|
+
case "multipolygon":
|
|
2209
|
+
geomData = buildMultiPolygonData(wkbs, b);
|
|
2210
|
+
break;
|
|
2211
|
+
}
|
|
2212
|
+
const extensionName = EXTENSION_NAMES[geomType];
|
|
2213
|
+
const geomMetadata = /* @__PURE__ */ new Map([
|
|
2214
|
+
["ARROW:extension:name", extensionName],
|
|
2215
|
+
[
|
|
2216
|
+
"ARROW:extension:metadata",
|
|
2217
|
+
JSON.stringify({
|
|
2218
|
+
crs: {
|
|
2219
|
+
type: "name",
|
|
2220
|
+
properties: { name: "urn:ogc:def:crs:OGC:1.3:CRS84" }
|
|
2221
|
+
}
|
|
2222
|
+
})
|
|
2223
|
+
]
|
|
2224
|
+
]);
|
|
2225
|
+
const geomField = new apacheArrow.Field("geometry", geomData.type, false, geomMetadata);
|
|
2226
|
+
const attrCols = buildAttributeColumns(indices, attributes);
|
|
2227
|
+
const fields = [geomField, ...attrCols.fields];
|
|
2228
|
+
const childrenData = [geomData, ...attrCols.data];
|
|
2229
|
+
const arrowSchema = new apacheArrow.Schema(fields);
|
|
2230
|
+
const structType = new apacheArrow.Struct(fields);
|
|
2231
|
+
const structData = apacheArrow.makeData({
|
|
2232
|
+
type: structType,
|
|
2233
|
+
length: n,
|
|
2234
|
+
nullCount: 0,
|
|
2235
|
+
children: childrenData
|
|
2236
|
+
});
|
|
2237
|
+
const batch = new apacheArrow.RecordBatch(arrowSchema, structData);
|
|
2238
|
+
const table = new apacheArrow.Table(arrowSchema, batch);
|
|
2239
|
+
return {
|
|
2240
|
+
table,
|
|
2241
|
+
geometryType: geomType,
|
|
2242
|
+
bounds: [b.minX, b.minY, b.maxX, b.maxY],
|
|
2243
|
+
sourceIndices: indices
|
|
2244
|
+
};
|
|
2245
|
+
}
|
|
2246
|
+
function buildGeoArrowTables(wkbArrays, attributes, knownGeomType) {
|
|
2247
|
+
if (wkbArrays.length === 0) return [];
|
|
2248
|
+
if (knownGeomType) {
|
|
2249
|
+
const globalBounds2 = newBounds();
|
|
2250
|
+
const indices = Array.from({ length: wkbArrays.length }, (_, i) => i);
|
|
2251
|
+
const result = buildSingleTable(knownGeomType, wkbArrays, indices, attributes, globalBounds2);
|
|
2252
|
+
return [result];
|
|
2253
|
+
}
|
|
2254
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2255
|
+
for (let i = 0; i < wkbArrays.length; i++) {
|
|
2256
|
+
const geomType = classifyWkbType(wkbArrays[i]);
|
|
2257
|
+
if (!geomType) continue;
|
|
2258
|
+
let group = groups.get(geomType);
|
|
2259
|
+
if (!group) {
|
|
2260
|
+
group = { wkbs: [], indices: [] };
|
|
2261
|
+
groups.set(geomType, group);
|
|
2262
|
+
}
|
|
2263
|
+
group.wkbs.push(wkbArrays[i]);
|
|
2264
|
+
group.indices.push(i);
|
|
2265
|
+
}
|
|
2266
|
+
if (groups.size === 0) return [];
|
|
2267
|
+
const globalBounds = newBounds();
|
|
2268
|
+
const results = [];
|
|
2269
|
+
for (const [geomType, { wkbs, indices }] of groups) {
|
|
2270
|
+
const result = buildSingleTable(geomType, wkbs, indices, attributes, globalBounds);
|
|
2271
|
+
results.push(result);
|
|
2272
|
+
}
|
|
2273
|
+
const mergedBounds = [
|
|
2274
|
+
globalBounds.minX,
|
|
2275
|
+
globalBounds.minY,
|
|
2276
|
+
globalBounds.maxX,
|
|
2277
|
+
globalBounds.maxY
|
|
2278
|
+
];
|
|
2279
|
+
for (const r of results) r.bounds = mergedBounds;
|
|
2280
|
+
return results;
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
// ../../src/lib/utils/hex.ts
|
|
2284
|
+
function generateHexDump(data, bytesPerRow = 16) {
|
|
2285
|
+
const rows = [];
|
|
2286
|
+
for (let i = 0; i < data.length; i += bytesPerRow) {
|
|
2287
|
+
const slice = data.slice(i, i + bytesPerRow);
|
|
2288
|
+
const offset = i.toString(16).padStart(8, "0");
|
|
2289
|
+
const hex = [];
|
|
2290
|
+
for (let j = 0; j < bytesPerRow; j++) {
|
|
2291
|
+
if (j < slice.length) {
|
|
2292
|
+
hex.push(slice[j].toString(16).padStart(2, "0"));
|
|
2293
|
+
} else {
|
|
2294
|
+
hex.push(" ");
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
let ascii = "";
|
|
2298
|
+
for (let j = 0; j < slice.length; j++) {
|
|
2299
|
+
const byte = slice[j];
|
|
2300
|
+
ascii += byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : ".";
|
|
2301
|
+
}
|
|
2302
|
+
rows.push({ offset, hex, ascii });
|
|
2303
|
+
}
|
|
2304
|
+
return rows;
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
// ../../src/lib/utils/local-storage.ts
|
|
2308
|
+
function loadFromStorage(key, defaultValue) {
|
|
2309
|
+
if (typeof window === "undefined") return defaultValue;
|
|
2310
|
+
try {
|
|
2311
|
+
const raw = localStorage.getItem(key);
|
|
2312
|
+
if (raw) return JSON.parse(raw);
|
|
2313
|
+
} catch {
|
|
2314
|
+
}
|
|
2315
|
+
return defaultValue;
|
|
2316
|
+
}
|
|
2317
|
+
function persistToStorage(key, value) {
|
|
2318
|
+
if (typeof window === "undefined") return;
|
|
2319
|
+
try {
|
|
2320
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
2321
|
+
} catch {
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
// ../../src/lib/utils/markdown-sql.ts
|
|
2326
|
+
async function parseMarkdownDocument(markdown) {
|
|
2327
|
+
let frontmatter = {};
|
|
2328
|
+
let content = markdown;
|
|
2329
|
+
const fmMatch = markdown.match(/^---\n([\s\S]*?)\n---\n/);
|
|
2330
|
+
if (fmMatch) {
|
|
2331
|
+
try {
|
|
2332
|
+
const { default: YAML } = await import('yaml');
|
|
2333
|
+
frontmatter = YAML.parse(fmMatch[1]) || {};
|
|
2334
|
+
} catch {
|
|
2335
|
+
}
|
|
2336
|
+
content = markdown.slice(fmMatch[0].length);
|
|
2337
|
+
}
|
|
2338
|
+
const sqlBlocks = [];
|
|
2339
|
+
const lines = content.split("\n");
|
|
2340
|
+
let i = 0;
|
|
2341
|
+
while (i < lines.length) {
|
|
2342
|
+
const line = lines[i];
|
|
2343
|
+
const match = line.match(/^```sql\s+(\w[\w-]*)\s*$/);
|
|
2344
|
+
if (match) {
|
|
2345
|
+
const name = match[1];
|
|
2346
|
+
const startLine = i;
|
|
2347
|
+
const sqlLines = [];
|
|
2348
|
+
i++;
|
|
2349
|
+
while (i < lines.length && lines[i] !== "```") {
|
|
2350
|
+
sqlLines.push(lines[i]);
|
|
2351
|
+
i++;
|
|
2352
|
+
}
|
|
2353
|
+
sqlBlocks.push({
|
|
2354
|
+
name,
|
|
2355
|
+
sql: sqlLines.join("\n"),
|
|
2356
|
+
startLine,
|
|
2357
|
+
endLine: i
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2360
|
+
i++;
|
|
2361
|
+
}
|
|
2362
|
+
return { frontmatter, content, sqlBlocks };
|
|
2363
|
+
}
|
|
2364
|
+
function interpolateTemplates(text, queryResults) {
|
|
2365
|
+
return text.replace(/\{(\w+)\.rows\[(\d+)\]\.(\w+)\}/g, (match, queryName, rowIdx, colName) => {
|
|
2366
|
+
const rows = queryResults.get(queryName);
|
|
2367
|
+
if (!rows) return match;
|
|
2368
|
+
const row = rows[parseInt(rowIdx, 10)];
|
|
2369
|
+
if (!row) return match;
|
|
2370
|
+
const value = row[colName];
|
|
2371
|
+
return value !== void 0 ? String(value) : match;
|
|
2372
|
+
});
|
|
2373
|
+
}
|
|
2374
|
+
function markSqlBlocks(content) {
|
|
2375
|
+
return content.replace(
|
|
2376
|
+
/```sql\s+(\w[\w-]*)\s*\n([\s\S]*?)```/g,
|
|
2377
|
+
(_, name) => `<div data-sql-block="${name}"></div>`
|
|
2378
|
+
);
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
// ../../src/lib/utils/parquet-metadata.ts
|
|
2382
|
+
function mapParquetType(col) {
|
|
2383
|
+
const lt = col.logical_type;
|
|
2384
|
+
if (lt) {
|
|
2385
|
+
if (lt.type === "GEOMETRY" || lt.type === "GEOGRAPHY") return "GEOMETRY";
|
|
2386
|
+
if (lt.type === "STRING" || lt.type === "UTF8") return "VARCHAR";
|
|
2387
|
+
if (lt.type === "JSON") return "JSON";
|
|
2388
|
+
if (lt.type === "UUID") return "UUID";
|
|
2389
|
+
if (lt.type === "ENUM") return "VARCHAR";
|
|
2390
|
+
if (lt.type === "INT" || lt.type === "INTEGER") {
|
|
2391
|
+
const bits = lt.bitWidth ?? 32;
|
|
2392
|
+
const signed = lt.isSigned !== false;
|
|
2393
|
+
if (bits <= 8) return signed ? "TINYINT" : "UTINYINT";
|
|
2394
|
+
if (bits <= 16) return signed ? "SMALLINT" : "USMALLINT";
|
|
2395
|
+
if (bits <= 32) return signed ? "INTEGER" : "UINTEGER";
|
|
2396
|
+
return signed ? "BIGINT" : "UBIGINT";
|
|
2397
|
+
}
|
|
2398
|
+
if (lt.type === "DECIMAL") return `DECIMAL(${lt.precision ?? 18},${lt.scale ?? 0})`;
|
|
2399
|
+
if (lt.type === "DATE") return "DATE";
|
|
2400
|
+
if (lt.type === "TIME") return "TIME";
|
|
2401
|
+
if (lt.type === "TIMESTAMP") return "TIMESTAMP";
|
|
2402
|
+
if (lt.type === "BSON") return "BLOB";
|
|
2403
|
+
}
|
|
2404
|
+
const ct = col.converted_type;
|
|
2405
|
+
if (ct === "UTF8") return "VARCHAR";
|
|
2406
|
+
if (ct === "JSON") return "JSON";
|
|
2407
|
+
if (ct === "DATE") return "DATE";
|
|
2408
|
+
if (ct === "TIMESTAMP_MILLIS" || ct === "TIMESTAMP_MICROS") return "TIMESTAMP";
|
|
2409
|
+
if (ct === "DECIMAL") return `DECIMAL(${col.precision ?? 18},${col.scale ?? 0})`;
|
|
2410
|
+
if (ct === "INT_8") return "TINYINT";
|
|
2411
|
+
if (ct === "INT_16") return "SMALLINT";
|
|
2412
|
+
if (ct === "INT_32") return "INTEGER";
|
|
2413
|
+
if (ct === "INT_64") return "BIGINT";
|
|
2414
|
+
if (ct === "UINT_8") return "UTINYINT";
|
|
2415
|
+
if (ct === "UINT_16") return "USMALLINT";
|
|
2416
|
+
if (ct === "UINT_32") return "UINTEGER";
|
|
2417
|
+
if (ct === "UINT_64") return "UBIGINT";
|
|
2418
|
+
const pt = col.type;
|
|
2419
|
+
if (pt === "BOOLEAN") return "BOOLEAN";
|
|
2420
|
+
if (pt === "INT32") return "INTEGER";
|
|
2421
|
+
if (pt === "INT64") return "BIGINT";
|
|
2422
|
+
if (pt === "INT96") return "TIMESTAMP";
|
|
2423
|
+
if (pt === "FLOAT") return "FLOAT";
|
|
2424
|
+
if (pt === "DOUBLE") return "DOUBLE";
|
|
2425
|
+
if (pt === "BYTE_ARRAY") return "BLOB";
|
|
2426
|
+
if (pt === "FIXED_LEN_BYTE_ARRAY") return "BLOB";
|
|
2427
|
+
return "VARCHAR";
|
|
2428
|
+
}
|
|
2429
|
+
async function readParquetMetadata(url) {
|
|
2430
|
+
const { parquetMetadataAsync, asyncBufferFromUrl } = await import('hyparquet');
|
|
2431
|
+
const file = await asyncBufferFromUrl({ url });
|
|
2432
|
+
const metadata = await parquetMetadataAsync(file);
|
|
2433
|
+
const rowCount = metadata.row_groups.reduce(
|
|
2434
|
+
(sum, rg) => sum + Number(rg.num_rows),
|
|
2435
|
+
0
|
|
2436
|
+
);
|
|
2437
|
+
const schema = metadata.schema.slice(1).filter((col) => col.num_children === void 0).map((col) => ({
|
|
2438
|
+
name: col.name,
|
|
2439
|
+
type: mapParquetType(col)
|
|
2440
|
+
}));
|
|
2441
|
+
let geo = null;
|
|
2442
|
+
let legacyGeoParquet = false;
|
|
2443
|
+
const geoKv = metadata.key_value_metadata?.find((kv) => kv.key === "geo");
|
|
2444
|
+
if (geoKv) {
|
|
2445
|
+
try {
|
|
2446
|
+
const geoJson = JSON.parse(geoKv.value ?? "");
|
|
2447
|
+
if (geoJson.schema_version && !geoJson.version) {
|
|
2448
|
+
legacyGeoParquet = true;
|
|
2449
|
+
}
|
|
2450
|
+
geo = {
|
|
2451
|
+
primaryColumn: geoJson.primary_column ?? "geometry",
|
|
2452
|
+
columns: {}
|
|
2453
|
+
};
|
|
2454
|
+
if (geoJson.columns) {
|
|
2455
|
+
for (const [colName, colMeta] of Object.entries(geoJson.columns)) {
|
|
2456
|
+
geo.columns[colName] = {
|
|
2457
|
+
encoding: colMeta.encoding ?? "WKB",
|
|
2458
|
+
geometryTypes: colMeta.geometry_types ?? [],
|
|
2459
|
+
crs: colMeta.crs ?? null,
|
|
2460
|
+
bbox: colMeta.bbox
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
} catch {
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
const createdBy = metadata.created_by ?? null;
|
|
2468
|
+
const numRowGroups = metadata.row_groups.length;
|
|
2469
|
+
let compression = null;
|
|
2470
|
+
if (numRowGroups > 0 && metadata.row_groups[0].columns) {
|
|
2471
|
+
const codecs = /* @__PURE__ */ new Set();
|
|
2472
|
+
for (const col of metadata.row_groups[0].columns) {
|
|
2473
|
+
const codec = col.meta_data?.codec;
|
|
2474
|
+
if (codec) codecs.add(codec);
|
|
2475
|
+
}
|
|
2476
|
+
if (codecs.size === 1) {
|
|
2477
|
+
compression = [...codecs][0];
|
|
2478
|
+
} else if (codecs.size > 1) {
|
|
2479
|
+
compression = [...codecs].join(", ");
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
return { rowCount, schema, geo, legacyGeoParquet, createdBy, numRowGroups, compression };
|
|
2483
|
+
}
|
|
2484
|
+
function extractEpsgFromGeoMeta(geo) {
|
|
2485
|
+
const primaryCol = geo.columns[geo.primaryColumn];
|
|
2486
|
+
if (!primaryCol?.crs) return null;
|
|
2487
|
+
const crs = primaryCol.crs;
|
|
2488
|
+
if (crs.type === "name" && crs.properties?.name?.includes("CRS84")) return null;
|
|
2489
|
+
if (crs.id?.authority === "EPSG") {
|
|
2490
|
+
const code = crs.id.code;
|
|
2491
|
+
if (WGS84_CODES.has(code)) return null;
|
|
2492
|
+
return `EPSG:${code}`;
|
|
2493
|
+
}
|
|
2494
|
+
return null;
|
|
2495
|
+
}
|
|
2496
|
+
function extractGeometryTypes(geo) {
|
|
2497
|
+
const primaryCol = geo.columns[geo.primaryColumn];
|
|
2498
|
+
if (!primaryCol?.geometryTypes?.length) return [];
|
|
2499
|
+
const typeMap = {
|
|
2500
|
+
Point: "point",
|
|
2501
|
+
LineString: "linestring",
|
|
2502
|
+
Polygon: "polygon",
|
|
2503
|
+
MultiPoint: "multipoint",
|
|
2504
|
+
MultiLineString: "multilinestring",
|
|
2505
|
+
MultiPolygon: "multipolygon"
|
|
2506
|
+
};
|
|
2507
|
+
const types = [];
|
|
2508
|
+
for (const raw of primaryCol.geometryTypes) {
|
|
2509
|
+
const base = raw.split(" ")[0];
|
|
2510
|
+
const mapped = typeMap[base];
|
|
2511
|
+
if (mapped && !types.includes(mapped)) types.push(mapped);
|
|
2512
|
+
}
|
|
2513
|
+
return types;
|
|
2514
|
+
}
|
|
2515
|
+
function extractBounds(geo) {
|
|
2516
|
+
const primaryCol = geo.columns[geo.primaryColumn];
|
|
2517
|
+
if (!primaryCol?.bbox || primaryCol.bbox.length < 4) return null;
|
|
2518
|
+
return [primaryCol.bbox[0], primaryCol.bbox[1], primaryCol.bbox[2], primaryCol.bbox[3]];
|
|
2519
|
+
}
|
|
2275
2520
|
|
|
2276
2521
|
// ../../src/lib/utils/storage-url.ts
|
|
2277
2522
|
function buildSchemeMap() {
|
|
@@ -2854,16 +3099,24 @@ exports.DEFAULT_TARGET_CRS = DEFAULT_TARGET_CRS;
|
|
|
2854
3099
|
exports.DUCKDB_INIT_TIMEOUT_MS = DUCKDB_INIT_TIMEOUT_MS;
|
|
2855
3100
|
exports.LAYER_HUE_MULTIPLIER = LAYER_HUE_MULTIPLIER;
|
|
2856
3101
|
exports.MAX_QUERY_HISTORY_ENTRIES = MAX_QUERY_HISTORY_ENTRIES;
|
|
3102
|
+
exports.PROVIDERS = PROVIDERS;
|
|
3103
|
+
exports.PROVIDER_IDS = PROVIDER_IDS;
|
|
2857
3104
|
exports.QueryCancelledError = QueryCancelledError;
|
|
3105
|
+
exports.SF_LABELS = SF_LABELS;
|
|
2858
3106
|
exports.SQL_PREVIEW_LENGTH = SQL_PREVIEW_LENGTH;
|
|
2859
3107
|
exports.STORAGE_KEYS = STORAGE_KEYS;
|
|
2860
3108
|
exports.UrlAdapter = UrlAdapter;
|
|
2861
3109
|
exports.VIEWER_DIR_EXTENSIONS = VIEWER_DIR_EXTENSIONS;
|
|
2862
3110
|
exports.WGS84_CODES = WGS84_CODES;
|
|
3111
|
+
exports.buildDataTypeLabel = buildDataTypeLabel;
|
|
2863
3112
|
exports.buildDuckDbSource = buildDuckDbSource;
|
|
3113
|
+
exports.buildEndpointFromTemplate = buildEndpointFromTemplate;
|
|
2864
3114
|
exports.buildGeoArrowTables = buildGeoArrowTables;
|
|
3115
|
+
exports.buildProviderBaseUrl = buildProviderBaseUrl;
|
|
3116
|
+
exports.clampBounds = clampBounds;
|
|
2865
3117
|
exports.classifyType = classifyType;
|
|
2866
3118
|
exports.describeParseResult = describeParseResult;
|
|
3119
|
+
exports.escapeCsvField = escapeCsvField;
|
|
2867
3120
|
exports.extractBounds = extractBounds;
|
|
2868
3121
|
exports.extractEpsgFromGeoMeta = extractEpsgFromGeoMeta;
|
|
2869
3122
|
exports.extractGeometryTypes = extractGeometryTypes;
|
|
@@ -2877,17 +3130,32 @@ exports.getDuckDbReadFn = getDuckDbReadFn;
|
|
|
2877
3130
|
exports.getFileExtension = getFileExtension;
|
|
2878
3131
|
exports.getFileTypeInfo = getFileTypeInfo;
|
|
2879
3132
|
exports.getMimeType = getMimeType;
|
|
3133
|
+
exports.getNativeScheme = getNativeScheme;
|
|
3134
|
+
exports.getProvider = getProvider;
|
|
2880
3135
|
exports.getViewerKind = getViewerKind;
|
|
2881
3136
|
exports.handleLoadError = handleLoadError;
|
|
3137
|
+
exports.interpolateTemplates = interpolateTemplates;
|
|
2882
3138
|
exports.isCloudNativeFormat = isCloudNativeFormat;
|
|
3139
|
+
exports.isGcsProvider = isGcsProvider;
|
|
2883
3140
|
exports.isQueryable = isQueryable;
|
|
2884
3141
|
exports.jsonReplacerBigInt = jsonReplacerBigInt;
|
|
3142
|
+
exports.loadFromStorage = loadFromStorage;
|
|
2885
3143
|
exports.looksLikeUrl = looksLikeUrl;
|
|
3144
|
+
exports.markSqlBlocks = markSqlBlocks;
|
|
2886
3145
|
exports.normalizeGeomType = normalizeGeomType;
|
|
3146
|
+
exports.parseMarkdownDocument = parseMarkdownDocument;
|
|
2887
3147
|
exports.parseStorageUrl = parseStorageUrl;
|
|
2888
3148
|
exports.parseWKB = parseWKB;
|
|
3149
|
+
exports.persistToStorage = persistToStorage;
|
|
2889
3150
|
exports.readParquetMetadata = readParquetMetadata;
|
|
3151
|
+
exports.resolveCloudUrl = resolveCloudUrl;
|
|
3152
|
+
exports.safeClamp = safeClamp;
|
|
3153
|
+
exports.safeDecodeURIComponent = safeDecodeURIComponent;
|
|
3154
|
+
exports.serializeToCsv = serializeToCsv;
|
|
3155
|
+
exports.serializeToJson = serializeToJson;
|
|
3156
|
+
exports.sortFileEntries = sortFileEntries;
|
|
2890
3157
|
exports.toBinary = toBinary;
|
|
3158
|
+
exports.toggleSortField = toggleSortField;
|
|
2891
3159
|
exports.typeBadgeClass = typeBadgeClass;
|
|
2892
3160
|
exports.typeColor = typeColor;
|
|
2893
3161
|
exports.typeLabel = typeLabel;
|