@mastra/pg 1.15.0-alpha.0 → 1.15.0-alpha.2
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/CHANGELOG.md +159 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +183 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +183 -51
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/datasets/index.d.ts +6 -7
- package/dist/storage/domains/datasets/index.d.ts.map +1 -1
- package/dist/storage/domains/experiments/index.d.ts +9 -5
- package/dist/storage/domains/experiments/index.d.ts.map +1 -1
- package/dist/storage/domains/scorer-definitions/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +9 -5
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/utils.d.ts +20 -1
- package/dist/storage/domains/utils.d.ts.map +1 -1
- package/dist/storage/test-utils.d.ts.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,164 @@
|
|
|
1
1
|
# @mastra/pg
|
|
2
2
|
|
|
3
|
+
## 1.15.0-alpha.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Raise `@mastra/core` peer floor to `>=1.49.0-0` on all storage adapters so the tenancy-related named exports the adapters now consume are guaranteed to exist at install time. ([#18861](https://github.com/mastra-ai/mastra/pull/18861))
|
|
8
|
+
|
|
9
|
+
## 1.15.0-alpha.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Added optional tenancy arguments to `getDataset`, `updateDataset`, and `deleteDataset`. ([#18750](https://github.com/mastra-ai/mastra/pull/18750))
|
|
14
|
+
|
|
15
|
+
You can now pass `organizationId` and `projectId` to scope dataset reads, updates, and deletes to a specific tenant. Reads and updates against a dataset in a different tenant throw `DATASET_NOT_FOUND` (surfaced as a 404 over HTTP). Deletes silently no-op on a tenancy mismatch — matching the existing "delete non-existent id is a no-op" semantics so cross-tenant existence is never leaked via error timing or status.
|
|
16
|
+
|
|
17
|
+
**Example**
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// Before
|
|
21
|
+
await client.getDataset('abc123');
|
|
22
|
+
await client.deleteDataset('abc123');
|
|
23
|
+
await client.updateDataset({ id: 'abc123', name: 'renamed' });
|
|
24
|
+
|
|
25
|
+
// After — scope to a tenant
|
|
26
|
+
await client.getDataset('abc123', { organizationId: 'org_a', projectId: 'proj_1' });
|
|
27
|
+
await client.deleteDataset('abc123', { organizationId: 'org_a' });
|
|
28
|
+
await client.updateDataset({ id: 'abc123', name: 'renamed', organizationId: 'org_a' });
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- Pushed remaining dataset read filters and pagination down to storage. ([#18710](https://github.com/mastra-ai/mastra/pull/18710))
|
|
32
|
+
|
|
33
|
+
`DatasetsManager.list({ filters })` now accepts `targetType`, `targetIds` (overlap/union semantics), and `name` (substring, case-insensitive) in addition to the existing tenancy and candidate filters. Filtering is pushed down to the storage layer so callers no longer have to post-filter results.
|
|
34
|
+
|
|
35
|
+
Storage adapters must also be upgraded to the versions listed below to honor the new filters. If a caller is on this version of `@mastra/core` but on an older storage adapter, the new `targetType`/`targetIds`/`name` filter keys are silently ignored by the adapter — no runtime error, but the filter has no effect and every dataset in the tenancy is returned.
|
|
36
|
+
|
|
37
|
+
`Dataset.listItems({ version, search, page, perPage })` now applies `search` and pagination at the storage layer when `version` is provided alongside any of those. Previously they were silently dropped whenever `version` was set. The return shape is unchanged: passing only `version` still returns a bare `DatasetItem[]` snapshot; passing `search`, `page`, or `perPage` (with or without `version`) returns the paginated `{ items, pagination }` shape. The bare-array branch is marked `@deprecated`; prefer passing `page` / `perPage` to always receive the paginated shape.
|
|
38
|
+
|
|
39
|
+
- Tenancy-scope experiments `getById` and `delete*` on `ExperimentsStorage`. ([#18770](https://github.com/mastra-ai/mastra/pull/18770))
|
|
40
|
+
|
|
41
|
+
`ExperimentsStorage.getExperimentById`, `getExperimentResultById`, `deleteExperiment`, and `deleteExperimentResults` used to key on the primary id alone, so any caller who knew the id could read or delete the row regardless of tenant. All four now accept an optional `filters: { organizationId?, projectId? }` argument that is enforced on every adapter (inmemory, libsql, pg, mysql, mongodb, spanner):
|
|
42
|
+
- On tenancy mismatch, `get*` returns `null` at the storage layer.
|
|
43
|
+
- On tenancy mismatch, `delete*` is a silent no-op.
|
|
44
|
+
- The tenancy predicate is folded into the destructive DML itself (scoped `WHERE` on the DELETE, an atomic gate + delete inside a transaction, or a scoped subquery for the results cascade). A concurrent tenant swap of the same id between a pre-check and the DELETE cannot let a scoped delete hit another tenant's row.
|
|
45
|
+
|
|
46
|
+
Both behaviors match how a missing id already responds, so existence does not leak through error timing or messages.
|
|
47
|
+
|
|
48
|
+
The same atomic-DML pattern is also applied to `DatasetsStorage.deleteDataset` across all 5 store adapters, closing a TOCTOU window between the pre-check and the parent DELETE that was introduced when tenancy filters were originally added.
|
|
49
|
+
|
|
50
|
+
`Dataset.getExperiment` and the shared experiment-ownership gate on `Dataset` now forward the dataset's tenancy scope to storage, so experiment reads and downstream mutations (list results, update result, delete experiment) reached through a dataset handle are automatically scoped to the owning tenant.
|
|
51
|
+
|
|
52
|
+
Legacy calls that omit `filters` are unchanged, so this is fully backwards-compatible.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
// Before: any caller who knew the id could read/delete across tenants.
|
|
56
|
+
await store.experiments.getExperimentById({ id: experimentId });
|
|
57
|
+
await store.experiments.deleteExperiment({ id: experimentId });
|
|
58
|
+
|
|
59
|
+
// After: pass the caller's scope; wrong tenant gets null / silent no-op.
|
|
60
|
+
await store.experiments.getExperimentById({
|
|
61
|
+
id: experimentId,
|
|
62
|
+
filters: { organizationId, projectId },
|
|
63
|
+
});
|
|
64
|
+
await store.experiments.deleteExperiment({
|
|
65
|
+
id: experimentId,
|
|
66
|
+
filters: { organizationId, projectId },
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- Fixed a double-encoding bug where `createDataset` and `updateDataset` stored `targetIds` and `scorerIds` as JSON-encoded strings into the `JSONB` columns instead of arrays. This caused the new `listDatasets({ filters: { targetIds } })` overlap query (`targetIds ?| array[...]`) to never match. ([#18710](https://github.com/mastra-ai/mastra/pull/18710))
|
|
71
|
+
|
|
72
|
+
Existing rows written before this fix are still double-encoded and will not be matched by the new `targetIds` filter. They self-heal on the next `updateDataset` call. Deployments with a long tail of pre-existing datasets should run a one-time backfill (re-encoding `targetIds` and `scorerIds` on affected rows) rather than rely on incidental writes; this can be tracked as a follow-up if needed.
|
|
73
|
+
|
|
74
|
+
- Fixed a cross-tenant data-access issue on datasets by scoping `DatasetsManager.get` and `DatasetsManager.delete` to tenancy filters. ([#18750](https://github.com/mastra-ai/mastra/pull/18750))
|
|
75
|
+
|
|
76
|
+
Previously `get({ id })` and `delete({ id })` looked up a dataset by its primary key alone. Any caller who knew a dataset id could read or delete it regardless of which `organizationId` / `projectId` it belonged to. This is now closed at the storage layer via a scoped SQL predicate (option (a) — no fetch-then-assert).
|
|
77
|
+
|
|
78
|
+
**What changed**
|
|
79
|
+
- `DatasetsManager.get` and `DatasetsManager.delete` accept optional `organizationId` and `projectId`.
|
|
80
|
+
- The tenancy is stashed on the returned `Dataset` handle and forwarded to every downstream storage call (`getDetails`, `update`, `addItem`, item batch ops, `startExperimentAsync`).
|
|
81
|
+
- The abstract storage contract (`getDatasetById`, `deleteDataset`) gained an optional `filters?: DatasetTenancyFilters` arg.
|
|
82
|
+
- Item-mutation inputs (`AddDatasetItemInput`, `UpdateDatasetItemInput`, `BatchInsertItemsInput`, `BatchDeleteItemsInput`) and `UpdateDatasetInput` accept optional `filters` for the internal existence check.
|
|
83
|
+
|
|
84
|
+
**Behavior**
|
|
85
|
+
- Omitting tenancy preserves the existing behavior (no predicate added) — fully backwards compatible.
|
|
86
|
+
- On tenancy mismatch, `get` throws NOT_FOUND (returns null at the storage layer) and `delete` is a silent no-op — matching how a missing id already behaves, so existence does not leak through error timing or messages.
|
|
87
|
+
|
|
88
|
+
**Example**
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// Before
|
|
92
|
+
const ds = await mastra.datasets.get({ id });
|
|
93
|
+
await mastra.datasets.delete({ id });
|
|
94
|
+
|
|
95
|
+
// After — scope to a tenant
|
|
96
|
+
const ds = await mastra.datasets.get({ id, organizationId, projectId });
|
|
97
|
+
await mastra.datasets.delete({ id, organizationId, projectId });
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- Add optional `batchId`, `datasetId`, and `datasetItemId` fields to persisted scores so saved baseline scores can be grouped as one scoring pass and joined back to the dataset items they came from. ([#18331](https://github.com/mastra-ai/mastra/pull/18331))
|
|
101
|
+
- `scoreTrace()` accepts top-level `batchId`, `datasetId`, and `datasetItemId` when persisting a score for a stored trace.
|
|
102
|
+
- `ScoreRowData` and score save payloads now include nullable `batchId`, `datasetId`, and `datasetItemId`.
|
|
103
|
+
- Built-in stores with explicit score schema or attribute mappings now persist these provenance fields on saved scores.
|
|
104
|
+
- D1, DSQL, MSSQL, and Upstash score stores now apply additive provenance migrations or deterministic score ordering for persisted score reads.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
await scoreTrace({
|
|
108
|
+
storage,
|
|
109
|
+
scorer,
|
|
110
|
+
target: { traceId },
|
|
111
|
+
batchId: 'baseline-batch-1',
|
|
112
|
+
datasetId,
|
|
113
|
+
datasetItemId,
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- Added multi-tenant scoping to stored scorer definitions. Stored scorers now persist optional `organizationId` and `projectId` on the definition record, and `list`/`listResolved` accept matching filters to scope results by tenant. The Postgres adapter backfills the new columns and applies the scoped filters; tenancy lives on the record while version snapshots stay pure config. ([#18331](https://github.com/mastra-ai/mastra/pull/18331))
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
await storage.create({
|
|
121
|
+
scorerDefinition: { id, organizationId: 'org-a', projectId: 'proj-1', ...config },
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const { scorerDefinitions } = await storage.list({
|
|
125
|
+
status: 'draft',
|
|
126
|
+
organizationId: 'org-a',
|
|
127
|
+
projectId: 'proj-1',
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- Added optional `organizationId` and `projectId` fields to scores for multi-tenant isolation. Scores can now be saved with tenancy metadata and the `listScoresBy*` methods accept a `filters` option to scope results by organization and project. ([#18331](https://github.com/mastra-ai/mastra/pull/18331))
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
await storage.saveScore({ ...score, organizationId: 'org-a', projectId: 'proj-1' });
|
|
135
|
+
|
|
136
|
+
const result = await storage.listScoresByScorerId({
|
|
137
|
+
scorerId,
|
|
138
|
+
filters: { organizationId: 'org-a', projectId: 'proj-1' },
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`projectId` identifies the project scope, separate from `resourceId` which continues to mean the agent memory resource.
|
|
143
|
+
|
|
144
|
+
- Scoped `getDatasetById` and `deleteDataset` to tenancy filters when the caller passes `organizationId` / `projectId`. ([#18750](https://github.com/mastra-ai/mastra/pull/18750))
|
|
145
|
+
|
|
146
|
+
The adapters now push the tenancy predicate into the SQL/query when the new optional `filters` argument is present. Legacy calls that omit tenancy are unchanged. On mismatch, `getDatasetById` returns `null` and `deleteDataset` is a silent no-op — the cascade delete (dataset items and versions) is gated by a scoped parent pre-check, so cross-tenant data is never touched.
|
|
147
|
+
|
|
148
|
+
- Added optional `organizationId` and `projectId` query parameters to the dataset routes. ([#18750](https://github.com/mastra-ai/mastra/pull/18750))
|
|
149
|
+
|
|
150
|
+
`GET /datasets/:datasetId`, `PATCH /datasets/:datasetId`, and `DELETE /datasets/:datasetId` now accept optional tenancy query parameters. When provided, they are forwarded to `mastra.datasets.get` / `.delete` and the operation returns 404 if the dataset does not belong to the requested tenant. Requests that omit the query parameters keep their existing behavior.
|
|
151
|
+
|
|
152
|
+
**Example**
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
GET /datasets/abc123?organizationId=org_a&projectId=proj_1
|
|
156
|
+
DELETE /datasets/abc123?organizationId=org_a
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
- Updated dependencies [[`9250acd`](https://github.com/mastra-ai/mastra/commit/9250acd1357f0f1f33d0dcca16f9655084c58eca), [`215f9b0`](https://github.com/mastra-ai/mastra/commit/215f9b0f3f3f6fc165edad360582dd4d3d7ea748), [`c64c2a8`](https://github.com/mastra-ai/mastra/commit/c64c2a8503a50252f9ca6b8e8c54cadee31b92a2), [`06e2680`](https://github.com/mastra-ai/mastra/commit/06e26806b51d2cbd858afdc66daa2b86ff3ba64a), [`1240f05`](https://github.com/mastra-ai/mastra/commit/1240f051c8e5371f1c014448bf37b1a1b9a05e47), [`215f9b0`](https://github.com/mastra-ai/mastra/commit/215f9b0f3f3f6fc165edad360582dd4d3d7ea748), [`24c10d3`](https://github.com/mastra-ai/mastra/commit/24c10d333e6649ac06075903aeeee13a933db3b3), [`24c10d3`](https://github.com/mastra-ai/mastra/commit/24c10d333e6649ac06075903aeeee13a933db3b3), [`24c10d3`](https://github.com/mastra-ai/mastra/commit/24c10d333e6649ac06075903aeeee13a933db3b3), [`24c10d3`](https://github.com/mastra-ai/mastra/commit/24c10d333e6649ac06075903aeeee13a933db3b3), [`215f9b0`](https://github.com/mastra-ai/mastra/commit/215f9b0f3f3f6fc165edad360582dd4d3d7ea748), [`215f9b0`](https://github.com/mastra-ai/mastra/commit/215f9b0f3f3f6fc165edad360582dd4d3d7ea748)]:
|
|
160
|
+
- @mastra/core@1.49.0-alpha.5
|
|
161
|
+
|
|
3
162
|
## 1.15.0-alpha.0
|
|
4
163
|
|
|
5
164
|
### Minor Changes
|
package/dist/docs/SKILL.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -3748,6 +3748,20 @@ function transformFromSqlRow({
|
|
|
3748
3748
|
});
|
|
3749
3749
|
return result;
|
|
3750
3750
|
}
|
|
3751
|
+
function tenancyWhere(filters, startIndex) {
|
|
3752
|
+
const conditions = [];
|
|
3753
|
+
const params = [];
|
|
3754
|
+
let idx = startIndex;
|
|
3755
|
+
if (filters?.organizationId !== void 0) {
|
|
3756
|
+
conditions.push(`"organizationId" = $${idx++}`);
|
|
3757
|
+
params.push(filters.organizationId);
|
|
3758
|
+
}
|
|
3759
|
+
if (filters?.projectId !== void 0) {
|
|
3760
|
+
conditions.push(`"projectId" = $${idx++}`);
|
|
3761
|
+
params.push(filters.projectId);
|
|
3762
|
+
}
|
|
3763
|
+
return { conditions, params, nextIndex: idx };
|
|
3764
|
+
}
|
|
3751
3765
|
|
|
3752
3766
|
// src/storage/domains/agents/index.ts
|
|
3753
3767
|
var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
|
|
@@ -5603,8 +5617,8 @@ var DatasetsPG = class _DatasetsPG extends storage.DatasetsStorage {
|
|
|
5603
5617
|
groundTruthSchema: input.groundTruthSchema ?? null,
|
|
5604
5618
|
requestContextSchema: input.requestContextSchema ?? null,
|
|
5605
5619
|
targetType: input.targetType ?? null,
|
|
5606
|
-
targetIds: input.targetIds
|
|
5607
|
-
scorerIds: input.scorerIds
|
|
5620
|
+
targetIds: input.targetIds ?? null,
|
|
5621
|
+
scorerIds: input.scorerIds ?? null,
|
|
5608
5622
|
organizationId: input.organizationId ?? null,
|
|
5609
5623
|
projectId: input.projectId ?? null,
|
|
5610
5624
|
candidateKey: input.candidateKey ?? null,
|
|
@@ -5644,10 +5658,15 @@ var DatasetsPG = class _DatasetsPG extends storage.DatasetsStorage {
|
|
|
5644
5658
|
);
|
|
5645
5659
|
}
|
|
5646
5660
|
}
|
|
5647
|
-
async getDatasetById({
|
|
5661
|
+
async getDatasetById({
|
|
5662
|
+
id,
|
|
5663
|
+
filters
|
|
5664
|
+
}) {
|
|
5648
5665
|
try {
|
|
5649
5666
|
const tableName = getTableName2({ indexName: storage.TABLE_DATASETS, schemaName: getSchemaName2(this.#schema) });
|
|
5650
|
-
const
|
|
5667
|
+
const { conditions, params } = tenancyWhere(filters, 2);
|
|
5668
|
+
const whereSql = ['"id" = $1', ...conditions].join(" AND ");
|
|
5669
|
+
const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE ${whereSql}`, [id, ...params]);
|
|
5651
5670
|
return result ? this.transformDatasetRow(result) : null;
|
|
5652
5671
|
} catch (error$1) {
|
|
5653
5672
|
throw new error.MastraError(
|
|
@@ -5662,7 +5681,7 @@ var DatasetsPG = class _DatasetsPG extends storage.DatasetsStorage {
|
|
|
5662
5681
|
}
|
|
5663
5682
|
async _doUpdateDataset(args) {
|
|
5664
5683
|
try {
|
|
5665
|
-
const existing = await this.getDatasetById({ id: args.id });
|
|
5684
|
+
const existing = await this.getDatasetById({ id: args.id, filters: args.filters });
|
|
5666
5685
|
if (!existing) {
|
|
5667
5686
|
throw new error.MastraError({
|
|
5668
5687
|
id: storage.createStorageErrorId("PG", "UPDATE_DATASET", "NOT_FOUND"),
|
|
@@ -5751,7 +5770,7 @@ var DatasetsPG = class _DatasetsPG extends storage.DatasetsStorage {
|
|
|
5751
5770
|
);
|
|
5752
5771
|
}
|
|
5753
5772
|
}
|
|
5754
|
-
async deleteDataset({ id }) {
|
|
5773
|
+
async deleteDataset({ id, filters }) {
|
|
5755
5774
|
try {
|
|
5756
5775
|
const datasetsTable = getTableName2({ indexName: storage.TABLE_DATASETS, schemaName: getSchemaName2(this.#schema) });
|
|
5757
5776
|
const itemsTable = getTableName2({ indexName: storage.TABLE_DATASET_ITEMS, schemaName: getSchemaName2(this.#schema) });
|
|
@@ -5764,24 +5783,31 @@ var DatasetsPG = class _DatasetsPG extends storage.DatasetsStorage {
|
|
|
5764
5783
|
indexName: storage.TABLE_EXPERIMENT_RESULTS,
|
|
5765
5784
|
schemaName: getSchemaName2(this.#schema)
|
|
5766
5785
|
});
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
`DELETE FROM ${experimentResultsTable} WHERE "experimentId" IN (SELECT "id" FROM ${experimentsTable} WHERE "datasetId" = $1)`,
|
|
5770
|
-
[id]
|
|
5771
|
-
);
|
|
5772
|
-
} catch {
|
|
5773
|
-
}
|
|
5774
|
-
try {
|
|
5775
|
-
await this.#db.client.none(
|
|
5776
|
-
`UPDATE ${experimentsTable} SET "datasetId" = NULL, "datasetVersion" = NULL WHERE "datasetId" = $1`,
|
|
5777
|
-
[id]
|
|
5778
|
-
);
|
|
5779
|
-
} catch {
|
|
5780
|
-
}
|
|
5786
|
+
const { conditions, params } = tenancyWhere(filters, 2);
|
|
5787
|
+
const scopedWhere = ['"id" = $1', ...conditions].join(" AND ");
|
|
5781
5788
|
await this.#db.client.tx(async (t) => {
|
|
5789
|
+
const locked = await t.oneOrNone(`SELECT "id" FROM ${datasetsTable} WHERE ${scopedWhere} FOR UPDATE`, [
|
|
5790
|
+
id,
|
|
5791
|
+
...params
|
|
5792
|
+
]);
|
|
5793
|
+
if (!locked) return;
|
|
5794
|
+
const experimentTablesExist = await t.oneOrNone(
|
|
5795
|
+
`SELECT to_regclass($1) IS NOT NULL AND to_regclass($2) IS NOT NULL AS exists`,
|
|
5796
|
+
[experimentResultsTable, experimentsTable]
|
|
5797
|
+
);
|
|
5798
|
+
if (experimentTablesExist?.exists) {
|
|
5799
|
+
await t.none(
|
|
5800
|
+
`DELETE FROM ${experimentResultsTable} WHERE "experimentId" IN (SELECT "id" FROM ${experimentsTable} WHERE "datasetId" = $1)`,
|
|
5801
|
+
[id]
|
|
5802
|
+
);
|
|
5803
|
+
await t.none(
|
|
5804
|
+
`UPDATE ${experimentsTable} SET "datasetId" = NULL, "datasetVersion" = NULL WHERE "datasetId" = $1`,
|
|
5805
|
+
[id]
|
|
5806
|
+
);
|
|
5807
|
+
}
|
|
5782
5808
|
await t.none(`DELETE FROM ${versionsTable} WHERE "datasetId" = $1`, [id]);
|
|
5783
5809
|
await t.none(`DELETE FROM ${itemsTable} WHERE "datasetId" = $1`, [id]);
|
|
5784
|
-
await t.none(`DELETE FROM ${datasetsTable} WHERE
|
|
5810
|
+
await t.none(`DELETE FROM ${datasetsTable} WHERE ${scopedWhere}`, [id, ...params]);
|
|
5785
5811
|
});
|
|
5786
5812
|
} catch (error$1) {
|
|
5787
5813
|
if (error$1 instanceof error.MastraError) throw error$1;
|
|
@@ -5803,7 +5829,7 @@ var DatasetsPG = class _DatasetsPG extends storage.DatasetsStorage {
|
|
|
5803
5829
|
const queryParams = [];
|
|
5804
5830
|
let paramIndex = 1;
|
|
5805
5831
|
if (args.filters) {
|
|
5806
|
-
const { organizationId, projectId, candidateKey, candidateId } = args.filters;
|
|
5832
|
+
const { organizationId, projectId, candidateKey, candidateId, targetType, targetIds, name } = args.filters;
|
|
5807
5833
|
if (organizationId !== void 0) {
|
|
5808
5834
|
conditions.push(`"organizationId" = $${paramIndex++}`);
|
|
5809
5835
|
queryParams.push(organizationId);
|
|
@@ -5820,6 +5846,18 @@ var DatasetsPG = class _DatasetsPG extends storage.DatasetsStorage {
|
|
|
5820
5846
|
conditions.push(`"candidateId" = $${paramIndex++}`);
|
|
5821
5847
|
queryParams.push(candidateId);
|
|
5822
5848
|
}
|
|
5849
|
+
if (targetType !== void 0) {
|
|
5850
|
+
conditions.push(`"targetType" = $${paramIndex++}`);
|
|
5851
|
+
queryParams.push(targetType);
|
|
5852
|
+
}
|
|
5853
|
+
if (targetIds !== void 0 && targetIds.length > 0) {
|
|
5854
|
+
conditions.push(`"targetIds" ?| $${paramIndex++}::text[]`);
|
|
5855
|
+
queryParams.push(targetIds);
|
|
5856
|
+
}
|
|
5857
|
+
if (name !== void 0 && name.length > 0) {
|
|
5858
|
+
conditions.push(`"name" ILIKE $${paramIndex++}`);
|
|
5859
|
+
queryParams.push(`%${name}%`);
|
|
5860
|
+
}
|
|
5823
5861
|
}
|
|
5824
5862
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
5825
5863
|
const countResult = await this.#db.client.one(
|
|
@@ -6831,10 +6869,15 @@ var ExperimentsPG = class _ExperimentsPG extends storage.ExperimentsStorage {
|
|
|
6831
6869
|
);
|
|
6832
6870
|
}
|
|
6833
6871
|
}
|
|
6834
|
-
async getExperimentById({
|
|
6872
|
+
async getExperimentById({
|
|
6873
|
+
id,
|
|
6874
|
+
filters
|
|
6875
|
+
}) {
|
|
6835
6876
|
try {
|
|
6836
6877
|
const tableName = getTableName2({ indexName: storage.TABLE_EXPERIMENTS, schemaName: getSchemaName2(this.#schema) });
|
|
6837
|
-
const
|
|
6878
|
+
const { conditions, params } = tenancyWhere(filters, 2);
|
|
6879
|
+
const whereSql = ['"id" = $1', ...conditions].join(" AND ");
|
|
6880
|
+
const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE ${whereSql}`, [id, ...params]);
|
|
6838
6881
|
return result ? this.transformExperimentRow(result) : null;
|
|
6839
6882
|
} catch (error$1) {
|
|
6840
6883
|
throw new error.MastraError(
|
|
@@ -6921,15 +6964,21 @@ var ExperimentsPG = class _ExperimentsPG extends storage.ExperimentsStorage {
|
|
|
6921
6964
|
);
|
|
6922
6965
|
}
|
|
6923
6966
|
}
|
|
6924
|
-
async deleteExperiment({ id }) {
|
|
6967
|
+
async deleteExperiment({ id, filters }) {
|
|
6925
6968
|
try {
|
|
6926
6969
|
const resultsTable = getTableName2({
|
|
6927
6970
|
indexName: storage.TABLE_EXPERIMENT_RESULTS,
|
|
6928
6971
|
schemaName: getSchemaName2(this.#schema)
|
|
6929
6972
|
});
|
|
6930
6973
|
const experimentsTable = getTableName2({ indexName: storage.TABLE_EXPERIMENTS, schemaName: getSchemaName2(this.#schema) });
|
|
6931
|
-
|
|
6932
|
-
|
|
6974
|
+
const { conditions, params } = tenancyWhere(filters, 2);
|
|
6975
|
+
const gateSql = `SELECT "id" FROM ${experimentsTable} WHERE ${['"id" = $1', ...conditions].join(" AND ")} FOR UPDATE`;
|
|
6976
|
+
await this.#db.client.tx(async (t) => {
|
|
6977
|
+
const parent = await t.oneOrNone(gateSql, [id, ...params]);
|
|
6978
|
+
if (!parent) return;
|
|
6979
|
+
await t.none(`DELETE FROM ${resultsTable} WHERE "experimentId" = $1`, [id]);
|
|
6980
|
+
await t.none(`DELETE FROM ${experimentsTable} WHERE "id" = $1`, [id]);
|
|
6981
|
+
});
|
|
6933
6982
|
} catch (error$1) {
|
|
6934
6983
|
throw new error.MastraError(
|
|
6935
6984
|
{
|
|
@@ -7059,10 +7108,15 @@ var ExperimentsPG = class _ExperimentsPG extends storage.ExperimentsStorage {
|
|
|
7059
7108
|
);
|
|
7060
7109
|
}
|
|
7061
7110
|
}
|
|
7062
|
-
async getExperimentResultById({
|
|
7111
|
+
async getExperimentResultById({
|
|
7112
|
+
id,
|
|
7113
|
+
filters
|
|
7114
|
+
}) {
|
|
7063
7115
|
try {
|
|
7064
7116
|
const tableName = getTableName2({ indexName: storage.TABLE_EXPERIMENT_RESULTS, schemaName: getSchemaName2(this.#schema) });
|
|
7065
|
-
const
|
|
7117
|
+
const { conditions, params } = tenancyWhere(filters, 2);
|
|
7118
|
+
const whereSql = ['"id" = $1', ...conditions].join(" AND ");
|
|
7119
|
+
const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE ${whereSql}`, [id, ...params]);
|
|
7066
7120
|
return result ? this.transformExperimentResultRow(result) : null;
|
|
7067
7121
|
} catch (error$1) {
|
|
7068
7122
|
throw new error.MastraError(
|
|
@@ -7137,9 +7191,23 @@ var ExperimentsPG = class _ExperimentsPG extends storage.ExperimentsStorage {
|
|
|
7137
7191
|
);
|
|
7138
7192
|
}
|
|
7139
7193
|
}
|
|
7140
|
-
async deleteExperimentResults({
|
|
7194
|
+
async deleteExperimentResults({
|
|
7195
|
+
experimentId,
|
|
7196
|
+
filters
|
|
7197
|
+
}) {
|
|
7141
7198
|
try {
|
|
7142
7199
|
const tableName = getTableName2({ indexName: storage.TABLE_EXPERIMENT_RESULTS, schemaName: getSchemaName2(this.#schema) });
|
|
7200
|
+
const experimentsTable = getTableName2({ indexName: storage.TABLE_EXPERIMENTS, schemaName: getSchemaName2(this.#schema) });
|
|
7201
|
+
if (filters?.organizationId !== void 0 || filters?.projectId !== void 0) {
|
|
7202
|
+
const { conditions, params } = tenancyWhere(filters, 2);
|
|
7203
|
+
const gateSql = `SELECT "id" FROM ${experimentsTable} WHERE ${['"id" = $1', ...conditions].join(" AND ")} FOR UPDATE`;
|
|
7204
|
+
await this.#db.client.tx(async (t) => {
|
|
7205
|
+
const parent = await t.oneOrNone(gateSql, [experimentId, ...params]);
|
|
7206
|
+
if (!parent) return;
|
|
7207
|
+
await t.none(`DELETE FROM ${tableName} WHERE "experimentId" = $1`, [experimentId]);
|
|
7208
|
+
});
|
|
7209
|
+
return;
|
|
7210
|
+
}
|
|
7143
7211
|
await this.#db.client.none(`DELETE FROM ${tableName} WHERE "experimentId" = $1`, [experimentId]);
|
|
7144
7212
|
} catch (error$1) {
|
|
7145
7213
|
throw new error.MastraError(
|
|
@@ -16828,6 +16896,11 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends storage.ScorerDefin
|
|
|
16828
16896
|
tableName: storage.TABLE_SCORER_DEFINITIONS,
|
|
16829
16897
|
schema: storage.TABLE_SCHEMAS[storage.TABLE_SCORER_DEFINITIONS]
|
|
16830
16898
|
});
|
|
16899
|
+
await this.#db.alterTable({
|
|
16900
|
+
tableName: storage.TABLE_SCORER_DEFINITIONS,
|
|
16901
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_SCORER_DEFINITIONS],
|
|
16902
|
+
ifNotExists: ["organizationId", "projectId"]
|
|
16903
|
+
});
|
|
16831
16904
|
await this.#db.createTable({
|
|
16832
16905
|
tableName: storage.TABLE_SCORER_DEFINITION_VERSIONS,
|
|
16833
16906
|
schema: storage.TABLE_SCHEMAS[storage.TABLE_SCORER_DEFINITION_VERSIONS]
|
|
@@ -16883,14 +16956,16 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends storage.ScorerDefin
|
|
|
16883
16956
|
const nowIso = now.toISOString();
|
|
16884
16957
|
await this.#db.client.none(
|
|
16885
16958
|
`INSERT INTO ${tableName} (
|
|
16886
|
-
id, status, "activeVersionId", "authorId", metadata,
|
|
16959
|
+
id, status, "activeVersionId", "authorId", "organizationId", "projectId", metadata,
|
|
16887
16960
|
"createdAt", "createdAtZ", "updatedAt", "updatedAtZ"
|
|
16888
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
|
16961
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
|
|
16889
16962
|
[
|
|
16890
16963
|
scorerDefinition.id,
|
|
16891
16964
|
"draft",
|
|
16892
16965
|
null,
|
|
16893
16966
|
scorerDefinition.authorId ?? null,
|
|
16967
|
+
scorerDefinition.organizationId ?? null,
|
|
16968
|
+
scorerDefinition.projectId ?? null,
|
|
16894
16969
|
scorerDefinition.metadata ? JSON.stringify(scorerDefinition.metadata) : null,
|
|
16895
16970
|
nowIso,
|
|
16896
16971
|
nowIso,
|
|
@@ -16898,7 +16973,14 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends storage.ScorerDefin
|
|
|
16898
16973
|
nowIso
|
|
16899
16974
|
]
|
|
16900
16975
|
);
|
|
16901
|
-
const {
|
|
16976
|
+
const {
|
|
16977
|
+
id: _id,
|
|
16978
|
+
authorId: _authorId,
|
|
16979
|
+
organizationId: _organizationId,
|
|
16980
|
+
projectId: _projectId,
|
|
16981
|
+
metadata: _metadata,
|
|
16982
|
+
...snapshotConfig
|
|
16983
|
+
} = scorerDefinition;
|
|
16902
16984
|
const versionId = crypto.randomUUID();
|
|
16903
16985
|
await this.createVersion({
|
|
16904
16986
|
id: versionId,
|
|
@@ -16913,6 +16995,8 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends storage.ScorerDefin
|
|
|
16913
16995
|
status: "draft",
|
|
16914
16996
|
activeVersionId: void 0,
|
|
16915
16997
|
authorId: scorerDefinition.authorId,
|
|
16998
|
+
organizationId: scorerDefinition.organizationId,
|
|
16999
|
+
projectId: scorerDefinition.projectId,
|
|
16916
17000
|
metadata: scorerDefinition.metadata,
|
|
16917
17001
|
createdAt: now,
|
|
16918
17002
|
updatedAt: now
|
|
@@ -17026,7 +17110,16 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends storage.ScorerDefin
|
|
|
17026
17110
|
}
|
|
17027
17111
|
}
|
|
17028
17112
|
async list(args) {
|
|
17029
|
-
const {
|
|
17113
|
+
const {
|
|
17114
|
+
page = 0,
|
|
17115
|
+
perPage: perPageInput,
|
|
17116
|
+
orderBy,
|
|
17117
|
+
authorId,
|
|
17118
|
+
organizationId,
|
|
17119
|
+
projectId,
|
|
17120
|
+
metadata,
|
|
17121
|
+
status
|
|
17122
|
+
} = args || {};
|
|
17030
17123
|
const { field, direction } = this.parseOrderBy(orderBy);
|
|
17031
17124
|
if (page < 0) {
|
|
17032
17125
|
throw new error.MastraError(
|
|
@@ -17054,6 +17147,14 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends storage.ScorerDefin
|
|
|
17054
17147
|
conditions.push(`"authorId" = $${paramIdx++}`);
|
|
17055
17148
|
queryParams.push(authorId);
|
|
17056
17149
|
}
|
|
17150
|
+
if (organizationId !== void 0) {
|
|
17151
|
+
conditions.push(`"organizationId" = $${paramIdx++}`);
|
|
17152
|
+
queryParams.push(organizationId);
|
|
17153
|
+
}
|
|
17154
|
+
if (projectId !== void 0) {
|
|
17155
|
+
conditions.push(`"projectId" = $${paramIdx++}`);
|
|
17156
|
+
queryParams.push(projectId);
|
|
17157
|
+
}
|
|
17057
17158
|
if (metadata && Object.keys(metadata).length > 0) {
|
|
17058
17159
|
conditions.push(`metadata @> $${paramIdx++}::jsonb`);
|
|
17059
17160
|
queryParams.push(JSON.stringify(metadata));
|
|
@@ -17380,6 +17481,8 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends storage.ScorerDefin
|
|
|
17380
17481
|
status: row.status,
|
|
17381
17482
|
activeVersionId: row.activeVersionId,
|
|
17382
17483
|
authorId: row.authorId,
|
|
17484
|
+
organizationId: row.organizationId,
|
|
17485
|
+
projectId: row.projectId,
|
|
17383
17486
|
metadata: parseJsonResilient(row.metadata),
|
|
17384
17487
|
createdAt: new Date(row.createdAtZ || row.createdAt),
|
|
17385
17488
|
updatedAt: new Date(row.updatedAtZ || row.updatedAt)
|
|
@@ -17404,6 +17507,18 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends storage.ScorerDefin
|
|
|
17404
17507
|
};
|
|
17405
17508
|
}
|
|
17406
17509
|
};
|
|
17510
|
+
function applyTenancyFilters(conditions, queryParams, startIndex, filters) {
|
|
17511
|
+
let paramIndex = startIndex;
|
|
17512
|
+
if (filters?.organizationId !== void 0) {
|
|
17513
|
+
conditions.push(`"organizationId" = $${paramIndex++}`);
|
|
17514
|
+
queryParams.push(filters.organizationId);
|
|
17515
|
+
}
|
|
17516
|
+
if (filters?.projectId !== void 0) {
|
|
17517
|
+
conditions.push(`"projectId" = $${paramIndex++}`);
|
|
17518
|
+
queryParams.push(filters.projectId);
|
|
17519
|
+
}
|
|
17520
|
+
return paramIndex;
|
|
17521
|
+
}
|
|
17407
17522
|
function getSchemaName6(schema) {
|
|
17408
17523
|
return schema ? `"${schema}"` : '"public"';
|
|
17409
17524
|
}
|
|
@@ -17446,7 +17561,7 @@ var ScoresPG = class _ScoresPG extends storage.ScoresStorage {
|
|
|
17446
17561
|
await this.#db.alterTable({
|
|
17447
17562
|
tableName: storage.TABLE_SCORERS,
|
|
17448
17563
|
schema: storage.TABLE_SCHEMAS[storage.TABLE_SCORERS],
|
|
17449
|
-
ifNotExists: ["spanId", "requestContext"]
|
|
17564
|
+
ifNotExists: ["spanId", "requestContext", "organizationId", "projectId", "batchId", "datasetId", "datasetItemId"]
|
|
17450
17565
|
});
|
|
17451
17566
|
await this.createDefaultIndexes();
|
|
17452
17567
|
await this.createCustomIndexes();
|
|
@@ -17582,7 +17697,8 @@ var ScoresPG = class _ScoresPG extends storage.ScoresStorage {
|
|
|
17582
17697
|
pagination,
|
|
17583
17698
|
entityId,
|
|
17584
17699
|
entityType,
|
|
17585
|
-
source
|
|
17700
|
+
source,
|
|
17701
|
+
filters
|
|
17586
17702
|
}) {
|
|
17587
17703
|
try {
|
|
17588
17704
|
const conditions = [`"scorerId" = $1`];
|
|
@@ -17600,6 +17716,7 @@ var ScoresPG = class _ScoresPG extends storage.ScoresStorage {
|
|
|
17600
17716
|
conditions.push(`"source" = $${paramIndex++}`);
|
|
17601
17717
|
queryParams.push(source);
|
|
17602
17718
|
}
|
|
17719
|
+
paramIndex = applyTenancyFilters(conditions, queryParams, paramIndex, filters);
|
|
17603
17720
|
const whereClause = conditions.join(" AND ");
|
|
17604
17721
|
const total = await this.#db.client.oneOrNone(
|
|
17605
17722
|
`SELECT COUNT(*) FROM ${getTableName6({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName6(this.#schema) })} WHERE ${whereClause}`,
|
|
@@ -17713,12 +17830,17 @@ var ScoresPG = class _ScoresPG extends storage.ScoresStorage {
|
|
|
17713
17830
|
}
|
|
17714
17831
|
async listScoresByRunId({
|
|
17715
17832
|
runId,
|
|
17716
|
-
pagination
|
|
17833
|
+
pagination,
|
|
17834
|
+
filters
|
|
17717
17835
|
}) {
|
|
17718
17836
|
try {
|
|
17837
|
+
const conditions = [`"runId" = $1`];
|
|
17838
|
+
const queryParams = [runId];
|
|
17839
|
+
let paramIndex = applyTenancyFilters(conditions, queryParams, 2, filters);
|
|
17840
|
+
const whereClause = conditions.join(" AND ");
|
|
17719
17841
|
const total = await this.#db.client.oneOrNone(
|
|
17720
|
-
`SELECT COUNT(*) FROM ${getTableName6({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName6(this.#schema) })} WHERE
|
|
17721
|
-
|
|
17842
|
+
`SELECT COUNT(*) FROM ${getTableName6({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName6(this.#schema) })} WHERE ${whereClause}`,
|
|
17843
|
+
queryParams
|
|
17722
17844
|
);
|
|
17723
17845
|
const { page, perPage: perPageInput } = pagination;
|
|
17724
17846
|
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
@@ -17737,8 +17859,8 @@ var ScoresPG = class _ScoresPG extends storage.ScoresStorage {
|
|
|
17737
17859
|
const limitValue = perPageInput === false ? Number(total?.count) : perPage;
|
|
17738
17860
|
const end = perPageInput === false ? Number(total?.count) : start + perPage;
|
|
17739
17861
|
const result = await this.#db.client.manyOrNone(
|
|
17740
|
-
`SELECT * FROM ${getTableName6({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName6(this.#schema) })} WHERE "
|
|
17741
|
-
[
|
|
17862
|
+
`SELECT * FROM ${getTableName6({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName6(this.#schema) })} WHERE ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
|
|
17863
|
+
[...queryParams, limitValue, start]
|
|
17742
17864
|
);
|
|
17743
17865
|
return {
|
|
17744
17866
|
pagination: {
|
|
@@ -17763,12 +17885,17 @@ var ScoresPG = class _ScoresPG extends storage.ScoresStorage {
|
|
|
17763
17885
|
async listScoresByEntityId({
|
|
17764
17886
|
entityId,
|
|
17765
17887
|
entityType,
|
|
17766
|
-
pagination
|
|
17888
|
+
pagination,
|
|
17889
|
+
filters
|
|
17767
17890
|
}) {
|
|
17768
17891
|
try {
|
|
17892
|
+
const conditions = [`"entityId" = $1`, `"entityType" = $2`];
|
|
17893
|
+
const queryParams = [entityId, entityType];
|
|
17894
|
+
let paramIndex = applyTenancyFilters(conditions, queryParams, 3, filters);
|
|
17895
|
+
const whereClause = conditions.join(" AND ");
|
|
17769
17896
|
const total = await this.#db.client.oneOrNone(
|
|
17770
|
-
`SELECT COUNT(*) FROM ${getTableName6({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName6(this.#schema) })} WHERE
|
|
17771
|
-
|
|
17897
|
+
`SELECT COUNT(*) FROM ${getTableName6({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName6(this.#schema) })} WHERE ${whereClause}`,
|
|
17898
|
+
queryParams
|
|
17772
17899
|
);
|
|
17773
17900
|
const { page, perPage: perPageInput } = pagination;
|
|
17774
17901
|
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
@@ -17787,8 +17914,8 @@ var ScoresPG = class _ScoresPG extends storage.ScoresStorage {
|
|
|
17787
17914
|
const limitValue = perPageInput === false ? Number(total?.count) : perPage;
|
|
17788
17915
|
const end = perPageInput === false ? Number(total?.count) : start + perPage;
|
|
17789
17916
|
const result = await this.#db.client.manyOrNone(
|
|
17790
|
-
`SELECT * FROM ${getTableName6({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName6(this.#schema) })} WHERE
|
|
17791
|
-
[
|
|
17917
|
+
`SELECT * FROM ${getTableName6({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName6(this.#schema) })} WHERE ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
|
|
17918
|
+
[...queryParams, limitValue, start]
|
|
17792
17919
|
);
|
|
17793
17920
|
return {
|
|
17794
17921
|
pagination: {
|
|
@@ -17813,13 +17940,18 @@ var ScoresPG = class _ScoresPG extends storage.ScoresStorage {
|
|
|
17813
17940
|
async listScoresBySpan({
|
|
17814
17941
|
traceId,
|
|
17815
17942
|
spanId,
|
|
17816
|
-
pagination
|
|
17943
|
+
pagination,
|
|
17944
|
+
filters
|
|
17817
17945
|
}) {
|
|
17818
17946
|
try {
|
|
17819
17947
|
const tableName = getTableName6({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName6(this.#schema) });
|
|
17948
|
+
const conditions = [`"traceId" = $1`, `"spanId" = $2`];
|
|
17949
|
+
const queryParams = [traceId, spanId];
|
|
17950
|
+
let paramIndex = applyTenancyFilters(conditions, queryParams, 3, filters);
|
|
17951
|
+
const whereClause = conditions.join(" AND ");
|
|
17820
17952
|
const countSQLResult = await this.#db.client.oneOrNone(
|
|
17821
|
-
`SELECT COUNT(*) as count FROM ${tableName} WHERE
|
|
17822
|
-
|
|
17953
|
+
`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`,
|
|
17954
|
+
queryParams
|
|
17823
17955
|
);
|
|
17824
17956
|
const total = Number(countSQLResult?.count ?? 0);
|
|
17825
17957
|
const { page, perPage: perPageInput } = pagination;
|
|
@@ -17828,8 +17960,8 @@ var ScoresPG = class _ScoresPG extends storage.ScoresStorage {
|
|
|
17828
17960
|
const limitValue = perPageInput === false ? total : perPage;
|
|
17829
17961
|
const end = perPageInput === false ? total : start + perPage;
|
|
17830
17962
|
const result = await this.#db.client.manyOrNone(
|
|
17831
|
-
`SELECT * FROM ${tableName} WHERE
|
|
17832
|
-
[
|
|
17963
|
+
`SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
|
|
17964
|
+
[...queryParams, limitValue, start]
|
|
17833
17965
|
);
|
|
17834
17966
|
const hasMore = end < total;
|
|
17835
17967
|
const scores = result.map((row) => transformScoreRow(row)) ?? [];
|