udbx4ts 0.3.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/dist/index.cjs ADDED
@@ -0,0 +1,3101 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
31
+
32
+ // src/index.ts
33
+ var src_exports = {};
34
+ __export(src_exports, {
35
+ BaseDataset: () => BaseDataset,
36
+ BinaryCursor: () => BinaryCursor,
37
+ BinaryWriter: () => BinaryWriter,
38
+ CadDataset: () => CadDataset,
39
+ GAIA_BYTE_ORDER_LE: () => GAIA_BYTE_ORDER_LE,
40
+ GAIA_END: () => GAIA_END,
41
+ GAIA_GEOMETRY_DATA_OFFSET: () => GAIA_GEOMETRY_DATA_OFFSET,
42
+ GAIA_MBR: () => GAIA_MBR,
43
+ GAIA_START: () => GAIA_START,
44
+ GEO_TYPE_MULTILINESTRING: () => GEO_TYPE_MULTILINESTRING,
45
+ GEO_TYPE_MULTILINESTRINGZ: () => GEO_TYPE_MULTILINESTRINGZ,
46
+ GEO_TYPE_MULTIPOLYGON: () => GEO_TYPE_MULTIPOLYGON,
47
+ GEO_TYPE_MULTIPOLYGONZ: () => GEO_TYPE_MULTIPOLYGONZ,
48
+ GEO_TYPE_POINT: () => GEO_TYPE_POINT,
49
+ GEO_TYPE_POINTZ: () => GEO_TYPE_POINTZ,
50
+ GaiaError: () => GaiaError,
51
+ GaiaFormatError: () => GaiaFormatError,
52
+ GaiaGeoTypeMismatchError: () => GaiaGeoTypeMismatchError,
53
+ GaiaGeometryCodec: () => GaiaGeometryCodec,
54
+ GaiaLineCodec: () => GaiaLineCodec,
55
+ GaiaPointCodec: () => GaiaPointCodec,
56
+ GaiaPolygonCodec: () => GaiaPolygonCodec,
57
+ GaiaUnsupportedGeoTypeError: () => GaiaUnsupportedGeoTypeError,
58
+ JstsGeometryCodec: () => JstsGeometryCodec,
59
+ LineDataset: () => LineDataset,
60
+ LineZDataset: () => LineZDataset,
61
+ NotImplementedError: () => NotImplementedError,
62
+ PointDataset: () => PointDataset,
63
+ PointZDataset: () => PointZDataset,
64
+ RegionDataset: () => RegionDataset,
65
+ RegionZDataset: () => RegionZDataset,
66
+ SmFieldInfoRepository: () => SmFieldInfoRepository,
67
+ SmRegisterRepository: () => SmRegisterRepository,
68
+ TabularDataset: () => TabularDataset,
69
+ TextDataset: () => TextDataset,
70
+ UDBX_SCHEMA_STATEMENTS: () => UDBX_SCHEMA_STATEMENTS,
71
+ UDBX_SYSTEM_TABLES: () => UDBX_SYSTEM_TABLES,
72
+ UdbxConstraintError: () => UdbxConstraintError,
73
+ UdbxDataSource: () => UdbxDataSource,
74
+ UdbxError: () => UdbxError,
75
+ UdbxFormatError: () => UdbxFormatError,
76
+ UdbxIOError: () => UdbxIOError,
77
+ UdbxNotFoundError: () => UdbxNotFoundError,
78
+ UdbxSchemaInitializer: () => UdbxSchemaInitializer,
79
+ UdbxUnsupportedError: () => UdbxUnsupportedError,
80
+ createNotImplementedError: () => createNotImplementedError,
81
+ datasetKindToValue: () => datasetKindToValue,
82
+ datasetValueToKind: () => datasetValueToKind,
83
+ fieldTypeToValue: () => fieldTypeToValue,
84
+ fieldValueToType: () => fieldValueToType,
85
+ fromJsts: () => fromJsts,
86
+ readGaiaHeader: () => readGaiaHeader,
87
+ toJsts: () => toJsts,
88
+ toJstsMultiLineString: () => toJstsMultiLineString,
89
+ toJstsMultiPolygon: () => toJstsMultiPolygon,
90
+ toJstsPoint: () => toJstsPoint,
91
+ validateGaiaEnd: () => validateGaiaEnd,
92
+ writeGaiaHeader: () => writeGaiaHeader
93
+ });
94
+ module.exports = __toCommonJS(src_exports);
95
+
96
+ // src/core/sql/SqlHelpers.ts
97
+ async function queryAll(driver, sql, params) {
98
+ const statement = await driver.prepare(sql);
99
+ try {
100
+ if (params) {
101
+ await statement.bind(params);
102
+ }
103
+ const rows = [];
104
+ while (await statement.step()) {
105
+ rows.push(await statement.getRow());
106
+ }
107
+ return rows;
108
+ } finally {
109
+ await statement.finalize();
110
+ }
111
+ }
112
+ async function queryOne(driver, sql, params) {
113
+ const rows = await queryAll(driver, sql, params);
114
+ return rows[0] ?? null;
115
+ }
116
+ async function executeStatement(statement, params) {
117
+ try {
118
+ if (params) {
119
+ await statement.bind(params);
120
+ }
121
+ await statement.step();
122
+ } finally {
123
+ await statement.finalize();
124
+ }
125
+ }
126
+ async function executeSql(driver, sql, params) {
127
+ const statement = await driver.prepare(sql);
128
+ await executeStatement(statement, params);
129
+ }
130
+
131
+ // src/core/schema/UdbxTypeMappings.ts
132
+ var datasetKindToValueMap = {
133
+ tabular: 0,
134
+ point: 1,
135
+ line: 3,
136
+ region: 5,
137
+ pointZ: 101,
138
+ lineZ: 103,
139
+ regionZ: 105,
140
+ text: 7,
141
+ cad: 149
142
+ };
143
+ var datasetValueToKindMap = new Map(
144
+ Object.entries(datasetKindToValueMap).map(([kind, value]) => [
145
+ value,
146
+ kind
147
+ ])
148
+ );
149
+ var fieldTypeToValueMap = {
150
+ boolean: 1,
151
+ byte: 2,
152
+ int16: 3,
153
+ int32: 4,
154
+ int64: 5,
155
+ single: 6,
156
+ double: 7,
157
+ date: 8,
158
+ binary: 9,
159
+ geometry: 10,
160
+ char: 11,
161
+ ntext: 127,
162
+ text: 128,
163
+ time: 16
164
+ };
165
+ var fieldValueToTypeMap = /* @__PURE__ */ new Map([
166
+ [1, "boolean"],
167
+ [2, "byte"],
168
+ [3, "int16"],
169
+ [4, "int32"],
170
+ [5, "int64"],
171
+ [6, "single"],
172
+ [7, "double"],
173
+ [8, "date"],
174
+ [9, "binary"],
175
+ [10, "geometry"],
176
+ [11, "char"],
177
+ [16, "time"],
178
+ [127, "ntext"],
179
+ [128, "text"]
180
+ ]);
181
+ function datasetKindToValue(kind) {
182
+ return datasetKindToValueMap[kind];
183
+ }
184
+ function datasetValueToKind(value) {
185
+ const kind = datasetValueToKindMap.get(value);
186
+ if (!kind) {
187
+ throw new Error(`Unsupported SmDatasetType value: ${value}.`);
188
+ }
189
+ return kind;
190
+ }
191
+ function fieldTypeToValue(type) {
192
+ return fieldTypeToValueMap[type];
193
+ }
194
+ function fieldValueToType(value) {
195
+ const type = fieldValueToTypeMap.get(value);
196
+ if (!type) {
197
+ throw new Error(`Unsupported SmFieldType value: ${value}.`);
198
+ }
199
+ return type;
200
+ }
201
+
202
+ // src/core/schema/SmFieldInfoRepository.ts
203
+ function mapRow(row) {
204
+ return {
205
+ name: row.SmFieldName,
206
+ fieldType: fieldValueToType(row.SmFieldType),
207
+ nullable: row.SmFieldbRequired !== 1,
208
+ defaultValue: row.SmFieldDefaultValue ?? void 0
209
+ };
210
+ }
211
+ var SmFieldInfoRepository = class {
212
+ constructor(driver) {
213
+ this.driver = driver;
214
+ }
215
+ async findByDatasetId(datasetId) {
216
+ const rows = await queryAll(
217
+ this.driver,
218
+ `SELECT
219
+ SmFieldName,
220
+ SmFieldType,
221
+ SmFieldbRequired,
222
+ SmFieldDefaultValue
223
+ FROM SmFieldInfo
224
+ WHERE SmDatasetID = ?
225
+ ORDER BY SmID`,
226
+ [datasetId]
227
+ );
228
+ return rows.map(mapRow);
229
+ }
230
+ async insertAll(datasetId, fields) {
231
+ for (const field of fields) {
232
+ const statement = await this.driver.prepare(
233
+ `INSERT INTO SmFieldInfo (
234
+ SmDatasetID,
235
+ SmFieldName,
236
+ SmFieldType,
237
+ SmFieldCaption,
238
+ SmFieldbRequired,
239
+ SmFieldDefaultValue
240
+ ) VALUES (?, ?, ?, ?, ?, ?)`
241
+ );
242
+ await executeStatement(statement, [
243
+ datasetId,
244
+ field.name,
245
+ fieldTypeToValue(field.fieldType),
246
+ field.name,
247
+ field.nullable ? 0 : 1,
248
+ field.defaultValue == null ? null : String(field.defaultValue)
249
+ ]);
250
+ }
251
+ }
252
+ };
253
+
254
+ // src/core/dataset/BaseDataset.ts
255
+ var BaseDataset = class {
256
+ constructor(driver, info) {
257
+ this.driver = driver;
258
+ this.info = info;
259
+ __publicField(this, "fieldInfoRepository");
260
+ this.fieldInfoRepository = new SmFieldInfoRepository(driver);
261
+ }
262
+ getFields() {
263
+ return this.fieldInfoRepository.findByDatasetId(this.info.id);
264
+ }
265
+ };
266
+
267
+ // src/core/utils/errors.ts
268
+ var NotImplementedError = class extends Error {
269
+ constructor(message) {
270
+ super(message);
271
+ this.name = "NotImplementedError";
272
+ }
273
+ };
274
+ function createNotImplementedError(scope) {
275
+ return new NotImplementedError(`${scope} is not implemented yet.`);
276
+ }
277
+
278
+ // src/core/dataset/CadDataset.ts
279
+ var CadDataset = class extends BaseDataset {
280
+ async getById() {
281
+ throw createNotImplementedError("CadDataset.getById");
282
+ }
283
+ async list() {
284
+ throw createNotImplementedError("CadDataset.list");
285
+ }
286
+ async *iterate() {
287
+ throw createNotImplementedError("CadDataset.iterate");
288
+ }
289
+ async count() {
290
+ throw createNotImplementedError("CadDataset.count");
291
+ }
292
+ async insert() {
293
+ throw createNotImplementedError("CadDataset.insert");
294
+ }
295
+ async insertMany() {
296
+ throw createNotImplementedError("CadDataset.insertMany");
297
+ }
298
+ async update() {
299
+ throw createNotImplementedError("CadDataset.update");
300
+ }
301
+ async delete() {
302
+ throw createNotImplementedError("CadDataset.delete");
303
+ }
304
+ };
305
+
306
+ // src/core/utils/BinaryCursor.ts
307
+ function toUint8Array(input) {
308
+ if (input instanceof Uint8Array) {
309
+ return input;
310
+ }
311
+ if (ArrayBuffer.isView(input)) {
312
+ return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
313
+ }
314
+ return new Uint8Array(input);
315
+ }
316
+ var BinaryCursor = class {
317
+ constructor(input) {
318
+ __publicField(this, "bytes");
319
+ __publicField(this, "view");
320
+ __publicField(this, "offset", 0);
321
+ this.bytes = toUint8Array(input);
322
+ this.view = new DataView(
323
+ this.bytes.buffer,
324
+ this.bytes.byteOffset,
325
+ this.bytes.byteLength
326
+ );
327
+ }
328
+ get length() {
329
+ return this.bytes.byteLength;
330
+ }
331
+ get position() {
332
+ return this.offset;
333
+ }
334
+ get remaining() {
335
+ return this.length - this.offset;
336
+ }
337
+ seek(position) {
338
+ if (position < 0 || position > this.length) {
339
+ throw new RangeError(
340
+ `Cannot seek to ${position}; valid range is 0..${this.length}.`
341
+ );
342
+ }
343
+ this.offset = position;
344
+ }
345
+ skip(length) {
346
+ this.seek(this.offset + length);
347
+ }
348
+ readUint8() {
349
+ this.ensureAvailable(1);
350
+ const value = this.view.getUint8(this.offset);
351
+ this.offset += 1;
352
+ return value;
353
+ }
354
+ readInt32(littleEndian = true) {
355
+ this.ensureAvailable(4);
356
+ const value = this.view.getInt32(this.offset, littleEndian);
357
+ this.offset += 4;
358
+ return value;
359
+ }
360
+ readFloat64(littleEndian = true) {
361
+ this.ensureAvailable(8);
362
+ const value = this.view.getFloat64(this.offset, littleEndian);
363
+ this.offset += 8;
364
+ return value;
365
+ }
366
+ readBytes(length) {
367
+ this.ensureAvailable(length);
368
+ const value = this.bytes.slice(this.offset, this.offset + length);
369
+ this.offset += length;
370
+ return value;
371
+ }
372
+ peekUint8() {
373
+ this.ensureAvailable(1);
374
+ return this.view.getUint8(this.offset);
375
+ }
376
+ ensureAvailable(length) {
377
+ if (length < 0) {
378
+ throw new RangeError("Length must be non-negative.");
379
+ }
380
+ if (this.offset + length > this.length) {
381
+ throw new RangeError(
382
+ `Cannot read ${length} byte(s) from offset ${this.offset}; only ${this.remaining} byte(s) remain.`
383
+ );
384
+ }
385
+ }
386
+ };
387
+
388
+ // src/core/utils/BinaryWriter.ts
389
+ var BinaryWriter = class {
390
+ constructor(initialCapacity = 64) {
391
+ __publicField(this, "buffer");
392
+ __publicField(this, "view");
393
+ __publicField(this, "bytes");
394
+ __publicField(this, "offset", 0);
395
+ if (initialCapacity <= 0) {
396
+ throw new RangeError("Initial capacity must be greater than 0.");
397
+ }
398
+ this.buffer = new ArrayBuffer(initialCapacity);
399
+ this.view = new DataView(this.buffer);
400
+ this.bytes = new Uint8Array(this.buffer);
401
+ }
402
+ get length() {
403
+ return this.offset;
404
+ }
405
+ writeUint8(value) {
406
+ this.ensureCapacity(1);
407
+ this.view.setUint8(this.offset, value);
408
+ this.offset += 1;
409
+ }
410
+ writeInt32(value, littleEndian = true) {
411
+ this.ensureCapacity(4);
412
+ this.view.setInt32(this.offset, value, littleEndian);
413
+ this.offset += 4;
414
+ }
415
+ writeFloat64(value, littleEndian = true) {
416
+ this.ensureCapacity(8);
417
+ this.view.setFloat64(this.offset, value, littleEndian);
418
+ this.offset += 8;
419
+ }
420
+ writeBytes(value) {
421
+ const bytes = value instanceof Uint8Array ? value : ArrayBuffer.isView(value) ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength) : new Uint8Array(value);
422
+ this.ensureCapacity(bytes.byteLength);
423
+ this.bytes.set(bytes, this.offset);
424
+ this.offset += bytes.byteLength;
425
+ }
426
+ toUint8Array() {
427
+ return this.bytes.slice(0, this.offset);
428
+ }
429
+ ensureCapacity(required) {
430
+ if (this.offset + required <= this.buffer.byteLength) {
431
+ return;
432
+ }
433
+ let nextCapacity = this.buffer.byteLength;
434
+ while (this.offset + required > nextCapacity) {
435
+ nextCapacity *= 2;
436
+ }
437
+ const nextBuffer = new ArrayBuffer(nextCapacity);
438
+ const nextBytes = new Uint8Array(nextBuffer);
439
+ nextBytes.set(this.bytes.subarray(0, this.offset));
440
+ this.buffer = nextBuffer;
441
+ this.view = new DataView(this.buffer);
442
+ this.bytes = nextBytes;
443
+ }
444
+ };
445
+
446
+ // src/core/geometry/gaia/GaiaConstants.ts
447
+ var GAIA_START = 0;
448
+ var GAIA_BYTE_ORDER_LE = 1;
449
+ var GAIA_MBR = 124;
450
+ var GAIA_END = 254;
451
+ var GAIA_GEOMETRY_DATA_OFFSET = 43;
452
+ var GEO_TYPE_POINT = 1;
453
+ var GEO_TYPE_POINTZ = 1001;
454
+ var GEO_TYPE_MULTILINESTRING = 5;
455
+ var GEO_TYPE_MULTILINESTRINGZ = 1005;
456
+ var GEO_TYPE_MULTIPOLYGON = 6;
457
+ var GEO_TYPE_MULTIPOLYGONZ = 1006;
458
+
459
+ // src/core/geometry/gaia/GaiaErrors.ts
460
+ var GaiaError = class extends Error {
461
+ constructor(message) {
462
+ super(message);
463
+ this.name = "GaiaError";
464
+ }
465
+ };
466
+ var GaiaFormatError = class extends GaiaError {
467
+ constructor(message) {
468
+ super(message);
469
+ this.name = "GaiaFormatError";
470
+ }
471
+ };
472
+ var GaiaGeoTypeMismatchError = class extends GaiaError {
473
+ constructor(expected, actual) {
474
+ super(`Expected geoType=${expected}, got ${actual}.`);
475
+ this.name = "GaiaGeoTypeMismatchError";
476
+ }
477
+ };
478
+ var GaiaUnsupportedGeoTypeError = class extends GaiaError {
479
+ constructor(geoType) {
480
+ super(`Unsupported GAIA geoType: ${geoType}.`);
481
+ this.name = "GaiaUnsupportedGeoTypeError";
482
+ }
483
+ };
484
+
485
+ // src/core/geometry/gaia/GaiaHeader.ts
486
+ function readGaiaHeader(cursor, expectedGeoType) {
487
+ cursor.seek(0);
488
+ const gaiaStart = cursor.readUint8();
489
+ if (gaiaStart !== GAIA_START) {
490
+ throw new GaiaFormatError(
491
+ `Invalid GAIA start marker: expected 0x${GAIA_START.toString(16)}, got 0x${gaiaStart.toString(16)}.`
492
+ );
493
+ }
494
+ const byteOrder = cursor.readUint8();
495
+ if (byteOrder !== GAIA_BYTE_ORDER_LE) {
496
+ throw new GaiaFormatError(
497
+ `Unsupported byte order: expected 0x${GAIA_BYTE_ORDER_LE.toString(16)}, got 0x${byteOrder.toString(16)}.`
498
+ );
499
+ }
500
+ const srid = cursor.readInt32(true);
501
+ const minX = cursor.readFloat64(true);
502
+ const minY = cursor.readFloat64(true);
503
+ const maxX = cursor.readFloat64(true);
504
+ const maxY = cursor.readFloat64(true);
505
+ const gaiaMbr = cursor.readUint8();
506
+ if (gaiaMbr !== GAIA_MBR) {
507
+ throw new GaiaFormatError(
508
+ `Invalid GAIA MBR marker: expected 0x${GAIA_MBR.toString(16)}, got 0x${gaiaMbr.toString(16)}.`
509
+ );
510
+ }
511
+ const geoType = cursor.readInt32(true);
512
+ if (expectedGeoType !== void 0 && geoType !== expectedGeoType) {
513
+ throw new GaiaGeoTypeMismatchError(expectedGeoType, geoType);
514
+ }
515
+ return {
516
+ byteOrder,
517
+ srid,
518
+ mbr: [minX, minY, maxX, maxY],
519
+ geoType,
520
+ geometryDataOffset: GAIA_GEOMETRY_DATA_OFFSET
521
+ };
522
+ }
523
+ function validateGaiaEnd(cursor) {
524
+ const gaiaEnd = cursor.readUint8();
525
+ if (gaiaEnd !== GAIA_END) {
526
+ throw new GaiaFormatError(
527
+ `Invalid GAIA end marker: expected 0x${GAIA_END.toString(16)}, got 0x${gaiaEnd.toString(16)}.`
528
+ );
529
+ }
530
+ }
531
+
532
+ // src/core/geometry/gaia/GaiaPointCodec.ts
533
+ function isPoint3D(geometry) {
534
+ return geometry.coordinates.length === 3;
535
+ }
536
+ function createPointMbr(coordinates) {
537
+ return [coordinates[0], coordinates[1], coordinates[0], coordinates[1]];
538
+ }
539
+ function writeGaiaHeader(writer2, srid, mbr, geoType) {
540
+ writer2.writeUint8(GAIA_START);
541
+ writer2.writeUint8(GAIA_BYTE_ORDER_LE);
542
+ writer2.writeInt32(srid, true);
543
+ writer2.writeFloat64(mbr[0], true);
544
+ writer2.writeFloat64(mbr[1], true);
545
+ writer2.writeFloat64(mbr[2], true);
546
+ writer2.writeFloat64(mbr[3], true);
547
+ writer2.writeUint8(GAIA_MBR);
548
+ writer2.writeInt32(geoType, true);
549
+ }
550
+ var GaiaPointCodec = class {
551
+ static readPoint(input) {
552
+ const cursor = new BinaryCursor(input);
553
+ const header = readGaiaHeader(cursor, GEO_TYPE_POINT);
554
+ const x = cursor.readFloat64(true);
555
+ const y = cursor.readFloat64(true);
556
+ validateGaiaEnd(cursor);
557
+ return {
558
+ type: "Point",
559
+ coordinates: [x, y],
560
+ srid: header.srid,
561
+ bbox: header.mbr,
562
+ hasZ: false,
563
+ geoType: header.geoType
564
+ };
565
+ }
566
+ static readPointZ(input) {
567
+ const cursor = new BinaryCursor(input);
568
+ const header = readGaiaHeader(cursor, GEO_TYPE_POINTZ);
569
+ const x = cursor.readFloat64(true);
570
+ const y = cursor.readFloat64(true);
571
+ const z = cursor.readFloat64(true);
572
+ validateGaiaEnd(cursor);
573
+ return {
574
+ type: "Point",
575
+ coordinates: [x, y, z],
576
+ srid: header.srid,
577
+ bbox: header.mbr,
578
+ hasZ: true,
579
+ geoType: header.geoType
580
+ };
581
+ }
582
+ static writePoint(geometry, srid) {
583
+ if (isPoint3D(geometry)) {
584
+ throw new GaiaFormatError("writePoint expects a 2D Point geometry.");
585
+ }
586
+ const writer2 = new BinaryWriter(60);
587
+ const mbr = createPointMbr(geometry.coordinates);
588
+ writeGaiaHeader(writer2, srid, mbr, GEO_TYPE_POINT);
589
+ writer2.writeFloat64(geometry.coordinates[0], true);
590
+ writer2.writeFloat64(geometry.coordinates[1], true);
591
+ writer2.writeUint8(GAIA_END);
592
+ return writer2.toUint8Array();
593
+ }
594
+ static writePointZ(geometry, srid) {
595
+ if (!isPoint3D(geometry)) {
596
+ throw new GaiaFormatError("writePointZ expects a 3D Point geometry.");
597
+ }
598
+ const writer2 = new BinaryWriter(68);
599
+ const mbr = createPointMbr(geometry.coordinates);
600
+ writeGaiaHeader(writer2, srid, mbr, GEO_TYPE_POINTZ);
601
+ writer2.writeFloat64(geometry.coordinates[0], true);
602
+ writer2.writeFloat64(geometry.coordinates[1], true);
603
+ writer2.writeFloat64(geometry.coordinates[2], true);
604
+ writer2.writeUint8(GAIA_END);
605
+ return writer2.toUint8Array();
606
+ }
607
+ };
608
+
609
+ // src/core/geometry/gaia/GaiaLineCodec.ts
610
+ var GAIA_ENTITY_MARK = 105;
611
+ var GEO_TYPE_LINESTRING = 2;
612
+ var GEO_TYPE_LINESTRINGZ = 1002;
613
+ function is3DCoordinates(coordinates) {
614
+ return coordinates[0]?.[0]?.length === 3;
615
+ }
616
+ function createLineMbr(coordinates) {
617
+ const xs = [];
618
+ const ys = [];
619
+ for (const line of coordinates) {
620
+ for (const point of line) {
621
+ xs.push(point[0]);
622
+ ys.push(point[1]);
623
+ }
624
+ }
625
+ if (xs.length === 0) {
626
+ throw new GaiaFormatError("MultiLineString must contain at least one point.");
627
+ }
628
+ return [
629
+ Math.min(...xs),
630
+ Math.min(...ys),
631
+ Math.max(...xs),
632
+ Math.max(...ys)
633
+ ];
634
+ }
635
+ var GaiaLineCodec = class {
636
+ static readMultiLineString(input) {
637
+ const cursor = new BinaryCursor(input);
638
+ const header = readGaiaHeader(cursor, GEO_TYPE_MULTILINESTRING);
639
+ const lineCount = cursor.readInt32(true);
640
+ const coordinates = [];
641
+ for (let lineIndex = 0; lineIndex < lineCount; lineIndex += 1) {
642
+ const entityMark = cursor.readUint8();
643
+ if (entityMark !== GAIA_ENTITY_MARK) {
644
+ throw new GaiaFormatError(
645
+ `Invalid LineString entity mark: expected 0x${GAIA_ENTITY_MARK.toString(16)}, got 0x${entityMark.toString(16)}.`
646
+ );
647
+ }
648
+ const lineGeoType = cursor.readInt32(true);
649
+ if (lineGeoType !== GEO_TYPE_LINESTRING) {
650
+ throw new GaiaFormatError(
651
+ `Invalid LineString geoType: expected ${GEO_TYPE_LINESTRING}, got ${lineGeoType}.`
652
+ );
653
+ }
654
+ const pointCount = cursor.readInt32(true);
655
+ const line = [];
656
+ for (let pointIndex = 0; pointIndex < pointCount; pointIndex += 1) {
657
+ line.push([cursor.readFloat64(true), cursor.readFloat64(true)]);
658
+ }
659
+ coordinates.push(line);
660
+ }
661
+ validateGaiaEnd(cursor);
662
+ return {
663
+ type: "MultiLineString",
664
+ coordinates,
665
+ srid: header.srid,
666
+ bbox: header.mbr,
667
+ hasZ: false,
668
+ geoType: header.geoType
669
+ };
670
+ }
671
+ static readMultiLineStringZ(input) {
672
+ const cursor = new BinaryCursor(input);
673
+ const header = readGaiaHeader(cursor, GEO_TYPE_MULTILINESTRINGZ);
674
+ const lineCount = cursor.readInt32(true);
675
+ const coordinates = [];
676
+ for (let lineIndex = 0; lineIndex < lineCount; lineIndex += 1) {
677
+ const entityMark = cursor.readUint8();
678
+ if (entityMark !== GAIA_ENTITY_MARK) {
679
+ throw new GaiaFormatError(
680
+ `Invalid LineString entity mark: expected 0x${GAIA_ENTITY_MARK.toString(16)}, got 0x${entityMark.toString(16)}.`
681
+ );
682
+ }
683
+ const lineGeoType = cursor.readInt32(true);
684
+ if (lineGeoType !== GEO_TYPE_LINESTRINGZ) {
685
+ throw new GaiaFormatError(
686
+ `Invalid LineStringZ geoType: expected ${GEO_TYPE_LINESTRINGZ}, got ${lineGeoType}.`
687
+ );
688
+ }
689
+ const pointCount = cursor.readInt32(true);
690
+ const line = [];
691
+ for (let pointIndex = 0; pointIndex < pointCount; pointIndex += 1) {
692
+ line.push([
693
+ cursor.readFloat64(true),
694
+ cursor.readFloat64(true),
695
+ cursor.readFloat64(true)
696
+ ]);
697
+ }
698
+ coordinates.push(line);
699
+ }
700
+ validateGaiaEnd(cursor);
701
+ return {
702
+ type: "MultiLineString",
703
+ coordinates,
704
+ srid: header.srid,
705
+ bbox: header.mbr,
706
+ hasZ: true,
707
+ geoType: header.geoType
708
+ };
709
+ }
710
+ static writeMultiLineString(geometry, srid) {
711
+ if (is3DCoordinates(geometry.coordinates)) {
712
+ throw new GaiaFormatError(
713
+ "writeMultiLineString expects 2D coordinates."
714
+ );
715
+ }
716
+ const writer2 = new BinaryWriter();
717
+ writeGaiaHeader(
718
+ writer2,
719
+ srid,
720
+ createLineMbr(geometry.coordinates),
721
+ GEO_TYPE_MULTILINESTRING
722
+ );
723
+ writer2.writeInt32(geometry.coordinates.length, true);
724
+ for (const line of geometry.coordinates) {
725
+ writer2.writeUint8(GAIA_ENTITY_MARK);
726
+ writer2.writeInt32(GEO_TYPE_LINESTRING, true);
727
+ writer2.writeInt32(line.length, true);
728
+ for (const point of line) {
729
+ writer2.writeFloat64(point[0], true);
730
+ writer2.writeFloat64(point[1], true);
731
+ }
732
+ }
733
+ writer2.writeUint8(GAIA_END);
734
+ return writer2.toUint8Array();
735
+ }
736
+ static writeMultiLineStringZ(geometry, srid) {
737
+ if (!is3DCoordinates(geometry.coordinates)) {
738
+ throw new GaiaFormatError(
739
+ "writeMultiLineStringZ expects 3D coordinates."
740
+ );
741
+ }
742
+ const writer2 = new BinaryWriter();
743
+ writeGaiaHeader(
744
+ writer2,
745
+ srid,
746
+ createLineMbr(geometry.coordinates),
747
+ GEO_TYPE_MULTILINESTRINGZ
748
+ );
749
+ writer2.writeInt32(geometry.coordinates.length, true);
750
+ for (const line of geometry.coordinates) {
751
+ writer2.writeUint8(GAIA_ENTITY_MARK);
752
+ writer2.writeInt32(GEO_TYPE_LINESTRINGZ, true);
753
+ writer2.writeInt32(line.length, true);
754
+ for (const point of line) {
755
+ writer2.writeFloat64(point[0], true);
756
+ writer2.writeFloat64(point[1], true);
757
+ writer2.writeFloat64(point[2], true);
758
+ }
759
+ }
760
+ writer2.writeUint8(GAIA_END);
761
+ return writer2.toUint8Array();
762
+ }
763
+ };
764
+
765
+ // src/core/schema/SmRegisterRepository.ts
766
+ function mapRow2(row) {
767
+ return {
768
+ id: row.SmDatasetID,
769
+ name: row.SmDatasetName,
770
+ kind: datasetValueToKind(row.SmDatasetType),
771
+ tableName: row.SmTableName,
772
+ srid: row.SmSRID ?? null,
773
+ objectCount: row.SmObjectCount,
774
+ geometryType: row.geometryType ?? null
775
+ };
776
+ }
777
+ var SmRegisterRepository = class {
778
+ constructor(driver) {
779
+ this.driver = driver;
780
+ }
781
+ async findAll() {
782
+ const rows = await queryAll(
783
+ this.driver,
784
+ `SELECT
785
+ SmDatasetID,
786
+ SmDatasetName,
787
+ SmTableName,
788
+ SmDatasetType,
789
+ SmObjectCount,
790
+ SmSRID
791
+ FROM SmRegister
792
+ ORDER BY SmDatasetID`
793
+ );
794
+ return rows.map(mapRow2);
795
+ }
796
+ async findByName(name) {
797
+ const row = await queryOne(
798
+ this.driver,
799
+ `SELECT
800
+ SmDatasetID,
801
+ SmDatasetName,
802
+ SmTableName,
803
+ SmDatasetType,
804
+ SmObjectCount,
805
+ SmSRID
806
+ FROM SmRegister
807
+ WHERE SmDatasetName = ?`,
808
+ [name]
809
+ );
810
+ return row ? mapRow2(row) : null;
811
+ }
812
+ async nextDatasetId() {
813
+ const row = await queryOne(
814
+ this.driver,
815
+ "SELECT COALESCE(MAX(SmDatasetID), 0) + 1 AS nextId FROM SmRegister"
816
+ );
817
+ return row?.nextId ?? 1;
818
+ }
819
+ async insert(params) {
820
+ const datasetId = await this.nextDatasetId();
821
+ const statement = await this.driver.prepare(
822
+ `INSERT INTO SmRegister (
823
+ SmDatasetID,
824
+ SmDatasetName,
825
+ SmTableName,
826
+ SmDatasetType,
827
+ SmObjectCount,
828
+ SmSRID,
829
+ SmIDColName,
830
+ SmGeoColName,
831
+ SmMaxGeometrySize,
832
+ SmCreateTime,
833
+ SmLastUpdateTime
834
+ ) VALUES (?, ?, ?, ?, 0, ?, ?, ?, 0, datetime('now'), datetime('now'))`
835
+ );
836
+ await executeStatement(statement, [
837
+ datasetId,
838
+ params.name,
839
+ params.name,
840
+ datasetKindToValue(params.kind),
841
+ params.srid,
842
+ params.idColumnName,
843
+ params.geometryColumnName
844
+ ]);
845
+ return datasetId;
846
+ }
847
+ async incrementObjectCount(datasetId, geometrySize) {
848
+ if (geometrySize === void 0) {
849
+ const statement2 = await this.driver.prepare(
850
+ "UPDATE SmRegister SET SmObjectCount = SmObjectCount + 1 WHERE SmDatasetID = ?"
851
+ );
852
+ await executeStatement(statement2, [datasetId]);
853
+ return;
854
+ }
855
+ const statement = await this.driver.prepare(
856
+ `UPDATE SmRegister
857
+ SET SmObjectCount = SmObjectCount + 1,
858
+ SmMaxGeometrySize = CASE
859
+ WHEN SmMaxGeometrySize < ? THEN ?
860
+ ELSE SmMaxGeometrySize
861
+ END
862
+ WHERE SmDatasetID = ?`
863
+ );
864
+ await executeStatement(statement, [geometrySize, geometrySize, datasetId]);
865
+ }
866
+ async incrementObjectCountBatch(datasetId, count, maxGeometrySize) {
867
+ const statement = await this.driver.prepare(
868
+ `UPDATE SmRegister
869
+ SET SmObjectCount = SmObjectCount + ?,
870
+ SmMaxGeometrySize = CASE
871
+ WHEN SmMaxGeometrySize < ? THEN ?
872
+ ELSE SmMaxGeometrySize
873
+ END
874
+ WHERE SmDatasetID = ?`
875
+ );
876
+ await executeStatement(statement, [
877
+ count,
878
+ maxGeometrySize,
879
+ maxGeometrySize,
880
+ datasetId
881
+ ]);
882
+ }
883
+ async decrementObjectCount(datasetId) {
884
+ const statement = await this.driver.prepare(
885
+ "UPDATE SmRegister SET SmObjectCount = SmObjectCount - 1 WHERE SmDatasetID = ? AND SmObjectCount > 0"
886
+ );
887
+ await executeStatement(statement, [datasetId]);
888
+ }
889
+ };
890
+
891
+ // src/core/dataset/vectorDatasetShared.ts
892
+ function normalizeGeometryBlob(value) {
893
+ return value instanceof Uint8Array ? value : new Uint8Array(value);
894
+ }
895
+ function buildListSql(tableName, options) {
896
+ const params = [];
897
+ const clauses = [];
898
+ if (options?.ids?.length) {
899
+ const placeholders = options.ids.map(() => "?").join(", ");
900
+ clauses.push(`SmID IN (${placeholders})`);
901
+ params.push(...options.ids);
902
+ }
903
+ const whereClause = clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : "";
904
+ let sql = `SELECT * FROM "${tableName}"${whereClause} ORDER BY SmID`;
905
+ if (options?.limit !== void 0) {
906
+ sql += " LIMIT ?";
907
+ params.push(options.limit);
908
+ }
909
+ if (options?.offset !== void 0) {
910
+ if (options.limit === void 0) {
911
+ sql += " LIMIT -1";
912
+ }
913
+ sql += " OFFSET ?";
914
+ params.push(options.offset);
915
+ }
916
+ return { sql, params };
917
+ }
918
+ function sqliteColumnType(field) {
919
+ switch (field.fieldType) {
920
+ case "boolean":
921
+ case "byte":
922
+ case "int16":
923
+ case "int32":
924
+ case "int64":
925
+ return "INTEGER";
926
+ case "single":
927
+ case "double":
928
+ return "REAL";
929
+ case "binary":
930
+ case "geometry":
931
+ return "BLOB";
932
+ case "date":
933
+ case "char":
934
+ case "ntext":
935
+ case "text":
936
+ case "time":
937
+ default:
938
+ return "TEXT";
939
+ }
940
+ }
941
+
942
+ // src/core/dataset/LineDataset.ts
943
+ function mapLineRow(row) {
944
+ const { SmID, SmGeometry, ...attributes } = row;
945
+ return {
946
+ id: SmID,
947
+ geometry: GaiaLineCodec.readMultiLineString(normalizeGeometryBlob(SmGeometry)),
948
+ attributes
949
+ };
950
+ }
951
+ var LineDataset = class _LineDataset extends BaseDataset {
952
+ constructor(driver, info) {
953
+ super(driver, info);
954
+ __publicField(this, "registerRepository");
955
+ this.registerRepository = new SmRegisterRepository(driver);
956
+ }
957
+ async getById(id) {
958
+ const row = await queryOne(
959
+ this.driver,
960
+ `SELECT * FROM "${this.info.tableName}" WHERE SmID = ?`,
961
+ [id]
962
+ );
963
+ return row ? mapLineRow(row) : null;
964
+ }
965
+ async list(options) {
966
+ const { sql, params } = buildListSql(this.info.tableName, options);
967
+ const rows = await queryAll(this.driver, sql, params);
968
+ return rows.map((row) => mapLineRow(row));
969
+ }
970
+ async *iterate(options) {
971
+ const { sql, params } = buildListSql(this.info.tableName, options);
972
+ const statement = await this.driver.prepare(sql);
973
+ try {
974
+ if (params.length > 0) {
975
+ await statement.bind(params);
976
+ }
977
+ while (await statement.step()) {
978
+ yield mapLineRow(await statement.getRow());
979
+ }
980
+ } finally {
981
+ await statement.finalize();
982
+ }
983
+ }
984
+ async insert(feature) {
985
+ const userFields = await this.getFields();
986
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
987
+ const placeholders = columnNames.map(() => "?").join(", ");
988
+ const geometry = GaiaLineCodec.writeMultiLineString(
989
+ feature.geometry,
990
+ feature.geometry.srid ?? this.info.srid ?? 0
991
+ );
992
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
993
+ const params = [
994
+ feature.id,
995
+ 0,
996
+ geometry,
997
+ ...userFields.map((field) => feature.attributes[field.name] ?? null)
998
+ ];
999
+ await this.driver.transaction(async () => {
1000
+ await executeSql(this.driver, sql, params);
1001
+ await this.registerRepository.incrementObjectCount(this.info.id, geometry.byteLength);
1002
+ });
1003
+ }
1004
+ async insertMany(features) {
1005
+ const userFields = await this.getFields();
1006
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
1007
+ const placeholders = columnNames.map(() => "?").join(", ");
1008
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
1009
+ await this.driver.transaction(async () => {
1010
+ const statement = await this.driver.prepare(sql);
1011
+ try {
1012
+ let count = 0;
1013
+ let maxGeometrySize = 0;
1014
+ for await (const feature of features) {
1015
+ const geometry = GaiaLineCodec.writeMultiLineString(
1016
+ feature.geometry,
1017
+ feature.geometry.srid ?? this.info.srid ?? 0
1018
+ );
1019
+ maxGeometrySize = Math.max(maxGeometrySize, geometry.byteLength);
1020
+ const params = [
1021
+ feature.id,
1022
+ 0,
1023
+ geometry,
1024
+ ...userFields.map(
1025
+ (field) => feature.attributes[field.name] ?? null
1026
+ )
1027
+ ];
1028
+ await statement.bind(params);
1029
+ await statement.step();
1030
+ await statement.reset();
1031
+ count++;
1032
+ }
1033
+ if (count > 0) {
1034
+ await this.registerRepository.incrementObjectCountBatch(
1035
+ this.info.id,
1036
+ count,
1037
+ maxGeometrySize
1038
+ );
1039
+ }
1040
+ } finally {
1041
+ await statement.finalize();
1042
+ }
1043
+ });
1044
+ }
1045
+ async count() {
1046
+ const row = await queryOne(
1047
+ this.driver,
1048
+ `SELECT COUNT(*) AS count FROM "${this.info.tableName}"`,
1049
+ []
1050
+ );
1051
+ return row?.count ?? 0;
1052
+ }
1053
+ async update(id, changes) {
1054
+ if (!changes.geometry && !changes.attributes) {
1055
+ return;
1056
+ }
1057
+ const setClauses = [];
1058
+ const params = [];
1059
+ if (changes.geometry) {
1060
+ const geometry = GaiaLineCodec.writeMultiLineString(
1061
+ changes.geometry,
1062
+ changes.geometry.srid ?? this.info.srid ?? 0
1063
+ );
1064
+ setClauses.push('"SmGeometry" = ?');
1065
+ params.push(geometry);
1066
+ }
1067
+ if (changes.attributes) {
1068
+ const userFields = await this.getFields();
1069
+ const fieldNames = new Set(userFields.map((f) => f.name));
1070
+ const validEntries = Object.entries(changes.attributes).filter(
1071
+ ([key]) => fieldNames.has(key)
1072
+ );
1073
+ for (const [key, value] of validEntries) {
1074
+ setClauses.push(`"${key}" = ?`);
1075
+ params.push(value);
1076
+ }
1077
+ }
1078
+ if (setClauses.length === 0) {
1079
+ return;
1080
+ }
1081
+ const sql = `UPDATE "${this.info.tableName}" SET ${setClauses.join(", ")} WHERE SmID = ?`;
1082
+ params.push(id);
1083
+ await this.driver.transaction(async () => {
1084
+ await executeSql(this.driver, sql, params);
1085
+ });
1086
+ }
1087
+ async delete(id) {
1088
+ await this.driver.transaction(async () => {
1089
+ await executeSql(
1090
+ this.driver,
1091
+ `DELETE FROM "${this.info.tableName}" WHERE SmID = ?`,
1092
+ [id]
1093
+ );
1094
+ await this.registerRepository.decrementObjectCount(this.info.id);
1095
+ });
1096
+ }
1097
+ static async create(driver, registerRepository, params) {
1098
+ const fields = params.fields ?? [];
1099
+ const datasetId = await registerRepository.insert({
1100
+ name: params.name,
1101
+ kind: "line",
1102
+ srid: params.srid,
1103
+ idColumnName: "SmID",
1104
+ geometryColumnName: "SmGeometry"
1105
+ });
1106
+ const userColumnDefinitions = fields.map((field) => {
1107
+ const nullability = field.nullable ? "" : " NOT NULL";
1108
+ return `"${field.name}" ${sqliteColumnType(field)}${nullability}`;
1109
+ });
1110
+ const createTableParts = [
1111
+ `"SmID" INTEGER NOT NULL PRIMARY KEY`,
1112
+ `"SmUserID" INTEGER DEFAULT 0 NOT NULL`,
1113
+ `"SmGeometry" BLOB NOT NULL`,
1114
+ ...userColumnDefinitions
1115
+ ];
1116
+ await driver.exec(
1117
+ `CREATE TABLE "${params.name}" (${createTableParts.join(", ")})`
1118
+ );
1119
+ await executeSql(
1120
+ driver,
1121
+ `INSERT INTO geometry_columns (
1122
+ f_table_name,
1123
+ f_geometry_column,
1124
+ geometry_type,
1125
+ coord_dimension,
1126
+ srid,
1127
+ spatial_index_enabled
1128
+ ) VALUES (?, ?, ?, ?, ?, ?)`,
1129
+ [params.name, "SmGeometry", 5, 2, params.srid, 0]
1130
+ );
1131
+ if (fields.length > 0) {
1132
+ const fieldInfoRepository = new SmFieldInfoRepository(driver);
1133
+ await fieldInfoRepository.insertAll(datasetId, fields);
1134
+ }
1135
+ return new _LineDataset(driver, {
1136
+ id: datasetId,
1137
+ name: params.name,
1138
+ kind: "line",
1139
+ tableName: params.name,
1140
+ srid: params.srid,
1141
+ objectCount: 0,
1142
+ geometryType: 5
1143
+ });
1144
+ }
1145
+ };
1146
+
1147
+ // src/core/dataset/LineZDataset.ts
1148
+ function mapLineZRow(row) {
1149
+ const { SmID, SmGeometry, ...attributes } = row;
1150
+ return {
1151
+ id: SmID,
1152
+ geometry: GaiaLineCodec.readMultiLineStringZ(normalizeGeometryBlob(SmGeometry)),
1153
+ attributes
1154
+ };
1155
+ }
1156
+ var LineZDataset = class _LineZDataset extends BaseDataset {
1157
+ constructor(driver, info) {
1158
+ super(driver, info);
1159
+ __publicField(this, "registerRepository");
1160
+ this.registerRepository = new SmRegisterRepository(driver);
1161
+ }
1162
+ async getById(id) {
1163
+ const row = await queryOne(
1164
+ this.driver,
1165
+ `SELECT * FROM "${this.info.tableName}" WHERE SmID = ?`,
1166
+ [id]
1167
+ );
1168
+ return row ? mapLineZRow(row) : null;
1169
+ }
1170
+ async list(options) {
1171
+ const { sql, params } = buildListSql(this.info.tableName, options);
1172
+ const rows = await queryAll(this.driver, sql, params);
1173
+ return rows.map((row) => mapLineZRow(row));
1174
+ }
1175
+ async *iterate(options) {
1176
+ const { sql, params } = buildListSql(this.info.tableName, options);
1177
+ const statement = await this.driver.prepare(sql);
1178
+ try {
1179
+ if (params.length > 0) {
1180
+ await statement.bind(params);
1181
+ }
1182
+ while (await statement.step()) {
1183
+ yield mapLineZRow(await statement.getRow());
1184
+ }
1185
+ } finally {
1186
+ await statement.finalize();
1187
+ }
1188
+ }
1189
+ async count() {
1190
+ const row = await queryOne(
1191
+ this.driver,
1192
+ `SELECT COUNT(*) AS count FROM "${this.info.tableName}"`,
1193
+ []
1194
+ );
1195
+ return row?.count ?? 0;
1196
+ }
1197
+ async insert(feature) {
1198
+ const userFields = await this.getFields();
1199
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
1200
+ const placeholders = columnNames.map(() => "?").join(", ");
1201
+ const geometry = GaiaLineCodec.writeMultiLineStringZ(
1202
+ feature.geometry,
1203
+ feature.geometry.srid ?? this.info.srid ?? 0
1204
+ );
1205
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
1206
+ const params = [
1207
+ feature.id,
1208
+ 0,
1209
+ geometry,
1210
+ ...userFields.map((field) => feature.attributes[field.name] ?? null)
1211
+ ];
1212
+ await this.driver.transaction(async () => {
1213
+ await executeSql(this.driver, sql, params);
1214
+ await this.registerRepository.incrementObjectCount(this.info.id, geometry.byteLength);
1215
+ });
1216
+ }
1217
+ async insertMany(features) {
1218
+ const userFields = await this.getFields();
1219
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
1220
+ const placeholders = columnNames.map(() => "?").join(", ");
1221
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
1222
+ await this.driver.transaction(async () => {
1223
+ const statement = await this.driver.prepare(sql);
1224
+ try {
1225
+ let count = 0;
1226
+ let maxGeometrySize = 0;
1227
+ for await (const feature of features) {
1228
+ const geometry = GaiaLineCodec.writeMultiLineStringZ(
1229
+ feature.geometry,
1230
+ feature.geometry.srid ?? this.info.srid ?? 0
1231
+ );
1232
+ maxGeometrySize = Math.max(maxGeometrySize, geometry.byteLength);
1233
+ const params = [
1234
+ feature.id,
1235
+ 0,
1236
+ geometry,
1237
+ ...userFields.map(
1238
+ (field) => feature.attributes[field.name] ?? null
1239
+ )
1240
+ ];
1241
+ await statement.bind(params);
1242
+ await statement.step();
1243
+ await statement.reset();
1244
+ count++;
1245
+ }
1246
+ if (count > 0) {
1247
+ await this.registerRepository.incrementObjectCountBatch(
1248
+ this.info.id,
1249
+ count,
1250
+ maxGeometrySize
1251
+ );
1252
+ }
1253
+ } finally {
1254
+ await statement.finalize();
1255
+ }
1256
+ });
1257
+ }
1258
+ async update(id, changes) {
1259
+ if (!changes.geometry && !changes.attributes) {
1260
+ return;
1261
+ }
1262
+ const setClauses = [];
1263
+ const params = [];
1264
+ if (changes.geometry) {
1265
+ const geometry = GaiaLineCodec.writeMultiLineStringZ(
1266
+ changes.geometry,
1267
+ changes.geometry.srid ?? this.info.srid ?? 0
1268
+ );
1269
+ setClauses.push('"SmGeometry" = ?');
1270
+ params.push(geometry);
1271
+ }
1272
+ if (changes.attributes) {
1273
+ const userFields = await this.getFields();
1274
+ const fieldNames = new Set(userFields.map((f) => f.name));
1275
+ const validEntries = Object.entries(changes.attributes).filter(
1276
+ ([key]) => fieldNames.has(key)
1277
+ );
1278
+ for (const [key, value] of validEntries) {
1279
+ setClauses.push(`"${key}" = ?`);
1280
+ params.push(value);
1281
+ }
1282
+ }
1283
+ if (setClauses.length === 0) {
1284
+ return;
1285
+ }
1286
+ const sql = `UPDATE "${this.info.tableName}" SET ${setClauses.join(", ")} WHERE SmID = ?`;
1287
+ params.push(id);
1288
+ await this.driver.transaction(async () => {
1289
+ await executeSql(this.driver, sql, params);
1290
+ });
1291
+ }
1292
+ async delete(id) {
1293
+ await this.driver.transaction(async () => {
1294
+ await executeSql(
1295
+ this.driver,
1296
+ `DELETE FROM "${this.info.tableName}" WHERE SmID = ?`,
1297
+ [id]
1298
+ );
1299
+ await this.registerRepository.decrementObjectCount(this.info.id);
1300
+ });
1301
+ }
1302
+ static async create(driver, registerRepository, params) {
1303
+ const fields = params.fields ?? [];
1304
+ const datasetId = await registerRepository.insert({
1305
+ name: params.name,
1306
+ kind: "lineZ",
1307
+ srid: params.srid,
1308
+ idColumnName: "SmID",
1309
+ geometryColumnName: "SmGeometry"
1310
+ });
1311
+ const userColumnDefinitions = fields.map((field) => {
1312
+ const nullability = field.nullable ? "" : " NOT NULL";
1313
+ return `"${field.name}" ${sqliteColumnType(field)}${nullability}`;
1314
+ });
1315
+ const createTableParts = [
1316
+ `"SmID" INTEGER NOT NULL PRIMARY KEY`,
1317
+ `"SmUserID" INTEGER DEFAULT 0 NOT NULL`,
1318
+ `"SmGeometry" BLOB NOT NULL`,
1319
+ ...userColumnDefinitions
1320
+ ];
1321
+ await driver.exec(
1322
+ `CREATE TABLE "${params.name}" (${createTableParts.join(", ")})`
1323
+ );
1324
+ await executeSql(
1325
+ driver,
1326
+ `INSERT INTO geometry_columns (
1327
+ f_table_name,
1328
+ f_geometry_column,
1329
+ geometry_type,
1330
+ coord_dimension,
1331
+ srid,
1332
+ spatial_index_enabled
1333
+ ) VALUES (?, ?, ?, ?, ?, ?)`,
1334
+ [params.name, "SmGeometry", 1005, 3, params.srid, 0]
1335
+ );
1336
+ if (fields.length > 0) {
1337
+ const fieldInfoRepository = new SmFieldInfoRepository(driver);
1338
+ await fieldInfoRepository.insertAll(datasetId, fields);
1339
+ }
1340
+ return new _LineZDataset(driver, {
1341
+ id: datasetId,
1342
+ name: params.name,
1343
+ kind: "lineZ",
1344
+ tableName: params.name,
1345
+ srid: params.srid,
1346
+ objectCount: 0,
1347
+ geometryType: 1005
1348
+ });
1349
+ }
1350
+ };
1351
+
1352
+ // src/core/dataset/PointDataset.ts
1353
+ function mapPointRow(row) {
1354
+ const { SmID, SmGeometry, ...attributes } = row;
1355
+ return {
1356
+ id: SmID,
1357
+ geometry: GaiaPointCodec.readPoint(normalizeGeometryBlob(SmGeometry)),
1358
+ attributes
1359
+ };
1360
+ }
1361
+ var PointDataset = class _PointDataset extends BaseDataset {
1362
+ constructor(driver, info) {
1363
+ super(driver, info);
1364
+ __publicField(this, "registerRepository");
1365
+ this.registerRepository = new SmRegisterRepository(driver);
1366
+ }
1367
+ async getById(id) {
1368
+ const row = await queryOne(
1369
+ this.driver,
1370
+ `SELECT * FROM "${this.info.tableName}" WHERE SmID = ?`,
1371
+ [id]
1372
+ );
1373
+ return row ? mapPointRow(row) : null;
1374
+ }
1375
+ async list(options) {
1376
+ const { sql, params } = buildListSql(this.info.tableName, options);
1377
+ const rows = await queryAll(this.driver, sql, params);
1378
+ return rows.map((row) => mapPointRow(row));
1379
+ }
1380
+ async *iterate(options) {
1381
+ const { sql, params } = buildListSql(this.info.tableName, options);
1382
+ const statement = await this.driver.prepare(sql);
1383
+ try {
1384
+ if (params.length > 0) {
1385
+ await statement.bind(params);
1386
+ }
1387
+ while (await statement.step()) {
1388
+ yield mapPointRow(await statement.getRow());
1389
+ }
1390
+ } finally {
1391
+ await statement.finalize();
1392
+ }
1393
+ }
1394
+ async insert(feature) {
1395
+ const userFields = await this.getFields();
1396
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
1397
+ const placeholders = columnNames.map(() => "?").join(", ");
1398
+ const geometry = GaiaPointCodec.writePoint(feature.geometry, feature.geometry.srid ?? this.info.srid ?? 0);
1399
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
1400
+ const params = [
1401
+ feature.id,
1402
+ 0,
1403
+ geometry,
1404
+ ...userFields.map((field) => feature.attributes[field.name] ?? null)
1405
+ ];
1406
+ await this.driver.transaction(async () => {
1407
+ await executeSql(this.driver, sql, params);
1408
+ await this.registerRepository.incrementObjectCount(this.info.id, geometry.byteLength);
1409
+ });
1410
+ }
1411
+ async insertMany(features) {
1412
+ const userFields = await this.getFields();
1413
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
1414
+ const placeholders = columnNames.map(() => "?").join(", ");
1415
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
1416
+ await this.driver.transaction(async () => {
1417
+ const statement = await this.driver.prepare(sql);
1418
+ try {
1419
+ let count = 0;
1420
+ let maxGeometrySize = 0;
1421
+ for await (const feature of features) {
1422
+ const geometry = GaiaPointCodec.writePoint(
1423
+ feature.geometry,
1424
+ feature.geometry.srid ?? this.info.srid ?? 0
1425
+ );
1426
+ maxGeometrySize = Math.max(maxGeometrySize, geometry.byteLength);
1427
+ const params = [
1428
+ feature.id,
1429
+ 0,
1430
+ geometry,
1431
+ ...userFields.map(
1432
+ (field) => feature.attributes[field.name] ?? null
1433
+ )
1434
+ ];
1435
+ await statement.bind(params);
1436
+ await statement.step();
1437
+ await statement.reset();
1438
+ count++;
1439
+ }
1440
+ if (count > 0) {
1441
+ await this.registerRepository.incrementObjectCountBatch(
1442
+ this.info.id,
1443
+ count,
1444
+ maxGeometrySize
1445
+ );
1446
+ }
1447
+ } finally {
1448
+ await statement.finalize();
1449
+ }
1450
+ });
1451
+ }
1452
+ async count() {
1453
+ const row = await queryOne(
1454
+ this.driver,
1455
+ `SELECT COUNT(*) AS count FROM "${this.info.tableName}"`,
1456
+ []
1457
+ );
1458
+ return row?.count ?? 0;
1459
+ }
1460
+ async update(id, changes) {
1461
+ if (!changes.geometry && !changes.attributes) {
1462
+ return;
1463
+ }
1464
+ const setClauses = [];
1465
+ const params = [];
1466
+ if (changes.geometry) {
1467
+ const geometry = GaiaPointCodec.writePoint(
1468
+ changes.geometry,
1469
+ changes.geometry.srid ?? this.info.srid ?? 0
1470
+ );
1471
+ setClauses.push('"SmGeometry" = ?');
1472
+ params.push(geometry);
1473
+ }
1474
+ if (changes.attributes) {
1475
+ const userFields = await this.getFields();
1476
+ const fieldNames = new Set(userFields.map((f) => f.name));
1477
+ const validEntries = Object.entries(changes.attributes).filter(
1478
+ ([key]) => fieldNames.has(key)
1479
+ );
1480
+ for (const [key, value] of validEntries) {
1481
+ setClauses.push(`"${key}" = ?`);
1482
+ params.push(value);
1483
+ }
1484
+ }
1485
+ if (setClauses.length === 0) {
1486
+ return;
1487
+ }
1488
+ const sql = `UPDATE "${this.info.tableName}" SET ${setClauses.join(", ")} WHERE SmID = ?`;
1489
+ params.push(id);
1490
+ await this.driver.transaction(async () => {
1491
+ await executeSql(this.driver, sql, params);
1492
+ });
1493
+ }
1494
+ async delete(id) {
1495
+ await this.driver.transaction(async () => {
1496
+ await executeSql(
1497
+ this.driver,
1498
+ `DELETE FROM "${this.info.tableName}" WHERE SmID = ?`,
1499
+ [id]
1500
+ );
1501
+ await this.registerRepository.decrementObjectCount(this.info.id);
1502
+ });
1503
+ }
1504
+ static async create(driver, registerRepository, params) {
1505
+ const fields = params.fields ?? [];
1506
+ const datasetId = await registerRepository.insert({
1507
+ name: params.name,
1508
+ kind: "point",
1509
+ srid: params.srid,
1510
+ idColumnName: "SmID",
1511
+ geometryColumnName: "SmGeometry"
1512
+ });
1513
+ const userColumnDefinitions = fields.map((field) => {
1514
+ const nullability = field.nullable ? "" : " NOT NULL";
1515
+ return `"${field.name}" ${sqliteColumnType(field)}${nullability}`;
1516
+ });
1517
+ const createTableParts = [
1518
+ `"SmID" INTEGER NOT NULL PRIMARY KEY`,
1519
+ `"SmUserID" INTEGER DEFAULT 0 NOT NULL`,
1520
+ `"SmGeometry" BLOB NOT NULL`,
1521
+ ...userColumnDefinitions
1522
+ ];
1523
+ await driver.exec(
1524
+ `CREATE TABLE "${params.name}" (${createTableParts.join(", ")})`
1525
+ );
1526
+ await executeSql(
1527
+ driver,
1528
+ `INSERT INTO geometry_columns (
1529
+ f_table_name,
1530
+ f_geometry_column,
1531
+ geometry_type,
1532
+ coord_dimension,
1533
+ srid,
1534
+ spatial_index_enabled
1535
+ ) VALUES (?, ?, ?, ?, ?, ?)`,
1536
+ [params.name, "SmGeometry", 1, 2, params.srid, 0]
1537
+ );
1538
+ if (fields.length > 0) {
1539
+ const fieldInfoRepository = new SmFieldInfoRepository(driver);
1540
+ await fieldInfoRepository.insertAll(datasetId, fields);
1541
+ }
1542
+ return new _PointDataset(driver, {
1543
+ id: datasetId,
1544
+ name: params.name,
1545
+ kind: "point",
1546
+ tableName: params.name,
1547
+ srid: params.srid,
1548
+ objectCount: 0,
1549
+ geometryType: 1
1550
+ });
1551
+ }
1552
+ };
1553
+
1554
+ // src/core/dataset/PointZDataset.ts
1555
+ function mapPointZRow(row) {
1556
+ const { SmID, SmGeometry, ...attributes } = row;
1557
+ return {
1558
+ id: SmID,
1559
+ geometry: GaiaPointCodec.readPointZ(normalizeGeometryBlob(SmGeometry)),
1560
+ attributes
1561
+ };
1562
+ }
1563
+ var PointZDataset = class _PointZDataset extends BaseDataset {
1564
+ constructor(driver, info) {
1565
+ super(driver, info);
1566
+ __publicField(this, "registerRepository");
1567
+ this.registerRepository = new SmRegisterRepository(driver);
1568
+ }
1569
+ async getById(id) {
1570
+ const row = await queryOne(
1571
+ this.driver,
1572
+ `SELECT * FROM "${this.info.tableName}" WHERE SmID = ?`,
1573
+ [id]
1574
+ );
1575
+ return row ? mapPointZRow(row) : null;
1576
+ }
1577
+ async list(options) {
1578
+ const { sql, params } = buildListSql(this.info.tableName, options);
1579
+ const rows = await queryAll(this.driver, sql, params);
1580
+ return rows.map((row) => mapPointZRow(row));
1581
+ }
1582
+ async *iterate(options) {
1583
+ const { sql, params } = buildListSql(this.info.tableName, options);
1584
+ const statement = await this.driver.prepare(sql);
1585
+ try {
1586
+ if (params.length > 0) {
1587
+ await statement.bind(params);
1588
+ }
1589
+ while (await statement.step()) {
1590
+ yield mapPointZRow(await statement.getRow());
1591
+ }
1592
+ } finally {
1593
+ await statement.finalize();
1594
+ }
1595
+ }
1596
+ async count() {
1597
+ const row = await queryOne(
1598
+ this.driver,
1599
+ `SELECT COUNT(*) AS count FROM "${this.info.tableName}"`,
1600
+ []
1601
+ );
1602
+ return row?.count ?? 0;
1603
+ }
1604
+ async insert(feature) {
1605
+ const userFields = await this.getFields();
1606
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
1607
+ const placeholders = columnNames.map(() => "?").join(", ");
1608
+ const geometry = GaiaPointCodec.writePointZ(
1609
+ feature.geometry,
1610
+ feature.geometry.srid ?? this.info.srid ?? 0
1611
+ );
1612
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
1613
+ const params = [
1614
+ feature.id,
1615
+ 0,
1616
+ geometry,
1617
+ ...userFields.map((field) => feature.attributes[field.name] ?? null)
1618
+ ];
1619
+ await this.driver.transaction(async () => {
1620
+ await executeSql(this.driver, sql, params);
1621
+ await this.registerRepository.incrementObjectCount(this.info.id, geometry.byteLength);
1622
+ });
1623
+ }
1624
+ async insertMany(features) {
1625
+ const userFields = await this.getFields();
1626
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
1627
+ const placeholders = columnNames.map(() => "?").join(", ");
1628
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
1629
+ await this.driver.transaction(async () => {
1630
+ const statement = await this.driver.prepare(sql);
1631
+ try {
1632
+ let count = 0;
1633
+ let maxGeometrySize = 0;
1634
+ for await (const feature of features) {
1635
+ const geometry = GaiaPointCodec.writePointZ(
1636
+ feature.geometry,
1637
+ feature.geometry.srid ?? this.info.srid ?? 0
1638
+ );
1639
+ maxGeometrySize = Math.max(maxGeometrySize, geometry.byteLength);
1640
+ const params = [
1641
+ feature.id,
1642
+ 0,
1643
+ geometry,
1644
+ ...userFields.map(
1645
+ (field) => feature.attributes[field.name] ?? null
1646
+ )
1647
+ ];
1648
+ await statement.bind(params);
1649
+ await statement.step();
1650
+ await statement.reset();
1651
+ count++;
1652
+ }
1653
+ if (count > 0) {
1654
+ await this.registerRepository.incrementObjectCountBatch(
1655
+ this.info.id,
1656
+ count,
1657
+ maxGeometrySize
1658
+ );
1659
+ }
1660
+ } finally {
1661
+ await statement.finalize();
1662
+ }
1663
+ });
1664
+ }
1665
+ async update(id, changes) {
1666
+ if (!changes.geometry && !changes.attributes) {
1667
+ return;
1668
+ }
1669
+ const setClauses = [];
1670
+ const params = [];
1671
+ if (changes.geometry) {
1672
+ const geometry = GaiaPointCodec.writePointZ(
1673
+ changes.geometry,
1674
+ changes.geometry.srid ?? this.info.srid ?? 0
1675
+ );
1676
+ setClauses.push('"SmGeometry" = ?');
1677
+ params.push(geometry);
1678
+ }
1679
+ if (changes.attributes) {
1680
+ const userFields = await this.getFields();
1681
+ const fieldNames = new Set(userFields.map((f) => f.name));
1682
+ const validEntries = Object.entries(changes.attributes).filter(
1683
+ ([key]) => fieldNames.has(key)
1684
+ );
1685
+ for (const [key, value] of validEntries) {
1686
+ setClauses.push(`"${key}" = ?`);
1687
+ params.push(value);
1688
+ }
1689
+ }
1690
+ if (setClauses.length === 0) {
1691
+ return;
1692
+ }
1693
+ const sql = `UPDATE "${this.info.tableName}" SET ${setClauses.join(", ")} WHERE SmID = ?`;
1694
+ params.push(id);
1695
+ await this.driver.transaction(async () => {
1696
+ await executeSql(this.driver, sql, params);
1697
+ });
1698
+ }
1699
+ async delete(id) {
1700
+ await this.driver.transaction(async () => {
1701
+ await executeSql(
1702
+ this.driver,
1703
+ `DELETE FROM "${this.info.tableName}" WHERE SmID = ?`,
1704
+ [id]
1705
+ );
1706
+ await this.registerRepository.decrementObjectCount(this.info.id);
1707
+ });
1708
+ }
1709
+ static async create(driver, registerRepository, params) {
1710
+ const fields = params.fields ?? [];
1711
+ const datasetId = await registerRepository.insert({
1712
+ name: params.name,
1713
+ kind: "pointZ",
1714
+ srid: params.srid,
1715
+ idColumnName: "SmID",
1716
+ geometryColumnName: "SmGeometry"
1717
+ });
1718
+ const userColumnDefinitions = fields.map((field) => {
1719
+ const nullability = field.nullable ? "" : " NOT NULL";
1720
+ return `"${field.name}" ${sqliteColumnType(field)}${nullability}`;
1721
+ });
1722
+ const createTableParts = [
1723
+ `"SmID" INTEGER NOT NULL PRIMARY KEY`,
1724
+ `"SmUserID" INTEGER DEFAULT 0 NOT NULL`,
1725
+ `"SmGeometry" BLOB NOT NULL`,
1726
+ ...userColumnDefinitions
1727
+ ];
1728
+ await driver.exec(
1729
+ `CREATE TABLE "${params.name}" (${createTableParts.join(", ")})`
1730
+ );
1731
+ await executeSql(
1732
+ driver,
1733
+ `INSERT INTO geometry_columns (
1734
+ f_table_name,
1735
+ f_geometry_column,
1736
+ geometry_type,
1737
+ coord_dimension,
1738
+ srid,
1739
+ spatial_index_enabled
1740
+ ) VALUES (?, ?, ?, ?, ?, ?)`,
1741
+ [params.name, "SmGeometry", 1001, 3, params.srid, 0]
1742
+ );
1743
+ if (fields.length > 0) {
1744
+ const fieldInfoRepository = new SmFieldInfoRepository(driver);
1745
+ await fieldInfoRepository.insertAll(datasetId, fields);
1746
+ }
1747
+ return new _PointZDataset(driver, {
1748
+ id: datasetId,
1749
+ name: params.name,
1750
+ kind: "pointZ",
1751
+ tableName: params.name,
1752
+ srid: params.srid,
1753
+ objectCount: 0,
1754
+ geometryType: 1001
1755
+ });
1756
+ }
1757
+ };
1758
+
1759
+ // src/core/geometry/gaia/GaiaPolygonCodec.ts
1760
+ var GAIA_ENTITY_MARK2 = 105;
1761
+ var GEO_TYPE_POLYGON = 3;
1762
+ var GEO_TYPE_POLYGONZ = 1003;
1763
+ function is3DCoordinates2(coordinates) {
1764
+ return coordinates[0]?.[0]?.[0]?.length === 3;
1765
+ }
1766
+ function createPolygonMbr(coordinates) {
1767
+ const xs = [];
1768
+ const ys = [];
1769
+ for (const polygon of coordinates) {
1770
+ for (const ring of polygon) {
1771
+ for (const point of ring) {
1772
+ xs.push(point[0]);
1773
+ ys.push(point[1]);
1774
+ }
1775
+ }
1776
+ }
1777
+ if (xs.length === 0) {
1778
+ throw new GaiaFormatError("MultiPolygon must contain at least one point.");
1779
+ }
1780
+ return [
1781
+ Math.min(...xs),
1782
+ Math.min(...ys),
1783
+ Math.max(...xs),
1784
+ Math.max(...ys)
1785
+ ];
1786
+ }
1787
+ function writeRing2D(writer2, ring) {
1788
+ writer2.writeInt32(ring.length, true);
1789
+ for (const point of ring) {
1790
+ writer2.writeFloat64(point[0], true);
1791
+ writer2.writeFloat64(point[1], true);
1792
+ }
1793
+ }
1794
+ function writeRing3D(writer2, ring) {
1795
+ writer2.writeInt32(ring.length, true);
1796
+ for (const point of ring) {
1797
+ writer2.writeFloat64(point[0], true);
1798
+ writer2.writeFloat64(point[1], true);
1799
+ writer2.writeFloat64(point[2], true);
1800
+ }
1801
+ }
1802
+ function readRing2D(cursor) {
1803
+ const pointCount = cursor.readInt32(true);
1804
+ const ring = [];
1805
+ for (let pointIndex = 0; pointIndex < pointCount; pointIndex += 1) {
1806
+ ring.push([cursor.readFloat64(true), cursor.readFloat64(true)]);
1807
+ }
1808
+ return ring;
1809
+ }
1810
+ function readRing3D(cursor) {
1811
+ const pointCount = cursor.readInt32(true);
1812
+ const ring = [];
1813
+ for (let pointIndex = 0; pointIndex < pointCount; pointIndex += 1) {
1814
+ ring.push([
1815
+ cursor.readFloat64(true),
1816
+ cursor.readFloat64(true),
1817
+ cursor.readFloat64(true)
1818
+ ]);
1819
+ }
1820
+ return ring;
1821
+ }
1822
+ var GaiaPolygonCodec = class {
1823
+ static readMultiPolygon(input) {
1824
+ const cursor = new BinaryCursor(input);
1825
+ const header = readGaiaHeader(cursor, GEO_TYPE_MULTIPOLYGON);
1826
+ const polygonCount = cursor.readInt32(true);
1827
+ const coordinates = [];
1828
+ for (let polygonIndex = 0; polygonIndex < polygonCount; polygonIndex += 1) {
1829
+ const entityMark = cursor.readUint8();
1830
+ if (entityMark !== GAIA_ENTITY_MARK2) {
1831
+ throw new GaiaFormatError(
1832
+ `Invalid Polygon entity mark: expected 0x${GAIA_ENTITY_MARK2.toString(16)}, got 0x${entityMark.toString(16)}.`
1833
+ );
1834
+ }
1835
+ const polygonGeoType = cursor.readInt32(true);
1836
+ if (polygonGeoType !== GEO_TYPE_POLYGON) {
1837
+ throw new GaiaFormatError(
1838
+ `Invalid Polygon geoType: expected ${GEO_TYPE_POLYGON}, got ${polygonGeoType}.`
1839
+ );
1840
+ }
1841
+ const ringCount = cursor.readInt32(true);
1842
+ if (ringCount < 1) {
1843
+ throw new GaiaFormatError(
1844
+ `Polygon must contain at least one ring, got ${ringCount}.`
1845
+ );
1846
+ }
1847
+ const polygon = [];
1848
+ for (let ringIndex = 0; ringIndex < ringCount; ringIndex += 1) {
1849
+ polygon.push(readRing2D(cursor));
1850
+ }
1851
+ coordinates.push(polygon);
1852
+ }
1853
+ validateGaiaEnd(cursor);
1854
+ return {
1855
+ type: "MultiPolygon",
1856
+ coordinates,
1857
+ srid: header.srid,
1858
+ bbox: header.mbr,
1859
+ hasZ: false,
1860
+ geoType: header.geoType
1861
+ };
1862
+ }
1863
+ static readMultiPolygonZ(input) {
1864
+ const cursor = new BinaryCursor(input);
1865
+ const header = readGaiaHeader(cursor, GEO_TYPE_MULTIPOLYGONZ);
1866
+ const polygonCount = cursor.readInt32(true);
1867
+ const coordinates = [];
1868
+ for (let polygonIndex = 0; polygonIndex < polygonCount; polygonIndex += 1) {
1869
+ const entityMark = cursor.readUint8();
1870
+ if (entityMark !== GAIA_ENTITY_MARK2) {
1871
+ throw new GaiaFormatError(
1872
+ `Invalid Polygon entity mark: expected 0x${GAIA_ENTITY_MARK2.toString(16)}, got 0x${entityMark.toString(16)}.`
1873
+ );
1874
+ }
1875
+ const polygonGeoType = cursor.readInt32(true);
1876
+ if (polygonGeoType !== GEO_TYPE_POLYGONZ) {
1877
+ throw new GaiaFormatError(
1878
+ `Invalid PolygonZ geoType: expected ${GEO_TYPE_POLYGONZ}, got ${polygonGeoType}.`
1879
+ );
1880
+ }
1881
+ const ringCount = cursor.readInt32(true);
1882
+ if (ringCount < 1) {
1883
+ throw new GaiaFormatError(
1884
+ `Polygon must contain at least one ring, got ${ringCount}.`
1885
+ );
1886
+ }
1887
+ const polygon = [];
1888
+ for (let ringIndex = 0; ringIndex < ringCount; ringIndex += 1) {
1889
+ polygon.push(readRing3D(cursor));
1890
+ }
1891
+ coordinates.push(polygon);
1892
+ }
1893
+ validateGaiaEnd(cursor);
1894
+ return {
1895
+ type: "MultiPolygon",
1896
+ coordinates,
1897
+ srid: header.srid,
1898
+ bbox: header.mbr,
1899
+ hasZ: true,
1900
+ geoType: header.geoType
1901
+ };
1902
+ }
1903
+ static writeMultiPolygon(geometry, srid) {
1904
+ if (is3DCoordinates2(geometry.coordinates)) {
1905
+ throw new GaiaFormatError("writeMultiPolygon expects 2D coordinates.");
1906
+ }
1907
+ const writer2 = new BinaryWriter();
1908
+ writeGaiaHeader(
1909
+ writer2,
1910
+ srid,
1911
+ createPolygonMbr(geometry.coordinates),
1912
+ GEO_TYPE_MULTIPOLYGON
1913
+ );
1914
+ writer2.writeInt32(geometry.coordinates.length, true);
1915
+ for (const polygon of geometry.coordinates) {
1916
+ writer2.writeUint8(GAIA_ENTITY_MARK2);
1917
+ writer2.writeInt32(GEO_TYPE_POLYGON, true);
1918
+ writer2.writeInt32(polygon.length, true);
1919
+ for (const ring of polygon) {
1920
+ writeRing2D(writer2, ring);
1921
+ }
1922
+ }
1923
+ writer2.writeUint8(GAIA_END);
1924
+ return writer2.toUint8Array();
1925
+ }
1926
+ static writeMultiPolygonZ(geometry, srid) {
1927
+ if (!is3DCoordinates2(geometry.coordinates)) {
1928
+ throw new GaiaFormatError("writeMultiPolygonZ expects 3D coordinates.");
1929
+ }
1930
+ const writer2 = new BinaryWriter();
1931
+ writeGaiaHeader(
1932
+ writer2,
1933
+ srid,
1934
+ createPolygonMbr(geometry.coordinates),
1935
+ GEO_TYPE_MULTIPOLYGONZ
1936
+ );
1937
+ writer2.writeInt32(geometry.coordinates.length, true);
1938
+ for (const polygon of geometry.coordinates) {
1939
+ writer2.writeUint8(GAIA_ENTITY_MARK2);
1940
+ writer2.writeInt32(GEO_TYPE_POLYGONZ, true);
1941
+ writer2.writeInt32(polygon.length, true);
1942
+ for (const ring of polygon) {
1943
+ writeRing3D(writer2, ring);
1944
+ }
1945
+ }
1946
+ writer2.writeUint8(GAIA_END);
1947
+ return writer2.toUint8Array();
1948
+ }
1949
+ };
1950
+
1951
+ // src/core/dataset/RegionDataset.ts
1952
+ function mapRegionRow(row) {
1953
+ const { SmID, SmGeometry, ...attributes } = row;
1954
+ return {
1955
+ id: SmID,
1956
+ geometry: GaiaPolygonCodec.readMultiPolygon(normalizeGeometryBlob(SmGeometry)),
1957
+ attributes
1958
+ };
1959
+ }
1960
+ var RegionDataset = class _RegionDataset extends BaseDataset {
1961
+ constructor(driver, info) {
1962
+ super(driver, info);
1963
+ __publicField(this, "registerRepository");
1964
+ this.registerRepository = new SmRegisterRepository(driver);
1965
+ }
1966
+ async getById(id) {
1967
+ const row = await queryOne(
1968
+ this.driver,
1969
+ `SELECT * FROM "${this.info.tableName}" WHERE SmID = ?`,
1970
+ [id]
1971
+ );
1972
+ return row ? mapRegionRow(row) : null;
1973
+ }
1974
+ async list(options) {
1975
+ const { sql, params } = buildListSql(this.info.tableName, options);
1976
+ const rows = await queryAll(this.driver, sql, params);
1977
+ return rows.map((row) => mapRegionRow(row));
1978
+ }
1979
+ async *iterate(options) {
1980
+ const { sql, params } = buildListSql(this.info.tableName, options);
1981
+ const statement = await this.driver.prepare(sql);
1982
+ try {
1983
+ if (params.length > 0) {
1984
+ await statement.bind(params);
1985
+ }
1986
+ while (await statement.step()) {
1987
+ yield mapRegionRow(
1988
+ await statement.getRow()
1989
+ );
1990
+ }
1991
+ } finally {
1992
+ await statement.finalize();
1993
+ }
1994
+ }
1995
+ async insert(feature) {
1996
+ const userFields = await this.getFields();
1997
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
1998
+ const placeholders = columnNames.map(() => "?").join(", ");
1999
+ const geometry = GaiaPolygonCodec.writeMultiPolygon(
2000
+ feature.geometry,
2001
+ feature.geometry.srid ?? this.info.srid ?? 0
2002
+ );
2003
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
2004
+ const params = [
2005
+ feature.id,
2006
+ 0,
2007
+ geometry,
2008
+ ...userFields.map((field) => feature.attributes[field.name] ?? null)
2009
+ ];
2010
+ await this.driver.transaction(async () => {
2011
+ await executeSql(this.driver, sql, params);
2012
+ await this.registerRepository.incrementObjectCount(this.info.id, geometry.byteLength);
2013
+ });
2014
+ }
2015
+ async insertMany(features) {
2016
+ const userFields = await this.getFields();
2017
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
2018
+ const placeholders = columnNames.map(() => "?").join(", ");
2019
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
2020
+ await this.driver.transaction(async () => {
2021
+ const statement = await this.driver.prepare(sql);
2022
+ try {
2023
+ let count = 0;
2024
+ let maxGeometrySize = 0;
2025
+ for await (const feature of features) {
2026
+ const geometry = GaiaPolygonCodec.writeMultiPolygon(
2027
+ feature.geometry,
2028
+ feature.geometry.srid ?? this.info.srid ?? 0
2029
+ );
2030
+ maxGeometrySize = Math.max(maxGeometrySize, geometry.byteLength);
2031
+ const params = [
2032
+ feature.id,
2033
+ 0,
2034
+ geometry,
2035
+ ...userFields.map(
2036
+ (field) => feature.attributes[field.name] ?? null
2037
+ )
2038
+ ];
2039
+ await statement.bind(params);
2040
+ await statement.step();
2041
+ await statement.reset();
2042
+ count++;
2043
+ }
2044
+ if (count > 0) {
2045
+ await this.registerRepository.incrementObjectCountBatch(
2046
+ this.info.id,
2047
+ count,
2048
+ maxGeometrySize
2049
+ );
2050
+ }
2051
+ } finally {
2052
+ await statement.finalize();
2053
+ }
2054
+ });
2055
+ }
2056
+ async count() {
2057
+ const row = await queryOne(
2058
+ this.driver,
2059
+ `SELECT COUNT(*) AS count FROM "${this.info.tableName}"`,
2060
+ []
2061
+ );
2062
+ return row?.count ?? 0;
2063
+ }
2064
+ async update(id, changes) {
2065
+ if (!changes.geometry && !changes.attributes) {
2066
+ return;
2067
+ }
2068
+ const setClauses = [];
2069
+ const params = [];
2070
+ if (changes.geometry) {
2071
+ const geometry = GaiaPolygonCodec.writeMultiPolygon(
2072
+ changes.geometry,
2073
+ changes.geometry.srid ?? this.info.srid ?? 0
2074
+ );
2075
+ setClauses.push('"SmGeometry" = ?');
2076
+ params.push(geometry);
2077
+ }
2078
+ if (changes.attributes) {
2079
+ const userFields = await this.getFields();
2080
+ const fieldNames = new Set(userFields.map((f) => f.name));
2081
+ const validEntries = Object.entries(changes.attributes).filter(
2082
+ ([key]) => fieldNames.has(key)
2083
+ );
2084
+ for (const [key, value] of validEntries) {
2085
+ setClauses.push(`"${key}" = ?`);
2086
+ params.push(value);
2087
+ }
2088
+ }
2089
+ if (setClauses.length === 0) {
2090
+ return;
2091
+ }
2092
+ const sql = `UPDATE "${this.info.tableName}" SET ${setClauses.join(", ")} WHERE SmID = ?`;
2093
+ params.push(id);
2094
+ await this.driver.transaction(async () => {
2095
+ await executeSql(this.driver, sql, params);
2096
+ });
2097
+ }
2098
+ async delete(id) {
2099
+ await this.driver.transaction(async () => {
2100
+ await executeSql(
2101
+ this.driver,
2102
+ `DELETE FROM "${this.info.tableName}" WHERE SmID = ?`,
2103
+ [id]
2104
+ );
2105
+ await this.registerRepository.decrementObjectCount(this.info.id);
2106
+ });
2107
+ }
2108
+ static async create(driver, registerRepository, params) {
2109
+ const fields = params.fields ?? [];
2110
+ const datasetId = await registerRepository.insert({
2111
+ name: params.name,
2112
+ kind: "region",
2113
+ srid: params.srid,
2114
+ idColumnName: "SmID",
2115
+ geometryColumnName: "SmGeometry"
2116
+ });
2117
+ const userColumnDefinitions = fields.map((field) => {
2118
+ const nullability = field.nullable ? "" : " NOT NULL";
2119
+ return `"${field.name}" ${sqliteColumnType(field)}${nullability}`;
2120
+ });
2121
+ const createTableParts = [
2122
+ `"SmID" INTEGER NOT NULL PRIMARY KEY`,
2123
+ `"SmUserID" INTEGER DEFAULT 0 NOT NULL`,
2124
+ `"SmGeometry" BLOB NOT NULL`,
2125
+ ...userColumnDefinitions
2126
+ ];
2127
+ await driver.exec(
2128
+ `CREATE TABLE "${params.name}" (${createTableParts.join(", ")})`
2129
+ );
2130
+ await executeSql(
2131
+ driver,
2132
+ `INSERT INTO geometry_columns (
2133
+ f_table_name,
2134
+ f_geometry_column,
2135
+ geometry_type,
2136
+ coord_dimension,
2137
+ srid,
2138
+ spatial_index_enabled
2139
+ ) VALUES (?, ?, ?, ?, ?, ?)`,
2140
+ [params.name, "SmGeometry", 6, 2, params.srid, 0]
2141
+ );
2142
+ if (fields.length > 0) {
2143
+ const fieldInfoRepository = new SmFieldInfoRepository(driver);
2144
+ await fieldInfoRepository.insertAll(datasetId, fields);
2145
+ }
2146
+ return new _RegionDataset(driver, {
2147
+ id: datasetId,
2148
+ name: params.name,
2149
+ kind: "region",
2150
+ tableName: params.name,
2151
+ srid: params.srid,
2152
+ objectCount: 0,
2153
+ geometryType: 6
2154
+ });
2155
+ }
2156
+ };
2157
+
2158
+ // src/core/dataset/RegionZDataset.ts
2159
+ function mapRegionZRow(row) {
2160
+ const { SmID, SmGeometry, ...attributes } = row;
2161
+ return {
2162
+ id: SmID,
2163
+ geometry: GaiaPolygonCodec.readMultiPolygonZ(normalizeGeometryBlob(SmGeometry)),
2164
+ attributes
2165
+ };
2166
+ }
2167
+ var RegionZDataset = class _RegionZDataset extends BaseDataset {
2168
+ constructor(driver, info) {
2169
+ super(driver, info);
2170
+ __publicField(this, "registerRepository");
2171
+ this.registerRepository = new SmRegisterRepository(driver);
2172
+ }
2173
+ async getById(id) {
2174
+ const row = await queryOne(
2175
+ this.driver,
2176
+ `SELECT * FROM "${this.info.tableName}" WHERE SmID = ?`,
2177
+ [id]
2178
+ );
2179
+ return row ? mapRegionZRow(row) : null;
2180
+ }
2181
+ async list(options) {
2182
+ const { sql, params } = buildListSql(this.info.tableName, options);
2183
+ const rows = await queryAll(this.driver, sql, params);
2184
+ return rows.map((row) => mapRegionZRow(row));
2185
+ }
2186
+ async *iterate(options) {
2187
+ const { sql, params } = buildListSql(this.info.tableName, options);
2188
+ const statement = await this.driver.prepare(sql);
2189
+ try {
2190
+ if (params.length > 0) {
2191
+ await statement.bind(params);
2192
+ }
2193
+ while (await statement.step()) {
2194
+ yield mapRegionZRow(
2195
+ await statement.getRow()
2196
+ );
2197
+ }
2198
+ } finally {
2199
+ await statement.finalize();
2200
+ }
2201
+ }
2202
+ async count() {
2203
+ const row = await queryOne(
2204
+ this.driver,
2205
+ `SELECT COUNT(*) AS count FROM "${this.info.tableName}"`,
2206
+ []
2207
+ );
2208
+ return row?.count ?? 0;
2209
+ }
2210
+ async insert(feature) {
2211
+ const userFields = await this.getFields();
2212
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
2213
+ const placeholders = columnNames.map(() => "?").join(", ");
2214
+ const geometry = GaiaPolygonCodec.writeMultiPolygonZ(
2215
+ feature.geometry,
2216
+ feature.geometry.srid ?? this.info.srid ?? 0
2217
+ );
2218
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
2219
+ const params = [
2220
+ feature.id,
2221
+ 0,
2222
+ geometry,
2223
+ ...userFields.map((field) => feature.attributes[field.name] ?? null)
2224
+ ];
2225
+ await this.driver.transaction(async () => {
2226
+ await executeSql(this.driver, sql, params);
2227
+ await this.registerRepository.incrementObjectCount(this.info.id, geometry.byteLength);
2228
+ });
2229
+ }
2230
+ async insertMany(features) {
2231
+ const userFields = await this.getFields();
2232
+ const columnNames = ["SmID", "SmUserID", "SmGeometry", ...userFields.map((field) => field.name)];
2233
+ const placeholders = columnNames.map(() => "?").join(", ");
2234
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
2235
+ await this.driver.transaction(async () => {
2236
+ const statement = await this.driver.prepare(sql);
2237
+ try {
2238
+ let count = 0;
2239
+ let maxGeometrySize = 0;
2240
+ for await (const feature of features) {
2241
+ const geometry = GaiaPolygonCodec.writeMultiPolygonZ(
2242
+ feature.geometry,
2243
+ feature.geometry.srid ?? this.info.srid ?? 0
2244
+ );
2245
+ maxGeometrySize = Math.max(maxGeometrySize, geometry.byteLength);
2246
+ const params = [
2247
+ feature.id,
2248
+ 0,
2249
+ geometry,
2250
+ ...userFields.map(
2251
+ (field) => feature.attributes[field.name] ?? null
2252
+ )
2253
+ ];
2254
+ await statement.bind(params);
2255
+ await statement.step();
2256
+ await statement.reset();
2257
+ count++;
2258
+ }
2259
+ if (count > 0) {
2260
+ await this.registerRepository.incrementObjectCountBatch(
2261
+ this.info.id,
2262
+ count,
2263
+ maxGeometrySize
2264
+ );
2265
+ }
2266
+ } finally {
2267
+ await statement.finalize();
2268
+ }
2269
+ });
2270
+ }
2271
+ async update(id, changes) {
2272
+ if (!changes.geometry && !changes.attributes) {
2273
+ return;
2274
+ }
2275
+ const setClauses = [];
2276
+ const params = [];
2277
+ if (changes.geometry) {
2278
+ const geometry = GaiaPolygonCodec.writeMultiPolygonZ(
2279
+ changes.geometry,
2280
+ changes.geometry.srid ?? this.info.srid ?? 0
2281
+ );
2282
+ setClauses.push('"SmGeometry" = ?');
2283
+ params.push(geometry);
2284
+ }
2285
+ if (changes.attributes) {
2286
+ const userFields = await this.getFields();
2287
+ const fieldNames = new Set(userFields.map((f) => f.name));
2288
+ const validEntries = Object.entries(changes.attributes).filter(
2289
+ ([key]) => fieldNames.has(key)
2290
+ );
2291
+ for (const [key, value] of validEntries) {
2292
+ setClauses.push(`"${key}" = ?`);
2293
+ params.push(value);
2294
+ }
2295
+ }
2296
+ if (setClauses.length === 0) {
2297
+ return;
2298
+ }
2299
+ const sql = `UPDATE "${this.info.tableName}" SET ${setClauses.join(", ")} WHERE SmID = ?`;
2300
+ params.push(id);
2301
+ await this.driver.transaction(async () => {
2302
+ await executeSql(this.driver, sql, params);
2303
+ });
2304
+ }
2305
+ async delete(id) {
2306
+ await this.driver.transaction(async () => {
2307
+ await executeSql(
2308
+ this.driver,
2309
+ `DELETE FROM "${this.info.tableName}" WHERE SmID = ?`,
2310
+ [id]
2311
+ );
2312
+ await this.registerRepository.decrementObjectCount(this.info.id);
2313
+ });
2314
+ }
2315
+ static async create(driver, registerRepository, params) {
2316
+ const fields = params.fields ?? [];
2317
+ const datasetId = await registerRepository.insert({
2318
+ name: params.name,
2319
+ kind: "regionZ",
2320
+ srid: params.srid,
2321
+ idColumnName: "SmID",
2322
+ geometryColumnName: "SmGeometry"
2323
+ });
2324
+ const userColumnDefinitions = fields.map((field) => {
2325
+ const nullability = field.nullable ? "" : " NOT NULL";
2326
+ return `"${field.name}" ${sqliteColumnType(field)}${nullability}`;
2327
+ });
2328
+ const createTableParts = [
2329
+ `"SmID" INTEGER NOT NULL PRIMARY KEY`,
2330
+ `"SmUserID" INTEGER DEFAULT 0 NOT NULL`,
2331
+ `"SmGeometry" BLOB NOT NULL`,
2332
+ ...userColumnDefinitions
2333
+ ];
2334
+ await driver.exec(
2335
+ `CREATE TABLE "${params.name}" (${createTableParts.join(", ")})`
2336
+ );
2337
+ await executeSql(
2338
+ driver,
2339
+ `INSERT INTO geometry_columns (
2340
+ f_table_name,
2341
+ f_geometry_column,
2342
+ geometry_type,
2343
+ coord_dimension,
2344
+ srid,
2345
+ spatial_index_enabled
2346
+ ) VALUES (?, ?, ?, ?, ?, ?)`,
2347
+ [params.name, "SmGeometry", 1006, 3, params.srid, 0]
2348
+ );
2349
+ if (fields.length > 0) {
2350
+ const fieldInfoRepository = new SmFieldInfoRepository(driver);
2351
+ await fieldInfoRepository.insertAll(datasetId, fields);
2352
+ }
2353
+ return new _RegionZDataset(driver, {
2354
+ id: datasetId,
2355
+ name: params.name,
2356
+ kind: "regionZ",
2357
+ tableName: params.name,
2358
+ srid: params.srid,
2359
+ objectCount: 0,
2360
+ geometryType: 1006
2361
+ });
2362
+ }
2363
+ };
2364
+
2365
+ // src/core/dataset/TabularDataset.ts
2366
+ var SYSTEM_COLUMN_PREFIX = "Sm";
2367
+ function mapTabularRow(row) {
2368
+ const { SmID, ...rest } = row;
2369
+ const attributes = {};
2370
+ for (const [key, value] of Object.entries(rest)) {
2371
+ if (!key.startsWith(SYSTEM_COLUMN_PREFIX)) {
2372
+ attributes[key] = value;
2373
+ }
2374
+ }
2375
+ return {
2376
+ id: SmID,
2377
+ attributes
2378
+ };
2379
+ }
2380
+ var TabularDataset = class _TabularDataset extends BaseDataset {
2381
+ constructor(driver, info) {
2382
+ super(driver, info);
2383
+ __publicField(this, "registerRepository");
2384
+ this.registerRepository = new SmRegisterRepository(driver);
2385
+ }
2386
+ async getById(id) {
2387
+ const row = await queryOne(
2388
+ this.driver,
2389
+ `SELECT * FROM "${this.info.tableName}" WHERE SmID = ?`,
2390
+ [id]
2391
+ );
2392
+ return row ? mapTabularRow(row) : null;
2393
+ }
2394
+ async list(options) {
2395
+ const { sql, params } = buildListSql(this.info.tableName, options);
2396
+ const rows = await queryAll(this.driver, sql, params);
2397
+ return rows.map((row) => mapTabularRow(row));
2398
+ }
2399
+ async *iterate(options) {
2400
+ const { sql, params } = buildListSql(this.info.tableName, options);
2401
+ const statement = await this.driver.prepare(sql);
2402
+ try {
2403
+ if (params.length > 0) {
2404
+ await statement.bind(params);
2405
+ }
2406
+ while (await statement.step()) {
2407
+ yield mapTabularRow(
2408
+ await statement.getRow()
2409
+ );
2410
+ }
2411
+ } finally {
2412
+ await statement.finalize();
2413
+ }
2414
+ }
2415
+ async count() {
2416
+ const row = await queryOne(
2417
+ this.driver,
2418
+ `SELECT COUNT(*) AS count FROM "${this.info.tableName}"`,
2419
+ []
2420
+ );
2421
+ return row?.count ?? 0;
2422
+ }
2423
+ async insert(record) {
2424
+ const userFields = await this.getFields();
2425
+ const columnNames = [
2426
+ "SmID",
2427
+ "SmUserID",
2428
+ ...userFields.map((field) => field.name)
2429
+ ];
2430
+ const placeholders = columnNames.map(() => "?").join(", ");
2431
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
2432
+ const params = [
2433
+ record.id,
2434
+ 0,
2435
+ ...userFields.map(
2436
+ (field) => record.attributes[field.name] ?? null
2437
+ )
2438
+ ];
2439
+ await this.driver.transaction(async () => {
2440
+ await executeSql(this.driver, sql, params);
2441
+ await this.registerRepository.incrementObjectCount(this.info.id);
2442
+ });
2443
+ }
2444
+ async insertMany(records) {
2445
+ const userFields = await this.getFields();
2446
+ const columnNames = [
2447
+ "SmID",
2448
+ "SmUserID",
2449
+ ...userFields.map((field) => field.name)
2450
+ ];
2451
+ const placeholders = columnNames.map(() => "?").join(", ");
2452
+ const sql = `INSERT INTO "${this.info.tableName}" (${columnNames.map((column) => `"${column}"`).join(", ")}) VALUES (${placeholders})`;
2453
+ await this.driver.transaction(async () => {
2454
+ const statement = await this.driver.prepare(sql);
2455
+ try {
2456
+ let count = 0;
2457
+ for await (const record of records) {
2458
+ const params = [
2459
+ record.id,
2460
+ 0,
2461
+ ...userFields.map(
2462
+ (field) => record.attributes[field.name] ?? null
2463
+ )
2464
+ ];
2465
+ await statement.bind(params);
2466
+ await statement.step();
2467
+ await statement.reset();
2468
+ count++;
2469
+ }
2470
+ if (count > 0) {
2471
+ await this.registerRepository.incrementObjectCountBatch(
2472
+ this.info.id,
2473
+ count,
2474
+ 0
2475
+ );
2476
+ }
2477
+ } finally {
2478
+ await statement.finalize();
2479
+ }
2480
+ });
2481
+ }
2482
+ async update(id, attributes) {
2483
+ const userFields = await this.getFields();
2484
+ const fieldNames = new Set(userFields.map((f) => f.name));
2485
+ const validEntries = Object.entries(attributes).filter(
2486
+ ([key]) => fieldNames.has(key)
2487
+ );
2488
+ if (validEntries.length === 0) return;
2489
+ const keys = validEntries.map(([key]) => key);
2490
+ const setClauses = keys.map((key) => `"${key}" = ?`).join(", ");
2491
+ const sql = `UPDATE "${this.info.tableName}" SET ${setClauses} WHERE SmID = ?`;
2492
+ const params = [
2493
+ ...keys.map((key) => attributes[key]),
2494
+ id
2495
+ ];
2496
+ await this.driver.transaction(async () => {
2497
+ await executeSql(this.driver, sql, params);
2498
+ });
2499
+ }
2500
+ async delete(id) {
2501
+ await this.driver.transaction(async () => {
2502
+ await executeSql(
2503
+ this.driver,
2504
+ `DELETE FROM "${this.info.tableName}" WHERE SmID = ?`,
2505
+ [id]
2506
+ );
2507
+ await this.registerRepository.decrementObjectCount(this.info.id);
2508
+ });
2509
+ }
2510
+ static async create(driver, registerRepository, params) {
2511
+ const fields = params.fields ?? [];
2512
+ const datasetId = await registerRepository.insert({
2513
+ name: params.name,
2514
+ kind: "tabular",
2515
+ srid: 0,
2516
+ idColumnName: "SmID",
2517
+ geometryColumnName: null
2518
+ });
2519
+ const userColumnDefinitions = fields.map((field) => {
2520
+ const nullability = field.nullable ? "" : " NOT NULL";
2521
+ return `"${field.name}" ${sqliteColumnType(field)}${nullability}`;
2522
+ });
2523
+ const createTableParts = [
2524
+ `"SmID" INTEGER NOT NULL PRIMARY KEY`,
2525
+ `"SmUserID" INTEGER DEFAULT 0 NOT NULL`,
2526
+ ...userColumnDefinitions
2527
+ ];
2528
+ await driver.exec(
2529
+ `CREATE TABLE "${params.name}" (${createTableParts.join(", ")})`
2530
+ );
2531
+ if (fields.length > 0) {
2532
+ const fieldInfoRepository = new SmFieldInfoRepository(driver);
2533
+ await fieldInfoRepository.insertAll(datasetId, fields);
2534
+ }
2535
+ return new _TabularDataset(driver, {
2536
+ id: datasetId,
2537
+ name: params.name,
2538
+ kind: "tabular",
2539
+ tableName: params.name,
2540
+ srid: 0,
2541
+ objectCount: 0,
2542
+ geometryType: null
2543
+ });
2544
+ }
2545
+ };
2546
+
2547
+ // src/core/dataset/TextDataset.ts
2548
+ var TextDataset = class extends BaseDataset {
2549
+ async getById() {
2550
+ throw createNotImplementedError("TextDataset.getById");
2551
+ }
2552
+ async list(_options) {
2553
+ throw createNotImplementedError("TextDataset.list");
2554
+ }
2555
+ async *iterate(_options) {
2556
+ throw createNotImplementedError("TextDataset.iterate");
2557
+ }
2558
+ async count() {
2559
+ throw createNotImplementedError("TextDataset.count");
2560
+ }
2561
+ async insert() {
2562
+ throw createNotImplementedError("TextDataset.insert");
2563
+ }
2564
+ async insertMany() {
2565
+ throw createNotImplementedError("TextDataset.insertMany");
2566
+ }
2567
+ async update() {
2568
+ throw createNotImplementedError("TextDataset.update");
2569
+ }
2570
+ async delete() {
2571
+ throw createNotImplementedError("TextDataset.delete");
2572
+ }
2573
+ };
2574
+
2575
+ // src/core/schema/UdbxSchemaInitializer.ts
2576
+ var UDBX_SYSTEM_TABLES = [
2577
+ "spatial_ref_sys",
2578
+ "geometry_columns",
2579
+ "SmDataSourceInfo",
2580
+ "SmRegister",
2581
+ "SmFieldInfo"
2582
+ ];
2583
+ var UDBX_SCHEMA_STATEMENTS = [
2584
+ `CREATE TABLE spatial_ref_sys (
2585
+ srid INTEGER NOT NULL PRIMARY KEY,
2586
+ auth_name TEXT NOT NULL,
2587
+ auth_srid INTEGER NOT NULL,
2588
+ ref_sys_name TEXT NOT NULL DEFAULT 'Unknown',
2589
+ proj4text TEXT NOT NULL,
2590
+ srtext TEXT NOT NULL DEFAULT 'Undefined'
2591
+ )`,
2592
+ `CREATE TABLE geometry_columns (
2593
+ f_table_name TEXT NOT NULL,
2594
+ f_geometry_column TEXT NOT NULL,
2595
+ geometry_type INTEGER NOT NULL,
2596
+ coord_dimension INTEGER NOT NULL,
2597
+ srid INTEGER NOT NULL,
2598
+ spatial_index_enabled INTEGER NOT NULL,
2599
+ CONSTRAINT pk_geom_cols PRIMARY KEY (f_table_name, f_geometry_column)
2600
+ )`,
2601
+ `CREATE TABLE SmDataSourceInfo (
2602
+ SmFlag INTEGER DEFAULT 0 NOT NULL PRIMARY KEY AUTOINCREMENT,
2603
+ SmVersion INTEGER,
2604
+ SmDsDescription TEXT,
2605
+ SmProjectInfo BLOB,
2606
+ SmLastUpdateTime DATE DEFAULT CURRENT_TIMESTAMP NOT NULL,
2607
+ SmDataFormat INTEGER DEFAULT 0 NOT NULL
2608
+ )`,
2609
+ `CREATE TABLE SmRegister (
2610
+ SmDatasetID INTEGER DEFAULT 0 NOT NULL PRIMARY KEY,
2611
+ SmDatasetName TEXT,
2612
+ SmTableName TEXT,
2613
+ SmOption INTEGER,
2614
+ SmEncType INTEGER,
2615
+ SmParentDTID INTEGER DEFAULT 0 NOT NULL,
2616
+ SmDatasetType INTEGER,
2617
+ SmObjectCount INTEGER DEFAULT 0 NOT NULL,
2618
+ SmLeft REAL,
2619
+ SmRight REAL,
2620
+ SmTop REAL,
2621
+ SmBottom REAL,
2622
+ SmIDColName TEXT,
2623
+ SmGeoColName TEXT,
2624
+ SmMinZ REAL,
2625
+ SmMaxZ REAL,
2626
+ SmSRID INTEGER DEFAULT 0,
2627
+ SmIndexType INTEGER DEFAULT 1,
2628
+ SmToleRanceFuzzy REAL,
2629
+ SmToleranceDAngle REAL,
2630
+ SmToleranceNodeSnap REAL,
2631
+ SmToleranceSmallPolygon REAL,
2632
+ SmToleranceGrain REAL,
2633
+ SmMaxGeometrySize INTEGER DEFAULT 0 NOT NULL,
2634
+ SmOptimizeCount INTEGER DEFAULT 0 NOT NULL,
2635
+ SmOptimizeRatio REAL,
2636
+ SmDescription TEXT,
2637
+ SmExtInfo TEXT,
2638
+ SmCreateTime TEXT,
2639
+ SmLastUpdateTime TEXT,
2640
+ SmProjectInfo BLOB
2641
+ )`,
2642
+ `CREATE TABLE SmFieldInfo (
2643
+ SmID INTEGER DEFAULT 0 NOT NULL PRIMARY KEY AUTOINCREMENT,
2644
+ SmDatasetID INTEGER,
2645
+ SmFieldName TEXT,
2646
+ SmFieldCaption TEXT,
2647
+ SmFieldType INTEGER,
2648
+ SmFieldFormat TEXT,
2649
+ SmFieldSign INTEGER,
2650
+ SmFieldDomain TEXT,
2651
+ SmFieldUpdatable INTEGER,
2652
+ SmFieldbRequired INTEGER,
2653
+ SmFieldDefaultValue TEXT,
2654
+ SmFieldSize INTEGER
2655
+ )`,
2656
+ "INSERT INTO SmDataSourceInfo (SmVersion, SmDataFormat) VALUES (0, 1)",
2657
+ "INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, ref_sys_name, proj4text, srtext) VALUES (0, 'none', 0, 'Undefined', '', 'Undefined')",
2658
+ `INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, ref_sys_name, proj4text, srtext)
2659
+ VALUES (
2660
+ 4326,
2661
+ 'epsg',
2662
+ 4326,
2663
+ 'WGS 84',
2664
+ '+proj=longlat +datum=WGS84 +no_defs',
2665
+ 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433],AUTHORITY["EPSG","4326"]]'
2666
+ )`
2667
+ ];
2668
+ var UdbxSchemaInitializer = class {
2669
+ static async isInitialized(driver) {
2670
+ const statement = await driver.prepare(
2671
+ "SELECT name FROM sqlite_master WHERE type = 'table' AND name = ? LIMIT 1"
2672
+ );
2673
+ try {
2674
+ await statement.bind(["SmDataSourceInfo"]);
2675
+ return statement.step();
2676
+ } finally {
2677
+ await statement.finalize();
2678
+ }
2679
+ }
2680
+ static async ensureInitialized(driver) {
2681
+ const initialized = await this.isInitialized(driver);
2682
+ if (initialized) {
2683
+ return false;
2684
+ }
2685
+ await this.initialize(driver);
2686
+ return true;
2687
+ }
2688
+ static async initialize(driver) {
2689
+ await driver.exec("PRAGMA journal_mode = WAL");
2690
+ await driver.transaction(async () => {
2691
+ for (const statement of UDBX_SCHEMA_STATEMENTS) {
2692
+ await driver.exec(statement);
2693
+ }
2694
+ });
2695
+ }
2696
+ };
2697
+
2698
+ // src/core/datasource/UdbxDataSource.ts
2699
+ var UdbxDataSource = class _UdbxDataSource {
2700
+ constructor(driver, runtime = "unknown") {
2701
+ this.driver = driver;
2702
+ this.runtime = runtime;
2703
+ __publicField(this, "registerRepository");
2704
+ this.registerRepository = new SmRegisterRepository(driver);
2705
+ }
2706
+ static async open(params) {
2707
+ await params.driver.open(params.target);
2708
+ return new _UdbxDataSource(params.driver, params.runtime ?? "unknown");
2709
+ }
2710
+ static async create(params) {
2711
+ await params.driver.open(params.target);
2712
+ await UdbxSchemaInitializer.initialize(params.driver);
2713
+ return new _UdbxDataSource(params.driver, params.runtime ?? "unknown");
2714
+ }
2715
+ async listDatasets() {
2716
+ return this.registerRepository.findAll();
2717
+ }
2718
+ async getDataset(name) {
2719
+ const info = await this.registerRepository.findByName(name);
2720
+ if (!info) {
2721
+ return null;
2722
+ }
2723
+ switch (info.kind) {
2724
+ case "point":
2725
+ return new PointDataset(this.driver, info);
2726
+ case "pointZ":
2727
+ return new PointZDataset(this.driver, info);
2728
+ case "line":
2729
+ return new LineDataset(this.driver, info);
2730
+ case "lineZ":
2731
+ return new LineZDataset(this.driver, info);
2732
+ case "region":
2733
+ return new RegionDataset(this.driver, info);
2734
+ case "regionZ":
2735
+ return new RegionZDataset(this.driver, info);
2736
+ case "tabular":
2737
+ return new TabularDataset(this.driver, info);
2738
+ case "text":
2739
+ return new TextDataset(this.driver, info);
2740
+ case "cad":
2741
+ return new CadDataset(this.driver, info);
2742
+ default:
2743
+ return null;
2744
+ }
2745
+ }
2746
+ async createPointDataset(name, srid, fields) {
2747
+ return this.driver.transaction(async () => {
2748
+ const params = fields === void 0 ? { name, srid } : { name, srid, fields };
2749
+ return PointDataset.create(this.driver, this.registerRepository, params);
2750
+ });
2751
+ }
2752
+ async createLineDataset(name, srid, fields) {
2753
+ return this.driver.transaction(async () => {
2754
+ const params = fields === void 0 ? { name, srid } : { name, srid, fields };
2755
+ return LineDataset.create(this.driver, this.registerRepository, params);
2756
+ });
2757
+ }
2758
+ async createRegionDataset(name, srid, fields) {
2759
+ return this.driver.transaction(async () => {
2760
+ const params = fields === void 0 ? { name, srid } : { name, srid, fields };
2761
+ return RegionDataset.create(this.driver, this.registerRepository, params);
2762
+ });
2763
+ }
2764
+ async createPointZDataset(name, srid, fields) {
2765
+ return this.driver.transaction(async () => {
2766
+ const params = fields === void 0 ? { name, srid } : { name, srid, fields };
2767
+ return PointZDataset.create(this.driver, this.registerRepository, params);
2768
+ });
2769
+ }
2770
+ async createLineZDataset(name, srid, fields) {
2771
+ return this.driver.transaction(async () => {
2772
+ const params = fields === void 0 ? { name, srid } : { name, srid, fields };
2773
+ return LineZDataset.create(this.driver, this.registerRepository, params);
2774
+ });
2775
+ }
2776
+ async createRegionZDataset(name, srid, fields) {
2777
+ return this.driver.transaction(async () => {
2778
+ const params = fields === void 0 ? { name, srid } : { name, srid, fields };
2779
+ return RegionZDataset.create(this.driver, this.registerRepository, params);
2780
+ });
2781
+ }
2782
+ async createTabularDataset(name, fields) {
2783
+ return this.driver.transaction(async () => {
2784
+ const params = fields === void 0 ? { name } : { name, fields };
2785
+ return TabularDataset.create(this.driver, this.registerRepository, params);
2786
+ });
2787
+ }
2788
+ async createTextDataset(name, srid, fields) {
2789
+ return this.driver.transaction(async () => {
2790
+ const fieldList = fields ?? [];
2791
+ const datasetId = await this.registerRepository.insert({
2792
+ name,
2793
+ kind: "text",
2794
+ srid,
2795
+ idColumnName: "SmID",
2796
+ geometryColumnName: "SmGeometry"
2797
+ });
2798
+ const userColumnDefinitions = fieldList.map((field) => {
2799
+ const nullability = field.nullable ? "" : " NOT NULL";
2800
+ return `"${field.name}" TEXT${nullability}`;
2801
+ });
2802
+ const createTableParts = [
2803
+ `"SmID" INTEGER NOT NULL PRIMARY KEY`,
2804
+ `"SmUserID" INTEGER DEFAULT 0 NOT NULL`,
2805
+ `"SmGeometry" BLOB`,
2806
+ `"SmIndexKey" POLYGON`,
2807
+ ...userColumnDefinitions
2808
+ ];
2809
+ await this.driver.exec(
2810
+ `CREATE TABLE "${name}" (${createTableParts.join(", ")})`
2811
+ );
2812
+ if (fieldList.length > 0) {
2813
+ const fieldInfoRepository = new SmFieldInfoRepository(this.driver);
2814
+ await fieldInfoRepository.insertAll(datasetId, fieldList);
2815
+ }
2816
+ return new TextDataset(this.driver, {
2817
+ id: datasetId,
2818
+ name,
2819
+ kind: "text",
2820
+ tableName: name,
2821
+ srid,
2822
+ objectCount: 0,
2823
+ geometryType: null
2824
+ });
2825
+ });
2826
+ }
2827
+ async createCadDataset(name, fields) {
2828
+ return this.driver.transaction(async () => {
2829
+ const fieldList = fields ?? [];
2830
+ const datasetId = await this.registerRepository.insert({
2831
+ name,
2832
+ kind: "cad",
2833
+ srid: 0,
2834
+ idColumnName: "SmID",
2835
+ geometryColumnName: "SmGeometry"
2836
+ });
2837
+ const userColumnDefinitions = fieldList.map((field) => {
2838
+ const nullability = field.nullable ? "" : " NOT NULL";
2839
+ return `"${field.name}" TEXT${nullability}`;
2840
+ });
2841
+ const createTableParts = [
2842
+ `"SmID" INTEGER NOT NULL PRIMARY KEY`,
2843
+ `"SmUserID" INTEGER DEFAULT 0 NOT NULL`,
2844
+ `"SmGeometry" BLOB`,
2845
+ ...userColumnDefinitions
2846
+ ];
2847
+ await this.driver.exec(
2848
+ `CREATE TABLE "${name}" (${createTableParts.join(", ")})`
2849
+ );
2850
+ if (fieldList.length > 0) {
2851
+ const fieldInfoRepository = new SmFieldInfoRepository(this.driver);
2852
+ await fieldInfoRepository.insertAll(datasetId, fieldList);
2853
+ }
2854
+ return new CadDataset(this.driver, {
2855
+ id: datasetId,
2856
+ name,
2857
+ kind: "cad",
2858
+ tableName: name,
2859
+ srid: 0,
2860
+ objectCount: 0,
2861
+ geometryType: null
2862
+ });
2863
+ });
2864
+ }
2865
+ async close() {
2866
+ await this.driver.close();
2867
+ }
2868
+ };
2869
+
2870
+ // src/core/errors.ts
2871
+ var UdbxError = class extends Error {
2872
+ constructor(message) {
2873
+ super(message);
2874
+ this.name = "UdbxError";
2875
+ }
2876
+ };
2877
+ var UdbxFormatError = class extends UdbxError {
2878
+ constructor(message) {
2879
+ super(message);
2880
+ this.name = "UdbxFormatError";
2881
+ }
2882
+ };
2883
+ var UdbxNotFoundError = class extends UdbxError {
2884
+ constructor(what, id) {
2885
+ super(id !== void 0 ? `${what} not found (id=${id})` : `${what} not found`);
2886
+ this.name = "UdbxNotFoundError";
2887
+ }
2888
+ };
2889
+ var UdbxUnsupportedError = class extends UdbxError {
2890
+ constructor(what) {
2891
+ super(`Unsupported: ${what}`);
2892
+ this.name = "UdbxUnsupportedError";
2893
+ }
2894
+ };
2895
+ var UdbxConstraintError = class extends UdbxError {
2896
+ constructor(what) {
2897
+ super(`Constraint violation: ${what}`);
2898
+ this.name = "UdbxConstraintError";
2899
+ }
2900
+ };
2901
+ var UdbxIOError = class extends UdbxError {
2902
+ constructor(cause) {
2903
+ super(cause ? `IO error: ${cause.message}` : "IO error");
2904
+ this.name = "UdbxIOError";
2905
+ }
2906
+ };
2907
+
2908
+ // src/core/geometry/gaia/GaiaGeometryCodec.ts
2909
+ var decodeByGeoType = /* @__PURE__ */ new Map([
2910
+ [GEO_TYPE_POINT, GaiaPointCodec.readPoint],
2911
+ [GEO_TYPE_POINTZ, GaiaPointCodec.readPointZ],
2912
+ [GEO_TYPE_MULTILINESTRING, GaiaLineCodec.readMultiLineString],
2913
+ [GEO_TYPE_MULTILINESTRINGZ, GaiaLineCodec.readMultiLineStringZ],
2914
+ [GEO_TYPE_MULTIPOLYGON, GaiaPolygonCodec.readMultiPolygon],
2915
+ [GEO_TYPE_MULTIPOLYGONZ, GaiaPolygonCodec.readMultiPolygonZ]
2916
+ ]);
2917
+ var pointCodecs = {
2918
+ [GEO_TYPE_POINT]: {
2919
+ geoType: GEO_TYPE_POINT,
2920
+ decode: GaiaPointCodec.readPoint
2921
+ },
2922
+ [GEO_TYPE_POINTZ]: {
2923
+ geoType: GEO_TYPE_POINTZ,
2924
+ decode: GaiaPointCodec.readPointZ
2925
+ }
2926
+ };
2927
+ var lineCodecs = {
2928
+ [GEO_TYPE_MULTILINESTRING]: {
2929
+ geoType: GEO_TYPE_MULTILINESTRING,
2930
+ decode: GaiaLineCodec.readMultiLineString
2931
+ },
2932
+ [GEO_TYPE_MULTILINESTRINGZ]: {
2933
+ geoType: GEO_TYPE_MULTILINESTRINGZ,
2934
+ decode: GaiaLineCodec.readMultiLineStringZ
2935
+ }
2936
+ };
2937
+ var polygonCodecs = {
2938
+ [GEO_TYPE_MULTIPOLYGON]: {
2939
+ geoType: GEO_TYPE_MULTIPOLYGON,
2940
+ decode: GaiaPolygonCodec.readMultiPolygon
2941
+ },
2942
+ [GEO_TYPE_MULTIPOLYGONZ]: {
2943
+ geoType: GEO_TYPE_MULTIPOLYGONZ,
2944
+ decode: GaiaPolygonCodec.readMultiPolygonZ
2945
+ }
2946
+ };
2947
+ function geometryHasZ(geometry) {
2948
+ switch (geometry.type) {
2949
+ case "Point":
2950
+ return geometry.coordinates.length === 3;
2951
+ case "MultiLineString":
2952
+ return geometry.coordinates[0]?.[0]?.length === 3;
2953
+ case "MultiPolygon":
2954
+ return geometry.coordinates[0]?.[0]?.[0]?.length === 3;
2955
+ case "Cad":
2956
+ case "Text":
2957
+ return false;
2958
+ default:
2959
+ return false;
2960
+ }
2961
+ }
2962
+ function encodeGeometry(geometry, srid) {
2963
+ switch (geometry.type) {
2964
+ case "Point":
2965
+ return geometryHasZ(geometry) ? GaiaPointCodec.writePointZ(geometry, srid) : GaiaPointCodec.writePoint(geometry, srid);
2966
+ case "MultiLineString":
2967
+ return geometryHasZ(geometry) ? GaiaLineCodec.writeMultiLineStringZ(geometry, srid) : GaiaLineCodec.writeMultiLineString(geometry, srid);
2968
+ case "MultiPolygon":
2969
+ return geometryHasZ(geometry) ? GaiaPolygonCodec.writeMultiPolygonZ(geometry, srid) : GaiaPolygonCodec.writeMultiPolygon(geometry, srid);
2970
+ case "Cad":
2971
+ throw new Error("CAD geometry is not supported by GaiaGeometryCodec.");
2972
+ case "Text":
2973
+ throw new Error("Text geometry is not supported by GaiaGeometryCodec.");
2974
+ default:
2975
+ throw new Error(`Unsupported geometry type: ${geometry.type}`);
2976
+ }
2977
+ }
2978
+ var GaiaGeometryCodec = class {
2979
+ static decode(input) {
2980
+ const header = readGaiaHeader(new BinaryCursor(input));
2981
+ const decoder = decodeByGeoType.get(header.geoType);
2982
+ if (!decoder) {
2983
+ throw new GaiaUnsupportedGeoTypeError(header.geoType);
2984
+ }
2985
+ return decoder(input);
2986
+ }
2987
+ static encode(geometry, srid) {
2988
+ return encodeGeometry(geometry, srid);
2989
+ }
2990
+ };
2991
+
2992
+ // src/core/geometry/jsts/JstsGeometryAdapter.ts
2993
+ var reader = null;
2994
+ var writer = null;
2995
+ async function getReader() {
2996
+ if (!reader) {
2997
+ const { default: GeoJSONReader } = await import("jsts/org/locationtech/jts/io/GeoJSONReader");
2998
+ const { default: GeometryFactory } = await import("jsts/org/locationtech/jts/geom/GeometryFactory");
2999
+ reader = new GeoJSONReader(new GeometryFactory());
3000
+ }
3001
+ return reader;
3002
+ }
3003
+ async function getWriter() {
3004
+ if (!writer) {
3005
+ const { default: GeoJSONWriter } = await import("jsts/org/locationtech/jts/io/GeoJSONWriter");
3006
+ writer = new GeoJSONWriter();
3007
+ }
3008
+ return writer;
3009
+ }
3010
+ async function toJsts(geometry) {
3011
+ const r = await getReader();
3012
+ return r.read(geometry);
3013
+ }
3014
+ async function fromJsts(jtsGeom) {
3015
+ const w = await getWriter();
3016
+ return w.write(jtsGeom);
3017
+ }
3018
+ async function toJstsPoint(geometry) {
3019
+ const r = await getReader();
3020
+ return r.read(geometry);
3021
+ }
3022
+ async function toJstsMultiLineString(geometry) {
3023
+ const r = await getReader();
3024
+ return r.read(geometry);
3025
+ }
3026
+ async function toJstsMultiPolygon(geometry) {
3027
+ const r = await getReader();
3028
+ return r.read(geometry);
3029
+ }
3030
+ var JstsGeometryCodec = class {
3031
+ static async decode(input) {
3032
+ const geojson = GaiaGeometryCodec.decode(input);
3033
+ return toJsts(geojson);
3034
+ }
3035
+ static async encode(jtsGeom, srid) {
3036
+ const geojson = await fromJsts(jtsGeom);
3037
+ return GaiaGeometryCodec.encode(geojson, srid);
3038
+ }
3039
+ };
3040
+ // Annotate the CommonJS export names for ESM import in node:
3041
+ 0 && (module.exports = {
3042
+ BaseDataset,
3043
+ BinaryCursor,
3044
+ BinaryWriter,
3045
+ CadDataset,
3046
+ GAIA_BYTE_ORDER_LE,
3047
+ GAIA_END,
3048
+ GAIA_GEOMETRY_DATA_OFFSET,
3049
+ GAIA_MBR,
3050
+ GAIA_START,
3051
+ GEO_TYPE_MULTILINESTRING,
3052
+ GEO_TYPE_MULTILINESTRINGZ,
3053
+ GEO_TYPE_MULTIPOLYGON,
3054
+ GEO_TYPE_MULTIPOLYGONZ,
3055
+ GEO_TYPE_POINT,
3056
+ GEO_TYPE_POINTZ,
3057
+ GaiaError,
3058
+ GaiaFormatError,
3059
+ GaiaGeoTypeMismatchError,
3060
+ GaiaGeometryCodec,
3061
+ GaiaLineCodec,
3062
+ GaiaPointCodec,
3063
+ GaiaPolygonCodec,
3064
+ GaiaUnsupportedGeoTypeError,
3065
+ JstsGeometryCodec,
3066
+ LineDataset,
3067
+ LineZDataset,
3068
+ NotImplementedError,
3069
+ PointDataset,
3070
+ PointZDataset,
3071
+ RegionDataset,
3072
+ RegionZDataset,
3073
+ SmFieldInfoRepository,
3074
+ SmRegisterRepository,
3075
+ TabularDataset,
3076
+ TextDataset,
3077
+ UDBX_SCHEMA_STATEMENTS,
3078
+ UDBX_SYSTEM_TABLES,
3079
+ UdbxConstraintError,
3080
+ UdbxDataSource,
3081
+ UdbxError,
3082
+ UdbxFormatError,
3083
+ UdbxIOError,
3084
+ UdbxNotFoundError,
3085
+ UdbxSchemaInitializer,
3086
+ UdbxUnsupportedError,
3087
+ createNotImplementedError,
3088
+ datasetKindToValue,
3089
+ datasetValueToKind,
3090
+ fieldTypeToValue,
3091
+ fieldValueToType,
3092
+ fromJsts,
3093
+ readGaiaHeader,
3094
+ toJsts,
3095
+ toJstsMultiLineString,
3096
+ toJstsMultiPolygon,
3097
+ toJstsPoint,
3098
+ validateGaiaEnd,
3099
+ writeGaiaHeader
3100
+ });
3101
+ //# sourceMappingURL=index.cjs.map