@atscript/moost-db 0.1.103 → 0.1.105
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 +118 -1
- package/dist/index.d.cts +21 -0
- package/dist/index.d.mts +21 -0
- package/dist/index.mjs +118 -1
- package/package.json +10 -10
package/dist/index.cjs
CHANGED
|
@@ -980,6 +980,25 @@ const QUERY_CONTROLS = [
|
|
|
980
980
|
];
|
|
981
981
|
const PAGES_CONTROLS = ["filter", ...dtoControls(PagesControlsDto)];
|
|
982
982
|
const ONE_CONTROLS = dtoControls(GetOneControlsDto);
|
|
983
|
+
/**
|
|
984
|
+
* Controls accepted by the `/geo` endpoint. No backing DTO — `$center` /
|
|
985
|
+
* `$maxDistance` / `$minDistance` are parsed and validated by the handler.
|
|
986
|
+
*/
|
|
987
|
+
const GEO_CONTROLS = [
|
|
988
|
+
"filter",
|
|
989
|
+
"insights",
|
|
990
|
+
"center",
|
|
991
|
+
"maxDistance",
|
|
992
|
+
"minDistance",
|
|
993
|
+
"index",
|
|
994
|
+
"select",
|
|
995
|
+
"skip",
|
|
996
|
+
"limit",
|
|
997
|
+
"page",
|
|
998
|
+
"size",
|
|
999
|
+
"with",
|
|
1000
|
+
"actions"
|
|
1001
|
+
];
|
|
983
1002
|
//#endregion
|
|
984
1003
|
//#region src/as-db-readable.controller.ts
|
|
985
1004
|
let AsDbReadableController = class AsDbReadableController extends AsReadableController {
|
|
@@ -1413,6 +1432,82 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1413
1432
|
};
|
|
1414
1433
|
}
|
|
1415
1434
|
/**
|
|
1435
|
+
* **GET /geo** — distance-ranked geospatial search (mirrors the search /
|
|
1436
|
+
* vector read endpoints; geo-index spec §7).
|
|
1437
|
+
*
|
|
1438
|
+
* URL controls: `$center=lng,lat` (required), `$maxDistance` / `$minDistance`
|
|
1439
|
+
* (meters), `$index` (geo index name), plus the standard filter / `$select` /
|
|
1440
|
+
* `$with` / pagination syntax. Each row carries a computed `$distance`
|
|
1441
|
+
* (meters). With `$page` / `$size` the response is the `/pages` envelope;
|
|
1442
|
+
* otherwise a plain row array (`$skip` / `$limit` compose).
|
|
1443
|
+
*/
|
|
1444
|
+
async geo(url) {
|
|
1445
|
+
const parsed = this.parseQueryString(url);
|
|
1446
|
+
const controls = parsed.controls;
|
|
1447
|
+
this._coerceActionsControl(controls);
|
|
1448
|
+
const point = this._parseGeoCenter(controls.$center);
|
|
1449
|
+
if (point instanceof _moostjs_event_http.HttpError) return point;
|
|
1450
|
+
for (const key of ["$maxDistance", "$minDistance"]) if (controls[key] !== void 0) {
|
|
1451
|
+
const num = Number(controls[key]);
|
|
1452
|
+
if (!Number.isFinite(num) || num < 0) return new _moostjs_event_http.HttpError(400, `${key} must be a non-negative number of meters`);
|
|
1453
|
+
controls[key] = num;
|
|
1454
|
+
}
|
|
1455
|
+
const indexName = typeof controls.$index === "string" ? controls.$index : void 0;
|
|
1456
|
+
if (parsed.insights) {
|
|
1457
|
+
const insightsError = this.validateInsights(parsed.insights);
|
|
1458
|
+
if (insightsError) return new _moostjs_event_http.HttpError(400, insightsError);
|
|
1459
|
+
}
|
|
1460
|
+
const gateError = this.checkGates(parsed.filter, controls, this._gates);
|
|
1461
|
+
if (gateError) return gateError;
|
|
1462
|
+
const [filter, rawSelect] = await Promise.all([this.transformFilter(parsed.filter), this.transformProjection(controls.$select)]);
|
|
1463
|
+
const select = this.widenPreferredIdProjection(rawSelect);
|
|
1464
|
+
if (select instanceof _moostjs_event_http.HttpError) return select;
|
|
1465
|
+
const paginated = controls.$page !== void 0 || controls.$size !== void 0;
|
|
1466
|
+
const page = Math.max(Number(controls.$page || 1), 1);
|
|
1467
|
+
const size = Math.max(Number(controls.$size || 10), 1);
|
|
1468
|
+
const queryObj = {
|
|
1469
|
+
filter,
|
|
1470
|
+
controls: {
|
|
1471
|
+
...controls,
|
|
1472
|
+
$center: void 0,
|
|
1473
|
+
$index: void 0,
|
|
1474
|
+
$select: select,
|
|
1475
|
+
...paginated ? {
|
|
1476
|
+
$skip: (page - 1) * size,
|
|
1477
|
+
$limit: size
|
|
1478
|
+
} : { $limit: controls.$limit || 1e3 }
|
|
1479
|
+
}
|
|
1480
|
+
};
|
|
1481
|
+
if (paginated) {
|
|
1482
|
+
const result = await this._runReadWithActions(queryObj, controls, select, async (q) => indexName ? this.readable.geoSearchWithCount(indexName, point, q) : this.readable.geoSearchWithCount(point, q));
|
|
1483
|
+
return {
|
|
1484
|
+
data: result.data,
|
|
1485
|
+
page,
|
|
1486
|
+
itemsPerPage: size,
|
|
1487
|
+
pages: Math.ceil(result.count / size),
|
|
1488
|
+
count: result.count
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
return (await this._runReadWithActions(queryObj, controls, select, async (q) => ({ data: await (indexName ? this.readable.geoSearch(indexName, point, q) : this.readable.geoSearch(point, q)) }))).data;
|
|
1492
|
+
}
|
|
1493
|
+
/** Parses the `$center` control: `"lng,lat"` string (or tuple) → `[number, number]`. */
|
|
1494
|
+
_parseGeoCenter(raw) {
|
|
1495
|
+
let lng;
|
|
1496
|
+
let lat;
|
|
1497
|
+
if (typeof raw === "string") {
|
|
1498
|
+
const parts = raw.split(",");
|
|
1499
|
+
if (parts.length === 2) {
|
|
1500
|
+
lng = Number(parts[0]);
|
|
1501
|
+
lat = Number(parts[1]);
|
|
1502
|
+
}
|
|
1503
|
+
} else if (Array.isArray(raw) && raw.length === 2) {
|
|
1504
|
+
lng = Number(raw[0]);
|
|
1505
|
+
lat = Number(raw[1]);
|
|
1506
|
+
}
|
|
1507
|
+
if (lng === void 0 || lat === void 0 || !Number.isFinite(lng) || !Number.isFinite(lat)) return new _moostjs_event_http.HttpError(400, "$center is required: $center=lng,lat (GeoJSON order)");
|
|
1508
|
+
return [lng, lat];
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1416
1511
|
* **GET /one/:id** — retrieves a single record by ID or unique property.
|
|
1417
1512
|
* The id-filter is AND-combined with {@link transformOne} so row-level
|
|
1418
1513
|
* read overlays gate `/one` symmetrically with `/query` / `/pages`.
|
|
@@ -1486,6 +1581,10 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1486
1581
|
});
|
|
1487
1582
|
const filterableMode = this.readable.type.metadata.get("db.table.filterable") === "manual";
|
|
1488
1583
|
const sortableMode = this.readable.type.metadata.get("db.table.sortable") === "manual";
|
|
1584
|
+
const geoIndexedPhysical = /* @__PURE__ */ new Set();
|
|
1585
|
+
if (this.readable.indexes instanceof Map) {
|
|
1586
|
+
for (const index of this.readable.indexes.values()) if (index.type === "geo") for (const f of index.fields) geoIndexedPhysical.add(f.name);
|
|
1587
|
+
}
|
|
1489
1588
|
const fields = {};
|
|
1490
1589
|
for (const fd of this.readable.fieldDescriptors) {
|
|
1491
1590
|
if (fd.ignored) continue;
|
|
@@ -1499,10 +1598,13 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1499
1598
|
sortable: adapterCanSort && (sortableMode ? annotatedSortable : !!fd.isIndexed),
|
|
1500
1599
|
filterable: adapterCanFilter && (filterableMode ? annotatedFilterable : true)
|
|
1501
1600
|
};
|
|
1601
|
+
if (fd.encrypted) fields[fd.path].encrypted = true;
|
|
1602
|
+
if (geoIndexedPhysical.has(fd.physicalName)) fields[fd.path].geo = true;
|
|
1502
1603
|
}
|
|
1503
1604
|
return {
|
|
1504
1605
|
searchable: this.readable.isSearchable(),
|
|
1505
1606
|
vectorSearchable: this.readable.isVectorSearchable(),
|
|
1607
|
+
geoSearchable: this._isGeoSearchable(),
|
|
1506
1608
|
searchIndexes: this.readable.getSearchIndexes(),
|
|
1507
1609
|
primaryKeys: [...this.readable.primaryKeys],
|
|
1508
1610
|
preferredId: [...this.readable.preferredId],
|
|
@@ -1519,9 +1621,17 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1519
1621
|
...super.buildCrud(),
|
|
1520
1622
|
query: [...QUERY_CONTROLS],
|
|
1521
1623
|
pages: [...PAGES_CONTROLS],
|
|
1522
|
-
one: [...ONE_CONTROLS]
|
|
1624
|
+
one: [...ONE_CONTROLS],
|
|
1625
|
+
...this._isGeoSearchable() ? { geo: [...GEO_CONTROLS] } : {}
|
|
1523
1626
|
};
|
|
1524
1627
|
}
|
|
1628
|
+
/** Adapter supports geo search AND the table declares at least one geo index. */
|
|
1629
|
+
_isGeoSearchable() {
|
|
1630
|
+
if (typeof this.readable.isGeoSearchable !== "function" || !this.readable.isGeoSearchable()) return false;
|
|
1631
|
+
if (!(this.readable.indexes instanceof Map)) return false;
|
|
1632
|
+
for (const index of this.readable.indexes.values()) if (index.type === "geo") return true;
|
|
1633
|
+
return false;
|
|
1634
|
+
}
|
|
1525
1635
|
};
|
|
1526
1636
|
__decorate([
|
|
1527
1637
|
(0, _moostjs_event_http.Get)("query"),
|
|
@@ -1537,6 +1647,13 @@ __decorate([
|
|
|
1537
1647
|
__decorateMetadata("design:paramtypes", [String]),
|
|
1538
1648
|
__decorateMetadata("design:returntype", Promise)
|
|
1539
1649
|
], AsDbReadableController.prototype, "pages", null);
|
|
1650
|
+
__decorate([
|
|
1651
|
+
(0, _moostjs_event_http.Get)("geo"),
|
|
1652
|
+
__decorateParam(0, (0, _moostjs_event_http.Url)()),
|
|
1653
|
+
__decorateMetadata("design:type", Function),
|
|
1654
|
+
__decorateMetadata("design:paramtypes", [String]),
|
|
1655
|
+
__decorateMetadata("design:returntype", Promise)
|
|
1656
|
+
], AsDbReadableController.prototype, "geo", null);
|
|
1540
1657
|
__decorate([
|
|
1541
1658
|
(0, _moostjs_event_http.Get)("one/:id"),
|
|
1542
1659
|
__decorateParam(0, (0, moost.Param)("id")),
|
package/dist/index.d.cts
CHANGED
|
@@ -263,6 +263,25 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
263
263
|
pages: number;
|
|
264
264
|
count: number;
|
|
265
265
|
} | HttpError>;
|
|
266
|
+
/**
|
|
267
|
+
* **GET /geo** — distance-ranked geospatial search (mirrors the search /
|
|
268
|
+
* vector read endpoints; geo-index spec §7).
|
|
269
|
+
*
|
|
270
|
+
* URL controls: `$center=lng,lat` (required), `$maxDistance` / `$minDistance`
|
|
271
|
+
* (meters), `$index` (geo index name), plus the standard filter / `$select` /
|
|
272
|
+
* `$with` / pagination syntax. Each row carries a computed `$distance`
|
|
273
|
+
* (meters). With `$page` / `$size` the response is the `/pages` envelope;
|
|
274
|
+
* otherwise a plain row array (`$skip` / `$limit` compose).
|
|
275
|
+
*/
|
|
276
|
+
geo(url: string): Promise<DataType[] | {
|
|
277
|
+
data: DataType[];
|
|
278
|
+
page: number;
|
|
279
|
+
itemsPerPage: number;
|
|
280
|
+
pages: number;
|
|
281
|
+
count: number;
|
|
282
|
+
} | HttpError>;
|
|
283
|
+
/** Parses the `$center` control: `"lng,lat"` string (or tuple) → `[number, number]`. */
|
|
284
|
+
private _parseGeoCenter;
|
|
266
285
|
/**
|
|
267
286
|
* **GET /one/:id** — retrieves a single record by ID or unique property.
|
|
268
287
|
* The id-filter is AND-combined with {@link transformOne} so row-level
|
|
@@ -285,6 +304,8 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
285
304
|
*/
|
|
286
305
|
protected buildMetaResponse(): TMetaResponse;
|
|
287
306
|
protected buildCrud(): TCrudPermissions$1;
|
|
307
|
+
/** Adapter supports geo search AND the table declares at least one geo index. */
|
|
308
|
+
private _isGeoSearchable;
|
|
288
309
|
}
|
|
289
310
|
//#endregion
|
|
290
311
|
//#region src/as-db.controller.d.ts
|
package/dist/index.d.mts
CHANGED
|
@@ -263,6 +263,25 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
263
263
|
pages: number;
|
|
264
264
|
count: number;
|
|
265
265
|
} | HttpError>;
|
|
266
|
+
/**
|
|
267
|
+
* **GET /geo** — distance-ranked geospatial search (mirrors the search /
|
|
268
|
+
* vector read endpoints; geo-index spec §7).
|
|
269
|
+
*
|
|
270
|
+
* URL controls: `$center=lng,lat` (required), `$maxDistance` / `$minDistance`
|
|
271
|
+
* (meters), `$index` (geo index name), plus the standard filter / `$select` /
|
|
272
|
+
* `$with` / pagination syntax. Each row carries a computed `$distance`
|
|
273
|
+
* (meters). With `$page` / `$size` the response is the `/pages` envelope;
|
|
274
|
+
* otherwise a plain row array (`$skip` / `$limit` compose).
|
|
275
|
+
*/
|
|
276
|
+
geo(url: string): Promise<DataType[] | {
|
|
277
|
+
data: DataType[];
|
|
278
|
+
page: number;
|
|
279
|
+
itemsPerPage: number;
|
|
280
|
+
pages: number;
|
|
281
|
+
count: number;
|
|
282
|
+
} | HttpError>;
|
|
283
|
+
/** Parses the `$center` control: `"lng,lat"` string (or tuple) → `[number, number]`. */
|
|
284
|
+
private _parseGeoCenter;
|
|
266
285
|
/**
|
|
267
286
|
* **GET /one/:id** — retrieves a single record by ID or unique property.
|
|
268
287
|
* The id-filter is AND-combined with {@link transformOne} so row-level
|
|
@@ -285,6 +304,8 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
|
|
|
285
304
|
*/
|
|
286
305
|
protected buildMetaResponse(): TMetaResponse;
|
|
287
306
|
protected buildCrud(): TCrudPermissions$1;
|
|
307
|
+
/** Adapter supports geo search AND the table declares at least one geo index. */
|
|
308
|
+
private _isGeoSearchable;
|
|
288
309
|
}
|
|
289
310
|
//#endregion
|
|
290
311
|
//#region src/as-db.controller.d.ts
|
package/dist/index.mjs
CHANGED
|
@@ -979,6 +979,25 @@ const QUERY_CONTROLS = [
|
|
|
979
979
|
];
|
|
980
980
|
const PAGES_CONTROLS = ["filter", ...dtoControls(PagesControlsDto)];
|
|
981
981
|
const ONE_CONTROLS = dtoControls(GetOneControlsDto);
|
|
982
|
+
/**
|
|
983
|
+
* Controls accepted by the `/geo` endpoint. No backing DTO — `$center` /
|
|
984
|
+
* `$maxDistance` / `$minDistance` are parsed and validated by the handler.
|
|
985
|
+
*/
|
|
986
|
+
const GEO_CONTROLS = [
|
|
987
|
+
"filter",
|
|
988
|
+
"insights",
|
|
989
|
+
"center",
|
|
990
|
+
"maxDistance",
|
|
991
|
+
"minDistance",
|
|
992
|
+
"index",
|
|
993
|
+
"select",
|
|
994
|
+
"skip",
|
|
995
|
+
"limit",
|
|
996
|
+
"page",
|
|
997
|
+
"size",
|
|
998
|
+
"with",
|
|
999
|
+
"actions"
|
|
1000
|
+
];
|
|
982
1001
|
//#endregion
|
|
983
1002
|
//#region src/as-db-readable.controller.ts
|
|
984
1003
|
let AsDbReadableController = class AsDbReadableController extends AsReadableController {
|
|
@@ -1412,6 +1431,82 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1412
1431
|
};
|
|
1413
1432
|
}
|
|
1414
1433
|
/**
|
|
1434
|
+
* **GET /geo** — distance-ranked geospatial search (mirrors the search /
|
|
1435
|
+
* vector read endpoints; geo-index spec §7).
|
|
1436
|
+
*
|
|
1437
|
+
* URL controls: `$center=lng,lat` (required), `$maxDistance` / `$minDistance`
|
|
1438
|
+
* (meters), `$index` (geo index name), plus the standard filter / `$select` /
|
|
1439
|
+
* `$with` / pagination syntax. Each row carries a computed `$distance`
|
|
1440
|
+
* (meters). With `$page` / `$size` the response is the `/pages` envelope;
|
|
1441
|
+
* otherwise a plain row array (`$skip` / `$limit` compose).
|
|
1442
|
+
*/
|
|
1443
|
+
async geo(url) {
|
|
1444
|
+
const parsed = this.parseQueryString(url);
|
|
1445
|
+
const controls = parsed.controls;
|
|
1446
|
+
this._coerceActionsControl(controls);
|
|
1447
|
+
const point = this._parseGeoCenter(controls.$center);
|
|
1448
|
+
if (point instanceof HttpError) return point;
|
|
1449
|
+
for (const key of ["$maxDistance", "$minDistance"]) if (controls[key] !== void 0) {
|
|
1450
|
+
const num = Number(controls[key]);
|
|
1451
|
+
if (!Number.isFinite(num) || num < 0) return new HttpError(400, `${key} must be a non-negative number of meters`);
|
|
1452
|
+
controls[key] = num;
|
|
1453
|
+
}
|
|
1454
|
+
const indexName = typeof controls.$index === "string" ? controls.$index : void 0;
|
|
1455
|
+
if (parsed.insights) {
|
|
1456
|
+
const insightsError = this.validateInsights(parsed.insights);
|
|
1457
|
+
if (insightsError) return new HttpError(400, insightsError);
|
|
1458
|
+
}
|
|
1459
|
+
const gateError = this.checkGates(parsed.filter, controls, this._gates);
|
|
1460
|
+
if (gateError) return gateError;
|
|
1461
|
+
const [filter, rawSelect] = await Promise.all([this.transformFilter(parsed.filter), this.transformProjection(controls.$select)]);
|
|
1462
|
+
const select = this.widenPreferredIdProjection(rawSelect);
|
|
1463
|
+
if (select instanceof HttpError) return select;
|
|
1464
|
+
const paginated = controls.$page !== void 0 || controls.$size !== void 0;
|
|
1465
|
+
const page = Math.max(Number(controls.$page || 1), 1);
|
|
1466
|
+
const size = Math.max(Number(controls.$size || 10), 1);
|
|
1467
|
+
const queryObj = {
|
|
1468
|
+
filter,
|
|
1469
|
+
controls: {
|
|
1470
|
+
...controls,
|
|
1471
|
+
$center: void 0,
|
|
1472
|
+
$index: void 0,
|
|
1473
|
+
$select: select,
|
|
1474
|
+
...paginated ? {
|
|
1475
|
+
$skip: (page - 1) * size,
|
|
1476
|
+
$limit: size
|
|
1477
|
+
} : { $limit: controls.$limit || 1e3 }
|
|
1478
|
+
}
|
|
1479
|
+
};
|
|
1480
|
+
if (paginated) {
|
|
1481
|
+
const result = await this._runReadWithActions(queryObj, controls, select, async (q) => indexName ? this.readable.geoSearchWithCount(indexName, point, q) : this.readable.geoSearchWithCount(point, q));
|
|
1482
|
+
return {
|
|
1483
|
+
data: result.data,
|
|
1484
|
+
page,
|
|
1485
|
+
itemsPerPage: size,
|
|
1486
|
+
pages: Math.ceil(result.count / size),
|
|
1487
|
+
count: result.count
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
return (await this._runReadWithActions(queryObj, controls, select, async (q) => ({ data: await (indexName ? this.readable.geoSearch(indexName, point, q) : this.readable.geoSearch(point, q)) }))).data;
|
|
1491
|
+
}
|
|
1492
|
+
/** Parses the `$center` control: `"lng,lat"` string (or tuple) → `[number, number]`. */
|
|
1493
|
+
_parseGeoCenter(raw) {
|
|
1494
|
+
let lng;
|
|
1495
|
+
let lat;
|
|
1496
|
+
if (typeof raw === "string") {
|
|
1497
|
+
const parts = raw.split(",");
|
|
1498
|
+
if (parts.length === 2) {
|
|
1499
|
+
lng = Number(parts[0]);
|
|
1500
|
+
lat = Number(parts[1]);
|
|
1501
|
+
}
|
|
1502
|
+
} else if (Array.isArray(raw) && raw.length === 2) {
|
|
1503
|
+
lng = Number(raw[0]);
|
|
1504
|
+
lat = Number(raw[1]);
|
|
1505
|
+
}
|
|
1506
|
+
if (lng === void 0 || lat === void 0 || !Number.isFinite(lng) || !Number.isFinite(lat)) return new HttpError(400, "$center is required: $center=lng,lat (GeoJSON order)");
|
|
1507
|
+
return [lng, lat];
|
|
1508
|
+
}
|
|
1509
|
+
/**
|
|
1415
1510
|
* **GET /one/:id** — retrieves a single record by ID or unique property.
|
|
1416
1511
|
* The id-filter is AND-combined with {@link transformOne} so row-level
|
|
1417
1512
|
* read overlays gate `/one` symmetrically with `/query` / `/pages`.
|
|
@@ -1485,6 +1580,10 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1485
1580
|
});
|
|
1486
1581
|
const filterableMode = this.readable.type.metadata.get("db.table.filterable") === "manual";
|
|
1487
1582
|
const sortableMode = this.readable.type.metadata.get("db.table.sortable") === "manual";
|
|
1583
|
+
const geoIndexedPhysical = /* @__PURE__ */ new Set();
|
|
1584
|
+
if (this.readable.indexes instanceof Map) {
|
|
1585
|
+
for (const index of this.readable.indexes.values()) if (index.type === "geo") for (const f of index.fields) geoIndexedPhysical.add(f.name);
|
|
1586
|
+
}
|
|
1488
1587
|
const fields = {};
|
|
1489
1588
|
for (const fd of this.readable.fieldDescriptors) {
|
|
1490
1589
|
if (fd.ignored) continue;
|
|
@@ -1498,10 +1597,13 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1498
1597
|
sortable: adapterCanSort && (sortableMode ? annotatedSortable : !!fd.isIndexed),
|
|
1499
1598
|
filterable: adapterCanFilter && (filterableMode ? annotatedFilterable : true)
|
|
1500
1599
|
};
|
|
1600
|
+
if (fd.encrypted) fields[fd.path].encrypted = true;
|
|
1601
|
+
if (geoIndexedPhysical.has(fd.physicalName)) fields[fd.path].geo = true;
|
|
1501
1602
|
}
|
|
1502
1603
|
return {
|
|
1503
1604
|
searchable: this.readable.isSearchable(),
|
|
1504
1605
|
vectorSearchable: this.readable.isVectorSearchable(),
|
|
1606
|
+
geoSearchable: this._isGeoSearchable(),
|
|
1505
1607
|
searchIndexes: this.readable.getSearchIndexes(),
|
|
1506
1608
|
primaryKeys: [...this.readable.primaryKeys],
|
|
1507
1609
|
preferredId: [...this.readable.preferredId],
|
|
@@ -1518,9 +1620,17 @@ let AsDbReadableController = class AsDbReadableController extends AsReadableCont
|
|
|
1518
1620
|
...super.buildCrud(),
|
|
1519
1621
|
query: [...QUERY_CONTROLS],
|
|
1520
1622
|
pages: [...PAGES_CONTROLS],
|
|
1521
|
-
one: [...ONE_CONTROLS]
|
|
1623
|
+
one: [...ONE_CONTROLS],
|
|
1624
|
+
...this._isGeoSearchable() ? { geo: [...GEO_CONTROLS] } : {}
|
|
1522
1625
|
};
|
|
1523
1626
|
}
|
|
1627
|
+
/** Adapter supports geo search AND the table declares at least one geo index. */
|
|
1628
|
+
_isGeoSearchable() {
|
|
1629
|
+
if (typeof this.readable.isGeoSearchable !== "function" || !this.readable.isGeoSearchable()) return false;
|
|
1630
|
+
if (!(this.readable.indexes instanceof Map)) return false;
|
|
1631
|
+
for (const index of this.readable.indexes.values()) if (index.type === "geo") return true;
|
|
1632
|
+
return false;
|
|
1633
|
+
}
|
|
1524
1634
|
};
|
|
1525
1635
|
__decorate([
|
|
1526
1636
|
Get("query"),
|
|
@@ -1536,6 +1646,13 @@ __decorate([
|
|
|
1536
1646
|
__decorateMetadata("design:paramtypes", [String]),
|
|
1537
1647
|
__decorateMetadata("design:returntype", Promise)
|
|
1538
1648
|
], AsDbReadableController.prototype, "pages", null);
|
|
1649
|
+
__decorate([
|
|
1650
|
+
Get("geo"),
|
|
1651
|
+
__decorateParam(0, Url()),
|
|
1652
|
+
__decorateMetadata("design:type", Function),
|
|
1653
|
+
__decorateMetadata("design:paramtypes", [String]),
|
|
1654
|
+
__decorateMetadata("design:returntype", Promise)
|
|
1655
|
+
], AsDbReadableController.prototype, "geo", null);
|
|
1539
1656
|
__decorate([
|
|
1540
1657
|
Get("one/:id"),
|
|
1541
1658
|
__decorateParam(0, Param("id")),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/moost-db",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.105",
|
|
4
4
|
"description": "Generic database controller for Moost with Atscript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"annotations",
|
|
@@ -41,24 +41,24 @@
|
|
|
41
41
|
"@uniqu/url": "^0.1.6"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@atscript/core": "^0.1.
|
|
45
|
-
"@atscript/typescript": "^0.1.
|
|
46
|
-
"@moostjs/event-http": "^0.6.
|
|
44
|
+
"@atscript/core": "^0.1.76",
|
|
45
|
+
"@atscript/typescript": "^0.1.76",
|
|
46
|
+
"@moostjs/event-http": "^0.6.27",
|
|
47
47
|
"@uniqu/core": "^0.1.6",
|
|
48
48
|
"@wooksjs/event-core": "^0.7.19",
|
|
49
49
|
"@wooksjs/event-http": "^0.7.19",
|
|
50
50
|
"@wooksjs/http-body": "^0.7.19",
|
|
51
|
-
"moost": "^0.6.
|
|
52
|
-
"unplugin-atscript": "^0.1.
|
|
51
|
+
"moost": "^0.6.27",
|
|
52
|
+
"unplugin-atscript": "^0.1.76"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
|
-
"@atscript/typescript": "^0.1.
|
|
56
|
-
"@moostjs/event-http": "^0.6.
|
|
55
|
+
"@atscript/typescript": "^0.1.76",
|
|
56
|
+
"@moostjs/event-http": "^0.6.27",
|
|
57
57
|
"@uniqu/core": "^0.1.6",
|
|
58
58
|
"@wooksjs/event-core": "^0.7.19",
|
|
59
59
|
"@wooksjs/http-body": "^0.7.19",
|
|
60
|
-
"moost": "^0.6.
|
|
61
|
-
"@atscript/db": "^0.1.
|
|
60
|
+
"moost": "^0.6.27",
|
|
61
|
+
"@atscript/db": "^0.1.105"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"postinstall": "asc -f dts",
|