@mastra/pg 1.12.1 → 1.13.0-alpha.1
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 +91 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-memory-working-memory.md +2 -2
- package/dist/docs/references/reference-storage-composite.md +34 -2
- package/dist/docs/references/reference-storage-postgresql.md +1 -1
- package/dist/index.cjs +3837 -147
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3836 -149
- package/dist/index.js.map +1 -1
- package/dist/{storage → shared}/pool-config.d.ts +10 -2
- package/dist/shared/pool-config.d.ts.map +1 -0
- package/dist/storage/domains/agents/index.d.ts.map +1 -1
- package/dist/storage/domains/background-tasks/index.d.ts.map +1 -1
- package/dist/storage/domains/blobs/index.d.ts +1 -0
- package/dist/storage/domains/blobs/index.d.ts.map +1 -1
- package/dist/storage/domains/mcp-clients/index.d.ts +2 -0
- package/dist/storage/domains/mcp-clients/index.d.ts.map +1 -1
- package/dist/storage/domains/mcp-servers/index.d.ts +2 -0
- package/dist/storage/domains/mcp-servers/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/ddl.d.ts +55 -0
- package/dist/storage/domains/observability/v-next/ddl.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/discovery.d.ts +52 -0
- package/dist/storage/domains/observability/v-next/discovery.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/feedback.d.ts +17 -0
- package/dist/storage/domains/observability/v-next/feedback.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/filters.d.ts +29 -0
- package/dist/storage/domains/observability/v-next/filters.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/helpers.d.ts +33 -0
- package/dist/storage/domains/observability/v-next/helpers.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/index.d.ts +104 -0
- package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/listing.d.ts +53 -0
- package/dist/storage/domains/observability/v-next/listing.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/logs.d.ts +8 -0
- package/dist/storage/domains/observability/v-next/logs.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/metrics.d.ts +19 -0
- package/dist/storage/domains/observability/v-next/metrics.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/olap.d.ts +93 -0
- package/dist/storage/domains/observability/v-next/olap.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/partitioning.d.ts +76 -0
- package/dist/storage/domains/observability/v-next/partitioning.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/pg-errors.d.ts +25 -0
- package/dist/storage/domains/observability/v-next/pg-errors.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/polling.d.ts +28 -0
- package/dist/storage/domains/observability/v-next/polling.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/scores.d.ts +17 -0
- package/dist/storage/domains/observability/v-next/scores.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/signal-schema.d.ts +776 -0
- package/dist/storage/domains/observability/v-next/signal-schema.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/sql.d.ts +31 -0
- package/dist/storage/domains/observability/v-next/sql.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/traces.d.ts +16 -0
- package/dist/storage/domains/observability/v-next/traces.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/tracing.d.ts +19 -0
- package/dist/storage/domains/observability/v-next/tracing.d.ts.map +1 -0
- package/dist/storage/domains/skills/index.d.ts +2 -0
- package/dist/storage/domains/skills/index.d.ts.map +1 -1
- package/dist/storage/domains/tool-provider-connections/index.d.ts +20 -0
- package/dist/storage/domains/tool-provider-connections/index.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/domains/workspaces/index.d.ts +2 -0
- package/dist/storage/domains/workspaces/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +89 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +9 -7
- package/dist/storage/pool-config.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -7,13 +7,14 @@ var vector = require('@mastra/core/vector');
|
|
|
7
7
|
var asyncMutex = require('async-mutex');
|
|
8
8
|
var pg = require('pg');
|
|
9
9
|
var xxhash = require('xxhash-wasm');
|
|
10
|
+
var pgConnectionString = require('pg-connection-string');
|
|
10
11
|
var filter = require('@mastra/core/vector/filter');
|
|
11
12
|
var base = require('@mastra/core/base');
|
|
12
13
|
var crypto$1 = require('crypto');
|
|
13
14
|
var module$1 = require('module');
|
|
14
15
|
var agent = require('@mastra/core/agent');
|
|
16
|
+
var features = require('@mastra/core/features');
|
|
15
17
|
var evals = require('@mastra/core/evals');
|
|
16
|
-
var pgConnectionString = require('pg-connection-string');
|
|
17
18
|
|
|
18
19
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
19
20
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -90,6 +91,15 @@ var validateConfig = (name, config) => {
|
|
|
90
91
|
);
|
|
91
92
|
}
|
|
92
93
|
};
|
|
94
|
+
function buildConnectionStringPoolConfig(config, defaults) {
|
|
95
|
+
const parsed = pgConnectionString.parse(config.connectionString);
|
|
96
|
+
return {
|
|
97
|
+
...parsed,
|
|
98
|
+
...config.ssl !== void 0 ? { ssl: config.ssl } : {},
|
|
99
|
+
max: config.max ?? defaults.max,
|
|
100
|
+
idleTimeoutMillis: config.idleTimeoutMillis ?? defaults.idleTimeoutMillis
|
|
101
|
+
};
|
|
102
|
+
}
|
|
93
103
|
var PGFilterTranslator = class extends filter.BaseFilterTranslator {
|
|
94
104
|
getSupportedOperators() {
|
|
95
105
|
return {
|
|
@@ -637,10 +647,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
637
647
|
let poolConfig;
|
|
638
648
|
if (isConnectionStringConfig(config)) {
|
|
639
649
|
poolConfig = {
|
|
640
|
-
|
|
641
|
-
ssl: config.ssl,
|
|
642
|
-
max: config.max ?? 20,
|
|
643
|
-
idleTimeoutMillis: config.idleTimeoutMillis ?? 3e4,
|
|
650
|
+
...buildConnectionStringPoolConfig(config, { max: 20, idleTimeoutMillis: 3e4 }),
|
|
644
651
|
connectionTimeoutMillis: 2e3,
|
|
645
652
|
...config.pgPoolOptions
|
|
646
653
|
};
|
|
@@ -3554,7 +3561,15 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
|
|
|
3554
3561
|
await this.#db.alterTable({
|
|
3555
3562
|
tableName: storage.TABLE_AGENT_VERSIONS,
|
|
3556
3563
|
schema: storage.TABLE_SCHEMAS[storage.TABLE_AGENT_VERSIONS],
|
|
3557
|
-
ifNotExists: [
|
|
3564
|
+
ifNotExists: [
|
|
3565
|
+
"mcpClients",
|
|
3566
|
+
"requestContextSchema",
|
|
3567
|
+
"workspace",
|
|
3568
|
+
"skills",
|
|
3569
|
+
"skillsFormat",
|
|
3570
|
+
"browser",
|
|
3571
|
+
"toolProviders"
|
|
3572
|
+
]
|
|
3558
3573
|
});
|
|
3559
3574
|
await this.#migrateToolsToJsonbFormat();
|
|
3560
3575
|
await this.createDefaultIndexes();
|
|
@@ -3607,9 +3622,9 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
|
|
|
3607
3622
|
await this.#db.client.none(
|
|
3608
3623
|
`INSERT INTO ${fullVersionsTableName}
|
|
3609
3624
|
(id, "agentId", "versionNumber", name, description, instructions, model, tools,
|
|
3610
|
-
"defaultOptions", workflows, agents, "integrationTools", "inputProcessors",
|
|
3625
|
+
"defaultOptions", workflows, agents, "integrationTools", "toolProviders", "inputProcessors",
|
|
3611
3626
|
"outputProcessors", memory, scorers, "changedFields", "changeMessage", "createdAt")
|
|
3612
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19)
|
|
3627
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20)
|
|
3613
3628
|
ON CONFLICT (id) DO NOTHING`,
|
|
3614
3629
|
[
|
|
3615
3630
|
versionId,
|
|
@@ -3624,6 +3639,7 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
|
|
|
3624
3639
|
row.workflows ? JSON.stringify(row.workflows) : null,
|
|
3625
3640
|
row.agents ? JSON.stringify(row.agents) : null,
|
|
3626
3641
|
row.integrationTools ? JSON.stringify(row.integrationTools) : null,
|
|
3642
|
+
row.toolProviders ? JSON.stringify(row.toolProviders) : null,
|
|
3627
3643
|
row.inputProcessors ? JSON.stringify(row.inputProcessors) : null,
|
|
3628
3644
|
row.outputProcessors ? JSON.stringify(row.outputProcessors) : null,
|
|
3629
3645
|
row.memory ? JSON.stringify(row.memory) : null,
|
|
@@ -4076,13 +4092,13 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
|
|
|
4076
4092
|
`INSERT INTO ${tableName} (
|
|
4077
4093
|
id, "agentId", "versionNumber",
|
|
4078
4094
|
name, description, instructions, model, tools,
|
|
4079
|
-
"defaultOptions", workflows, agents, "integrationTools",
|
|
4095
|
+
"defaultOptions", workflows, agents, "integrationTools", "toolProviders",
|
|
4080
4096
|
"inputProcessors", "outputProcessors", memory, scorers,
|
|
4081
4097
|
"mcpClients", "requestContextSchema", workspace, skills, "skillsFormat",
|
|
4082
4098
|
browser,
|
|
4083
4099
|
"changedFields", "changeMessage",
|
|
4084
4100
|
"createdAt", "createdAtZ"
|
|
4085
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26)`,
|
|
4101
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27)`,
|
|
4086
4102
|
[
|
|
4087
4103
|
input.id,
|
|
4088
4104
|
input.agentId,
|
|
@@ -4096,6 +4112,7 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
|
|
|
4096
4112
|
input.workflows ? JSON.stringify(input.workflows) : null,
|
|
4097
4113
|
input.agents ? JSON.stringify(input.agents) : null,
|
|
4098
4114
|
input.integrationTools ? JSON.stringify(input.integrationTools) : null,
|
|
4115
|
+
input.toolProviders ? JSON.stringify(input.toolProviders) : null,
|
|
4099
4116
|
input.inputProcessors ? JSON.stringify(input.inputProcessors) : null,
|
|
4100
4117
|
input.outputProcessors ? JSON.stringify(input.outputProcessors) : null,
|
|
4101
4118
|
input.memory ? JSON.stringify(input.memory) : null,
|
|
@@ -4346,6 +4363,7 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
|
|
|
4346
4363
|
workflows: parseJsonResilient(row.workflows),
|
|
4347
4364
|
agents: parseJsonResilient(row.agents),
|
|
4348
4365
|
integrationTools: parseJsonResilient(row.integrationTools),
|
|
4366
|
+
toolProviders: parseJsonResilient(row.toolProviders),
|
|
4349
4367
|
inputProcessors: parseJsonResilient(row.inputProcessors),
|
|
4350
4368
|
outputProcessors: parseJsonResilient(row.outputProcessors),
|
|
4351
4369
|
memory: parseJsonResilient(row.memory),
|
|
@@ -4384,6 +4402,10 @@ function parseJson(v) {
|
|
|
4384
4402
|
return v ?? void 0;
|
|
4385
4403
|
}
|
|
4386
4404
|
function rowToTask(row) {
|
|
4405
|
+
const createdAt = row.createdAtZ || row.createdAt;
|
|
4406
|
+
const startedAt = row.startedAtZ || row.startedAt;
|
|
4407
|
+
const suspendedAt = row.suspendedAtZ || row.suspendedAt;
|
|
4408
|
+
const completedAt = row.completedAtZ || row.completedAt;
|
|
4387
4409
|
return {
|
|
4388
4410
|
id: row.id,
|
|
4389
4411
|
status: row.status,
|
|
@@ -4400,10 +4422,10 @@ function rowToTask(row) {
|
|
|
4400
4422
|
retryCount: Number(row.retry_count),
|
|
4401
4423
|
maxRetries: Number(row.max_retries),
|
|
4402
4424
|
timeoutMs: Number(row.timeout_ms),
|
|
4403
|
-
createdAt:
|
|
4404
|
-
startedAt:
|
|
4405
|
-
suspendedAt:
|
|
4406
|
-
completedAt:
|
|
4425
|
+
createdAt: createdAt instanceof Date ? createdAt : new Date(createdAt),
|
|
4426
|
+
startedAt: startedAt ? startedAt instanceof Date ? startedAt : new Date(startedAt) : void 0,
|
|
4427
|
+
suspendedAt: suspendedAt ? suspendedAt instanceof Date ? suspendedAt : new Date(suspendedAt) : void 0,
|
|
4428
|
+
completedAt: completedAt ? completedAt instanceof Date ? completedAt : new Date(completedAt) : void 0
|
|
4407
4429
|
};
|
|
4408
4430
|
}
|
|
4409
4431
|
var BackgroundTasksPG = class _BackgroundTasksPG extends storage.BackgroundTasksStorage {
|
|
@@ -4521,9 +4543,13 @@ var BackgroundTasksPG = class _BackgroundTasksPG extends storage.BackgroundTasks
|
|
|
4521
4543
|
max_retries: task.maxRetries,
|
|
4522
4544
|
timeout_ms: task.timeoutMs,
|
|
4523
4545
|
createdAt: task.createdAt.toISOString(),
|
|
4546
|
+
createdAtZ: task.createdAt.toISOString(),
|
|
4524
4547
|
startedAt: task.startedAt?.toISOString() ?? null,
|
|
4548
|
+
startedAtZ: task.startedAt?.toISOString() ?? null,
|
|
4525
4549
|
suspendedAt: task.suspendedAt?.toISOString() ?? null,
|
|
4526
|
-
|
|
4550
|
+
suspendedAtZ: task.suspendedAt?.toISOString() ?? null,
|
|
4551
|
+
completedAt: task.completedAt?.toISOString() ?? null,
|
|
4552
|
+
completedAtZ: task.completedAt?.toISOString() ?? null
|
|
4527
4553
|
}
|
|
4528
4554
|
});
|
|
4529
4555
|
}
|
|
@@ -4700,6 +4726,16 @@ var BlobsPG = class extends storage.BlobStore {
|
|
|
4700
4726
|
this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
|
|
4701
4727
|
this.#schema = schemaName || "public";
|
|
4702
4728
|
}
|
|
4729
|
+
static getExportDDL(schemaName) {
|
|
4730
|
+
return [
|
|
4731
|
+
generateTableSQL({
|
|
4732
|
+
tableName: storage.TABLE_SKILL_BLOBS,
|
|
4733
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_SKILL_BLOBS],
|
|
4734
|
+
schemaName,
|
|
4735
|
+
includeAllConstraints: true
|
|
4736
|
+
})
|
|
4737
|
+
];
|
|
4738
|
+
}
|
|
4703
4739
|
async init() {
|
|
4704
4740
|
await this.#db.createTable({
|
|
4705
4741
|
tableName: storage.TABLE_SKILL_BLOBS,
|
|
@@ -6778,16 +6814,39 @@ var MCPClientsPG = class _MCPClientsPG extends storage.MCPClientsStorage {
|
|
|
6778
6814
|
this.#skipDefaultIndexes = skipDefaultIndexes;
|
|
6779
6815
|
this.#indexes = indexes?.filter((idx) => _MCPClientsPG.MANAGED_TABLES.includes(idx.table));
|
|
6780
6816
|
}
|
|
6781
|
-
|
|
6817
|
+
static getDefaultIndexDefs(schemaPrefix) {
|
|
6782
6818
|
return [
|
|
6783
6819
|
{
|
|
6784
|
-
name:
|
|
6820
|
+
name: `${schemaPrefix}idx_mcp_client_versions_client_version`,
|
|
6785
6821
|
table: storage.TABLE_MCP_CLIENT_VERSIONS,
|
|
6786
6822
|
columns: ["mcpClientId", "versionNumber"],
|
|
6787
6823
|
unique: true
|
|
6788
6824
|
}
|
|
6789
6825
|
];
|
|
6790
6826
|
}
|
|
6827
|
+
static getExportDDL(schemaName) {
|
|
6828
|
+
const statements = [];
|
|
6829
|
+
const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
|
|
6830
|
+
const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
|
|
6831
|
+
for (const tableName of _MCPClientsPG.MANAGED_TABLES) {
|
|
6832
|
+
statements.push(
|
|
6833
|
+
generateTableSQL({
|
|
6834
|
+
tableName,
|
|
6835
|
+
schema: storage.TABLE_SCHEMAS[tableName],
|
|
6836
|
+
schemaName,
|
|
6837
|
+
includeAllConstraints: true
|
|
6838
|
+
})
|
|
6839
|
+
);
|
|
6840
|
+
}
|
|
6841
|
+
for (const idx of _MCPClientsPG.getDefaultIndexDefs(schemaPrefix)) {
|
|
6842
|
+
statements.push(generateIndexSQL(idx, schemaName));
|
|
6843
|
+
}
|
|
6844
|
+
return statements;
|
|
6845
|
+
}
|
|
6846
|
+
getDefaultIndexDefinitions() {
|
|
6847
|
+
const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
|
|
6848
|
+
return _MCPClientsPG.getDefaultIndexDefs(schemaPrefix);
|
|
6849
|
+
}
|
|
6791
6850
|
async createDefaultIndexes() {
|
|
6792
6851
|
if (this.#skipDefaultIndexes) {
|
|
6793
6852
|
return;
|
|
@@ -7391,16 +7450,39 @@ var MCPServersPG = class _MCPServersPG extends storage.MCPServersStorage {
|
|
|
7391
7450
|
this.#skipDefaultIndexes = skipDefaultIndexes;
|
|
7392
7451
|
this.#indexes = indexes?.filter((idx) => _MCPServersPG.MANAGED_TABLES.includes(idx.table));
|
|
7393
7452
|
}
|
|
7394
|
-
|
|
7453
|
+
static getDefaultIndexDefs(schemaPrefix) {
|
|
7395
7454
|
return [
|
|
7396
7455
|
{
|
|
7397
|
-
name:
|
|
7456
|
+
name: `${schemaPrefix}idx_mcp_server_versions_server_version`,
|
|
7398
7457
|
table: storage.TABLE_MCP_SERVER_VERSIONS,
|
|
7399
7458
|
columns: ["mcpServerId", "versionNumber"],
|
|
7400
7459
|
unique: true
|
|
7401
7460
|
}
|
|
7402
7461
|
];
|
|
7403
7462
|
}
|
|
7463
|
+
static getExportDDL(schemaName) {
|
|
7464
|
+
const statements = [];
|
|
7465
|
+
const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
|
|
7466
|
+
const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
|
|
7467
|
+
for (const tableName of _MCPServersPG.MANAGED_TABLES) {
|
|
7468
|
+
statements.push(
|
|
7469
|
+
generateTableSQL({
|
|
7470
|
+
tableName,
|
|
7471
|
+
schema: storage.TABLE_SCHEMAS[tableName],
|
|
7472
|
+
schemaName,
|
|
7473
|
+
includeAllConstraints: true
|
|
7474
|
+
})
|
|
7475
|
+
);
|
|
7476
|
+
}
|
|
7477
|
+
for (const idx of _MCPServersPG.getDefaultIndexDefs(schemaPrefix)) {
|
|
7478
|
+
statements.push(generateIndexSQL(idx, schemaName));
|
|
7479
|
+
}
|
|
7480
|
+
return statements;
|
|
7481
|
+
}
|
|
7482
|
+
getDefaultIndexDefinitions() {
|
|
7483
|
+
const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
|
|
7484
|
+
return _MCPServersPG.getDefaultIndexDefs(schemaPrefix);
|
|
7485
|
+
}
|
|
7404
7486
|
async createDefaultIndexes() {
|
|
7405
7487
|
if (this.#skipDefaultIndexes) {
|
|
7406
7488
|
return;
|
|
@@ -11463,109 +11545,3348 @@ var ObservabilityPG = class _ObservabilityPG extends storage.ObservabilityStorag
|
|
|
11463
11545
|
}
|
|
11464
11546
|
}
|
|
11465
11547
|
};
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
}
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11548
|
+
|
|
11549
|
+
// src/storage/domains/observability/v-next/signal-schema.ts
|
|
11550
|
+
var CURSOR_ID_COLUMN = { name: "cursorId", type: "bigserial" };
|
|
11551
|
+
var XACT_ID_COLUMN = {
|
|
11552
|
+
name: "xactId",
|
|
11553
|
+
type: "xid8",
|
|
11554
|
+
defaultSql: "pg_current_xact_id()"
|
|
11555
|
+
};
|
|
11556
|
+
var COMMON_CONTEXT_COLUMNS = [
|
|
11557
|
+
{ name: "traceId", type: "text", nullable: true },
|
|
11558
|
+
{ name: "spanId", type: "text", nullable: true },
|
|
11559
|
+
{ name: "experimentId", type: "text", nullable: true },
|
|
11560
|
+
{ name: "entityType", type: "text", nullable: true },
|
|
11561
|
+
{ name: "entityId", type: "text", nullable: true },
|
|
11562
|
+
{ name: "entityName", type: "text", nullable: true },
|
|
11563
|
+
{ name: "entityVersionId", type: "text", nullable: true },
|
|
11564
|
+
{ name: "parentEntityType", type: "text", nullable: true },
|
|
11565
|
+
{ name: "parentEntityId", type: "text", nullable: true },
|
|
11566
|
+
{ name: "parentEntityName", type: "text", nullable: true },
|
|
11567
|
+
{ name: "parentEntityVersionId", type: "text", nullable: true },
|
|
11568
|
+
{ name: "rootEntityType", type: "text", nullable: true },
|
|
11569
|
+
{ name: "rootEntityId", type: "text", nullable: true },
|
|
11570
|
+
{ name: "rootEntityName", type: "text", nullable: true },
|
|
11571
|
+
{ name: "rootEntityVersionId", type: "text", nullable: true },
|
|
11572
|
+
{ name: "userId", type: "text", nullable: true },
|
|
11573
|
+
{ name: "organizationId", type: "text", nullable: true },
|
|
11574
|
+
{ name: "resourceId", type: "text", nullable: true },
|
|
11575
|
+
{ name: "runId", type: "text", nullable: true },
|
|
11576
|
+
{ name: "sessionId", type: "text", nullable: true },
|
|
11577
|
+
{ name: "threadId", type: "text", nullable: true },
|
|
11578
|
+
{ name: "requestId", type: "text", nullable: true },
|
|
11579
|
+
{ name: "environment", type: "text", nullable: true },
|
|
11580
|
+
{ name: "executionSource", type: "text", nullable: true },
|
|
11581
|
+
{ name: "serviceName", type: "text", nullable: true }
|
|
11582
|
+
];
|
|
11583
|
+
var SPAN_EVENT_COLUMNS = [
|
|
11584
|
+
CURSOR_ID_COLUMN,
|
|
11585
|
+
XACT_ID_COLUMN,
|
|
11586
|
+
{ name: "traceId", type: "text" },
|
|
11587
|
+
{ name: "spanId", type: "text" },
|
|
11588
|
+
{ name: "parentSpanId", type: "text", nullable: true },
|
|
11589
|
+
{ name: "experimentId", type: "text", nullable: true },
|
|
11590
|
+
{ name: "entityType", type: "text", nullable: true },
|
|
11591
|
+
{ name: "entityId", type: "text", nullable: true },
|
|
11592
|
+
{ name: "entityName", type: "text", nullable: true },
|
|
11593
|
+
{ name: "entityVersionId", type: "text", nullable: true },
|
|
11594
|
+
{ name: "parentEntityType", type: "text", nullable: true },
|
|
11595
|
+
{ name: "parentEntityId", type: "text", nullable: true },
|
|
11596
|
+
{ name: "parentEntityName", type: "text", nullable: true },
|
|
11597
|
+
{ name: "parentEntityVersionId", type: "text", nullable: true },
|
|
11598
|
+
{ name: "rootEntityType", type: "text", nullable: true },
|
|
11599
|
+
{ name: "rootEntityId", type: "text", nullable: true },
|
|
11600
|
+
{ name: "rootEntityName", type: "text", nullable: true },
|
|
11601
|
+
{ name: "rootEntityVersionId", type: "text", nullable: true },
|
|
11602
|
+
{ name: "userId", type: "text", nullable: true },
|
|
11603
|
+
{ name: "organizationId", type: "text", nullable: true },
|
|
11604
|
+
{ name: "resourceId", type: "text", nullable: true },
|
|
11605
|
+
{ name: "runId", type: "text", nullable: true },
|
|
11606
|
+
{ name: "sessionId", type: "text", nullable: true },
|
|
11607
|
+
{ name: "threadId", type: "text", nullable: true },
|
|
11608
|
+
{ name: "requestId", type: "text", nullable: true },
|
|
11609
|
+
{ name: "environment", type: "text", nullable: true },
|
|
11610
|
+
{ name: "executionSource", type: "text", nullable: true },
|
|
11611
|
+
{ name: "serviceName", type: "text", nullable: true },
|
|
11612
|
+
{ name: "name", type: "text" },
|
|
11613
|
+
{ name: "spanType", type: "text" },
|
|
11614
|
+
{ name: "isEvent", type: "boolean", defaultSql: "false" },
|
|
11615
|
+
{ name: "startedAt", type: "timestamptz" },
|
|
11616
|
+
{ name: "endedAt", type: "timestamptz" },
|
|
11617
|
+
{ name: "tags", type: "text[]", defaultSql: "'{}'" },
|
|
11618
|
+
{ name: "metadataSearch", type: "jsonb", defaultSql: "'{}'::jsonb" },
|
|
11619
|
+
{ name: "attributes", type: "jsonb", nullable: true },
|
|
11620
|
+
{ name: "scope", type: "jsonb", nullable: true },
|
|
11621
|
+
{ name: "links", type: "jsonb", nullable: true },
|
|
11622
|
+
{ name: "input", type: "jsonb", nullable: true },
|
|
11623
|
+
{ name: "output", type: "jsonb", nullable: true },
|
|
11624
|
+
{ name: "error", type: "jsonb", nullable: true },
|
|
11625
|
+
{ name: "metadataRaw", type: "jsonb", nullable: true },
|
|
11626
|
+
{ name: "requestContext", type: "jsonb", nullable: true }
|
|
11627
|
+
];
|
|
11628
|
+
var METRIC_EVENT_COLUMNS = [
|
|
11629
|
+
CURSOR_ID_COLUMN,
|
|
11630
|
+
XACT_ID_COLUMN,
|
|
11631
|
+
{ name: "metricId", type: "text" },
|
|
11632
|
+
{ name: "timestamp", type: "timestamptz" },
|
|
11633
|
+
{ name: "name", type: "text" },
|
|
11634
|
+
{ name: "value", type: "double precision" },
|
|
11635
|
+
...COMMON_CONTEXT_COLUMNS,
|
|
11636
|
+
{ name: "provider", type: "text", nullable: true },
|
|
11637
|
+
{ name: "model", type: "text", nullable: true },
|
|
11638
|
+
{ name: "estimatedCost", type: "double precision", nullable: true },
|
|
11639
|
+
{ name: "costUnit", type: "text", nullable: true },
|
|
11640
|
+
{ name: "tags", type: "text[]", defaultSql: "'{}'" },
|
|
11641
|
+
{ name: "labels", type: "jsonb", defaultSql: "'{}'::jsonb" },
|
|
11642
|
+
{ name: "costMetadata", type: "jsonb", nullable: true },
|
|
11643
|
+
{ name: "metadata", type: "jsonb", nullable: true },
|
|
11644
|
+
{ name: "scope", type: "jsonb", nullable: true }
|
|
11645
|
+
];
|
|
11646
|
+
var LOG_EVENT_COLUMNS = [
|
|
11647
|
+
CURSOR_ID_COLUMN,
|
|
11648
|
+
XACT_ID_COLUMN,
|
|
11649
|
+
{ name: "logId", type: "text" },
|
|
11650
|
+
{ name: "timestamp", type: "timestamptz" },
|
|
11651
|
+
{ name: "level", type: "text" },
|
|
11652
|
+
{ name: "message", type: "text" },
|
|
11653
|
+
...COMMON_CONTEXT_COLUMNS,
|
|
11654
|
+
{ name: "tags", type: "text[]", defaultSql: "'{}'" },
|
|
11655
|
+
{ name: "data", type: "jsonb", nullable: true },
|
|
11656
|
+
{ name: "metadata", type: "jsonb", nullable: true },
|
|
11657
|
+
{ name: "scope", type: "jsonb", nullable: true }
|
|
11658
|
+
];
|
|
11659
|
+
var SCORE_EVENT_COLUMNS = [
|
|
11660
|
+
CURSOR_ID_COLUMN,
|
|
11661
|
+
XACT_ID_COLUMN,
|
|
11662
|
+
{ name: "scoreId", type: "text" },
|
|
11663
|
+
{ name: "timestamp", type: "timestamptz" },
|
|
11664
|
+
{ name: "scorerId", type: "text" },
|
|
11665
|
+
{ name: "scorerVersion", type: "text", nullable: true },
|
|
11666
|
+
{ name: "scoreSource", type: "text", nullable: true },
|
|
11667
|
+
{ name: "score", type: "double precision" },
|
|
11668
|
+
{ name: "reason", type: "text", nullable: true },
|
|
11669
|
+
...COMMON_CONTEXT_COLUMNS,
|
|
11670
|
+
{ name: "scoreTraceId", type: "text", nullable: true },
|
|
11671
|
+
{ name: "tags", type: "text[]", defaultSql: "'{}'" },
|
|
11672
|
+
{ name: "metadata", type: "jsonb", nullable: true },
|
|
11673
|
+
{ name: "scope", type: "jsonb", nullable: true }
|
|
11674
|
+
];
|
|
11675
|
+
var FEEDBACK_EVENT_COLUMNS = [
|
|
11676
|
+
CURSOR_ID_COLUMN,
|
|
11677
|
+
XACT_ID_COLUMN,
|
|
11678
|
+
{ name: "feedbackId", type: "text" },
|
|
11679
|
+
{ name: "timestamp", type: "timestamptz" },
|
|
11680
|
+
{ name: "feedbackSource", type: "text" },
|
|
11681
|
+
{ name: "feedbackType", type: "text" },
|
|
11682
|
+
{ name: "valueString", type: "text", nullable: true },
|
|
11683
|
+
{ name: "valueNumber", type: "double precision", nullable: true },
|
|
11684
|
+
{ name: "comment", type: "text", nullable: true },
|
|
11685
|
+
{ name: "feedbackUserId", type: "text", nullable: true },
|
|
11686
|
+
{ name: "sourceId", type: "text", nullable: true },
|
|
11687
|
+
...COMMON_CONTEXT_COLUMNS,
|
|
11688
|
+
{ name: "tags", type: "text[]", defaultSql: "'{}'" },
|
|
11689
|
+
{ name: "metadata", type: "jsonb", nullable: true },
|
|
11690
|
+
{ name: "scope", type: "jsonb", nullable: true }
|
|
11691
|
+
];
|
|
11692
|
+
var SPAN_LIGHT_SELECT_COLUMN_NAMES = [
|
|
11693
|
+
"cursorId",
|
|
11694
|
+
"xactId",
|
|
11695
|
+
"traceId",
|
|
11696
|
+
"spanId",
|
|
11697
|
+
"parentSpanId",
|
|
11698
|
+
"name",
|
|
11699
|
+
"entityType",
|
|
11700
|
+
"entityId",
|
|
11701
|
+
"entityName",
|
|
11702
|
+
"spanType",
|
|
11703
|
+
"error",
|
|
11704
|
+
"isEvent",
|
|
11705
|
+
"startedAt",
|
|
11706
|
+
"endedAt"
|
|
11707
|
+
];
|
|
11708
|
+
function quotedColumnName(name) {
|
|
11709
|
+
return `"${name}"`;
|
|
11710
|
+
}
|
|
11711
|
+
function columnDefinition(column) {
|
|
11712
|
+
const nullable = column.nullable ? "" : " NOT NULL";
|
|
11713
|
+
const defaultSql = column.defaultSql ? ` DEFAULT ${column.defaultSql}` : "";
|
|
11714
|
+
return ` ${quotedColumnName(column.name)} ${column.type}${nullable}${defaultSql}`;
|
|
11715
|
+
}
|
|
11716
|
+
function buildColumnDefinitions(columns) {
|
|
11717
|
+
return columns.map(columnDefinition).join(",\n");
|
|
11718
|
+
}
|
|
11719
|
+
function buildSelectColumns(columns) {
|
|
11720
|
+
return `
|
|
11721
|
+
${columns.map((column) => quotedColumnName(column.name)).join(",\n ")}
|
|
11722
|
+
`;
|
|
11723
|
+
}
|
|
11724
|
+
function buildNamedSelectColumns(columnNames) {
|
|
11725
|
+
return `
|
|
11726
|
+
${columnNames.map(quotedColumnName).join(",\n ")}
|
|
11727
|
+
`;
|
|
11728
|
+
}
|
|
11729
|
+
function columnNamesByType(columns, type) {
|
|
11730
|
+
return columns.filter((column) => column.type === type).map((column) => column.name);
|
|
11731
|
+
}
|
|
11732
|
+
function typedColumnNames(columns) {
|
|
11733
|
+
return new Set(
|
|
11734
|
+
columns.filter((column) => !["bigserial", "jsonb", "text[]", "xid8"].includes(column.type)).map((column) => column.name)
|
|
11735
|
+
);
|
|
11736
|
+
}
|
|
11737
|
+
var ALL_EVENT_COLUMNS = [
|
|
11738
|
+
...SPAN_EVENT_COLUMNS,
|
|
11739
|
+
...METRIC_EVENT_COLUMNS,
|
|
11740
|
+
...LOG_EVENT_COLUMNS,
|
|
11741
|
+
...SCORE_EVENT_COLUMNS,
|
|
11742
|
+
...FEEDBACK_EVENT_COLUMNS
|
|
11743
|
+
];
|
|
11744
|
+
var JSONB_COLUMNS = new Set(columnNamesByType(ALL_EVENT_COLUMNS, "jsonb"));
|
|
11745
|
+
var TEXT_ARRAY_COLUMNS = new Set(columnNamesByType(ALL_EVENT_COLUMNS, "text[]"));
|
|
11746
|
+
var METRIC_TYPED_COLUMNS = typedColumnNames(METRIC_EVENT_COLUMNS);
|
|
11747
|
+
var SCORE_TYPED_COLUMNS = typedColumnNames(SCORE_EVENT_COLUMNS);
|
|
11748
|
+
var FEEDBACK_TYPED_COLUMNS = typedColumnNames(FEEDBACK_EVENT_COLUMNS);
|
|
11749
|
+
|
|
11750
|
+
// src/storage/domains/observability/v-next/ddl.ts
|
|
11751
|
+
var TABLE_SPAN_EVENTS = "mastra_span_events";
|
|
11752
|
+
var TABLE_METRIC_EVENTS = "mastra_metric_events";
|
|
11753
|
+
var TABLE_LOG_EVENTS = "mastra_log_events";
|
|
11754
|
+
var TABLE_SCORE_EVENTS = "mastra_score_events";
|
|
11755
|
+
var TABLE_FEEDBACK_EVENTS = "mastra_feedback_events";
|
|
11756
|
+
var TABLE_DISCOVERY = "mastra_observability_discovery";
|
|
11757
|
+
var ALL_SIGNAL_TABLES = [
|
|
11758
|
+
TABLE_SPAN_EVENTS,
|
|
11759
|
+
TABLE_METRIC_EVENTS,
|
|
11760
|
+
TABLE_LOG_EVENTS,
|
|
11761
|
+
TABLE_SCORE_EVENTS,
|
|
11762
|
+
TABLE_FEEDBACK_EVENTS
|
|
11763
|
+
];
|
|
11764
|
+
var SIGNAL_TIME_COLUMN = {
|
|
11765
|
+
[TABLE_SPAN_EVENTS]: "endedAt",
|
|
11766
|
+
[TABLE_METRIC_EVENTS]: "timestamp",
|
|
11767
|
+
[TABLE_LOG_EVENTS]: "timestamp",
|
|
11768
|
+
[TABLE_SCORE_EVENTS]: "timestamp",
|
|
11769
|
+
[TABLE_FEEDBACK_EVENTS]: "timestamp"
|
|
11770
|
+
};
|
|
11771
|
+
function qualifiedTable(schema, table) {
|
|
11772
|
+
const s = utils.parseSqlIdentifier(schema, "schema name");
|
|
11773
|
+
const t = utils.parseSqlIdentifier(table, "table name");
|
|
11774
|
+
return `"${s}"."${t}"`;
|
|
11775
|
+
}
|
|
11776
|
+
function qualifiedName(schema, name) {
|
|
11777
|
+
const s = utils.parseSqlIdentifier(schema, "schema name");
|
|
11778
|
+
const n = utils.parseSqlIdentifier(name, "object name");
|
|
11779
|
+
return `"${s}"."${n}"`;
|
|
11780
|
+
}
|
|
11781
|
+
function schemaDDL(schema) {
|
|
11782
|
+
const s = utils.parseSqlIdentifier(schema, "schema name");
|
|
11783
|
+
return `CREATE SCHEMA IF NOT EXISTS "${s}"`;
|
|
11784
|
+
}
|
|
11785
|
+
function partitionClause(mode, column) {
|
|
11786
|
+
return mode === "timescale" ? "" : `PARTITION BY RANGE ("${column}")`;
|
|
11787
|
+
}
|
|
11788
|
+
function spanEventsTableDDL(schema, mode) {
|
|
11789
|
+
return `
|
|
11790
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} (
|
|
11791
|
+
${buildColumnDefinitions(SPAN_EVENT_COLUMNS)},
|
|
11792
|
+
PRIMARY KEY ("traceId", "spanId", "endedAt")
|
|
11793
|
+
)
|
|
11794
|
+
${partitionClause(mode, "endedAt")}
|
|
11795
|
+
`.trim();
|
|
11796
|
+
}
|
|
11797
|
+
function metricEventsTableDDL(schema, mode) {
|
|
11798
|
+
return `
|
|
11799
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_METRIC_EVENTS)} (
|
|
11800
|
+
${buildColumnDefinitions(METRIC_EVENT_COLUMNS)},
|
|
11801
|
+
PRIMARY KEY ("metricId", "timestamp")
|
|
11802
|
+
)
|
|
11803
|
+
${partitionClause(mode, "timestamp")}
|
|
11804
|
+
`.trim();
|
|
11805
|
+
}
|
|
11806
|
+
function logEventsTableDDL(schema, mode) {
|
|
11807
|
+
return `
|
|
11808
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_LOG_EVENTS)} (
|
|
11809
|
+
${buildColumnDefinitions(LOG_EVENT_COLUMNS)},
|
|
11810
|
+
PRIMARY KEY ("logId", "timestamp")
|
|
11811
|
+
)
|
|
11812
|
+
${partitionClause(mode, "timestamp")}
|
|
11813
|
+
`.trim();
|
|
11814
|
+
}
|
|
11815
|
+
function scoreEventsTableDDL(schema, mode) {
|
|
11816
|
+
return `
|
|
11817
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_SCORE_EVENTS)} (
|
|
11818
|
+
${buildColumnDefinitions(SCORE_EVENT_COLUMNS)},
|
|
11819
|
+
PRIMARY KEY ("scoreId", "timestamp")
|
|
11820
|
+
)
|
|
11821
|
+
${partitionClause(mode, "timestamp")}
|
|
11822
|
+
`.trim();
|
|
11823
|
+
}
|
|
11824
|
+
function feedbackEventsTableDDL(schema, mode) {
|
|
11825
|
+
return `
|
|
11826
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)} (
|
|
11827
|
+
${buildColumnDefinitions(FEEDBACK_EVENT_COLUMNS)},
|
|
11828
|
+
PRIMARY KEY ("feedbackId", "timestamp")
|
|
11829
|
+
)
|
|
11830
|
+
${partitionClause(mode, "timestamp")}
|
|
11831
|
+
`.trim();
|
|
11832
|
+
}
|
|
11833
|
+
function discoveryTableDDL(schema) {
|
|
11834
|
+
return `
|
|
11835
|
+
CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_DISCOVERY)} (
|
|
11836
|
+
"cacheKey" text PRIMARY KEY,
|
|
11837
|
+
"refreshedAt" timestamptz NOT NULL,
|
|
11838
|
+
"values" jsonb NOT NULL DEFAULT '[]'::jsonb
|
|
11839
|
+
)
|
|
11840
|
+
`.trim();
|
|
11841
|
+
}
|
|
11842
|
+
var ROOT_SPAN_WHERE = '"parentSpanId" IS NULL';
|
|
11843
|
+
function tableIndexes() {
|
|
11844
|
+
return [
|
|
11845
|
+
// span_events — full-table indexes used by getTrace / getSpan
|
|
11846
|
+
{ name: "mastra_span_events_traceid_idx", table: TABLE_SPAN_EVENTS, columns: '("traceId", "endedAt" DESC)' },
|
|
11847
|
+
{
|
|
11848
|
+
name: "mastra_span_events_parentspan_idx",
|
|
11849
|
+
table: TABLE_SPAN_EVENTS,
|
|
11850
|
+
columns: '("parentSpanId", "endedAt" DESC)'
|
|
11851
|
+
},
|
|
11852
|
+
{ name: "mastra_span_events_name_idx", table: TABLE_SPAN_EVENTS, columns: '("name")' },
|
|
11853
|
+
// Used by listBranches page mode (filter by spanType, order by startedAt).
|
|
11854
|
+
{ name: "mastra_span_events_spantype_idx", table: TABLE_SPAN_EVENTS, columns: '("spanType", "startedAt" DESC)' },
|
|
11855
|
+
{ name: "mastra_span_events_entity_idx", table: TABLE_SPAN_EVENTS, columns: '("entityType", "entityId")' },
|
|
11856
|
+
{
|
|
11857
|
+
name: "mastra_span_events_orgid_userid_idx",
|
|
11858
|
+
table: TABLE_SPAN_EVENTS,
|
|
11859
|
+
columns: '("organizationId", "userId")'
|
|
11860
|
+
},
|
|
11861
|
+
{
|
|
11862
|
+
name: "mastra_span_events_metadatasearch_gin",
|
|
11863
|
+
table: TABLE_SPAN_EVENTS,
|
|
11864
|
+
columns: '("metadataSearch" jsonb_path_ops)',
|
|
11865
|
+
using: "gin"
|
|
11866
|
+
},
|
|
11867
|
+
{ name: "mastra_span_events_tags_gin", table: TABLE_SPAN_EVENTS, columns: '("tags")', using: "gin" },
|
|
11868
|
+
// span_events — partial indexes acting as the root-span projection. The
|
|
11869
|
+
// listTraces filter surface (startedAt / spanType / entityType / etc.) is
|
|
11870
|
+
// covered by these; rows where parentSpanId IS NOT NULL are excluded from
|
|
11871
|
+
// the index, so the index is the size of a separate trace_roots table.
|
|
11872
|
+
{
|
|
11873
|
+
name: "mastra_span_events_root_startedat_idx",
|
|
11874
|
+
table: TABLE_SPAN_EVENTS,
|
|
11875
|
+
columns: '("startedAt" DESC)',
|
|
11876
|
+
where: ROOT_SPAN_WHERE
|
|
11877
|
+
},
|
|
11878
|
+
{
|
|
11879
|
+
name: "mastra_span_events_root_endedat_idx",
|
|
11880
|
+
table: TABLE_SPAN_EVENTS,
|
|
11881
|
+
columns: '("endedAt" DESC)',
|
|
11882
|
+
where: ROOT_SPAN_WHERE
|
|
11883
|
+
},
|
|
11884
|
+
{
|
|
11885
|
+
name: "mastra_span_events_root_spantype_idx",
|
|
11886
|
+
table: TABLE_SPAN_EVENTS,
|
|
11887
|
+
columns: '("spanType", "startedAt" DESC)',
|
|
11888
|
+
where: ROOT_SPAN_WHERE
|
|
11889
|
+
},
|
|
11890
|
+
{
|
|
11891
|
+
name: "mastra_span_events_root_entityname_idx",
|
|
11892
|
+
table: TABLE_SPAN_EVENTS,
|
|
11893
|
+
columns: '("entityType", "entityName", "startedAt" DESC)',
|
|
11894
|
+
where: ROOT_SPAN_WHERE
|
|
11895
|
+
},
|
|
11896
|
+
{
|
|
11897
|
+
name: "mastra_span_events_root_traceid_idx",
|
|
11898
|
+
table: TABLE_SPAN_EVENTS,
|
|
11899
|
+
columns: '("traceId")',
|
|
11900
|
+
where: ROOT_SPAN_WHERE
|
|
11901
|
+
},
|
|
11902
|
+
// Delta polling: transaction-safe cursor ordering. Full-table coverage so the same index
|
|
11903
|
+
// serves both listTraces (combined with the `parentSpanId IS NULL`
|
|
11904
|
+
// predicate) and listBranches (combined with `spanType IN (...)`).
|
|
11905
|
+
{
|
|
11906
|
+
name: "mastra_span_events_cursor_idx",
|
|
11907
|
+
table: TABLE_SPAN_EVENTS,
|
|
11908
|
+
columns: '("xactId", "cursorId")'
|
|
11909
|
+
},
|
|
11910
|
+
// metric_events
|
|
11911
|
+
{ name: "mastra_metric_events_name_ts_idx", table: TABLE_METRIC_EVENTS, columns: '("name", "timestamp" DESC)' },
|
|
11912
|
+
{
|
|
11913
|
+
name: "mastra_metric_events_entity_idx",
|
|
11914
|
+
table: TABLE_METRIC_EVENTS,
|
|
11915
|
+
columns: '("entityType", "entityId", "timestamp" DESC)'
|
|
11916
|
+
},
|
|
11917
|
+
{ name: "mastra_metric_events_traceid_idx", table: TABLE_METRIC_EVENTS, columns: '("traceId")' },
|
|
11918
|
+
{ name: "mastra_metric_events_labels_gin", table: TABLE_METRIC_EVENTS, columns: '("labels")', using: "gin" },
|
|
11919
|
+
{ name: "mastra_metric_events_tags_gin", table: TABLE_METRIC_EVENTS, columns: '("tags")', using: "gin" },
|
|
11920
|
+
{ name: "mastra_metric_events_cursor_idx", table: TABLE_METRIC_EVENTS, columns: '("xactId", "cursorId")' },
|
|
11921
|
+
// log_events
|
|
11922
|
+
{ name: "mastra_log_events_ts_idx", table: TABLE_LOG_EVENTS, columns: '("timestamp" DESC)' },
|
|
11923
|
+
{ name: "mastra_log_events_level_ts_idx", table: TABLE_LOG_EVENTS, columns: '("level", "timestamp" DESC)' },
|
|
11924
|
+
{ name: "mastra_log_events_traceid_idx", table: TABLE_LOG_EVENTS, columns: '("traceId")' },
|
|
11925
|
+
{
|
|
11926
|
+
name: "mastra_log_events_entity_idx",
|
|
11927
|
+
table: TABLE_LOG_EVENTS,
|
|
11928
|
+
columns: '("entityType", "entityId", "timestamp" DESC)'
|
|
11929
|
+
},
|
|
11930
|
+
{ name: "mastra_log_events_tags_gin", table: TABLE_LOG_EVENTS, columns: '("tags")', using: "gin" },
|
|
11931
|
+
{ name: "mastra_log_events_cursor_idx", table: TABLE_LOG_EVENTS, columns: '("xactId", "cursorId")' },
|
|
11932
|
+
// score_events
|
|
11933
|
+
{ name: "mastra_score_events_traceid_idx", table: TABLE_SCORE_EVENTS, columns: '("traceId", "timestamp" DESC)' },
|
|
11934
|
+
{ name: "mastra_score_events_scorerid_idx", table: TABLE_SCORE_EVENTS, columns: '("scorerId", "timestamp" DESC)' },
|
|
11935
|
+
{
|
|
11936
|
+
name: "mastra_score_events_entity_idx",
|
|
11937
|
+
table: TABLE_SCORE_EVENTS,
|
|
11938
|
+
columns: '("entityType", "entityId", "timestamp" DESC)'
|
|
11939
|
+
},
|
|
11940
|
+
{ name: "mastra_score_events_tags_gin", table: TABLE_SCORE_EVENTS, columns: '("tags")', using: "gin" },
|
|
11941
|
+
{ name: "mastra_score_events_cursor_idx", table: TABLE_SCORE_EVENTS, columns: '("xactId", "cursorId")' },
|
|
11942
|
+
// feedback_events
|
|
11943
|
+
{
|
|
11944
|
+
name: "mastra_feedback_events_traceid_idx",
|
|
11945
|
+
table: TABLE_FEEDBACK_EVENTS,
|
|
11946
|
+
columns: '("traceId", "timestamp" DESC)'
|
|
11947
|
+
},
|
|
11948
|
+
{
|
|
11949
|
+
name: "mastra_feedback_events_type_idx",
|
|
11950
|
+
table: TABLE_FEEDBACK_EVENTS,
|
|
11951
|
+
columns: '("feedbackType", "timestamp" DESC)'
|
|
11952
|
+
},
|
|
11953
|
+
{
|
|
11954
|
+
name: "mastra_feedback_events_entity_idx",
|
|
11955
|
+
table: TABLE_FEEDBACK_EVENTS,
|
|
11956
|
+
columns: '("entityType", "entityId", "timestamp" DESC)'
|
|
11957
|
+
},
|
|
11958
|
+
{ name: "mastra_feedback_events_tags_gin", table: TABLE_FEEDBACK_EVENTS, columns: '("tags")', using: "gin" },
|
|
11959
|
+
{ name: "mastra_feedback_events_cursor_idx", table: TABLE_FEEDBACK_EVENTS, columns: '("xactId", "cursorId")' }
|
|
11960
|
+
];
|
|
11961
|
+
}
|
|
11962
|
+
function indexDDL(schema, spec) {
|
|
11963
|
+
const idxName = utils.parseSqlIdentifier(spec.name, "index name");
|
|
11964
|
+
const using = spec.using ? `USING ${spec.using}` : "";
|
|
11965
|
+
const where = spec.where ? `WHERE ${spec.where}` : "";
|
|
11966
|
+
return `CREATE INDEX IF NOT EXISTS "${idxName}" ON ${qualifiedTable(schema, spec.table)} ${using} ${spec.columns} ${where}`.replace(
|
|
11967
|
+
/\s+/g,
|
|
11968
|
+
" "
|
|
11969
|
+
);
|
|
11970
|
+
}
|
|
11971
|
+
function allTableDDL(schema, mode) {
|
|
11972
|
+
return [
|
|
11973
|
+
spanEventsTableDDL(schema, mode),
|
|
11974
|
+
metricEventsTableDDL(schema, mode),
|
|
11975
|
+
logEventsTableDDL(schema, mode),
|
|
11976
|
+
scoreEventsTableDDL(schema, mode),
|
|
11977
|
+
feedbackEventsTableDDL(schema, mode),
|
|
11978
|
+
discoveryTableDDL(schema)
|
|
11979
|
+
];
|
|
11980
|
+
}
|
|
11981
|
+
function allIndexDDL(schema) {
|
|
11982
|
+
return tableIndexes().map((spec) => indexDDL(schema, spec));
|
|
11983
|
+
}
|
|
11984
|
+
var DEFAULT_TTL_SECONDS = 5 * 60;
|
|
11985
|
+
var SIGNAL_TABLES_WITH_CONTEXT = [
|
|
11986
|
+
TABLE_SPAN_EVENTS,
|
|
11987
|
+
TABLE_METRIC_EVENTS,
|
|
11988
|
+
TABLE_LOG_EVENTS,
|
|
11989
|
+
TABLE_SCORE_EVENTS,
|
|
11990
|
+
TABLE_FEEDBACK_EVENTS
|
|
11991
|
+
];
|
|
11992
|
+
var ENTITY_DISCOVERY_TABLES = [TABLE_SPAN_EVENTS, TABLE_METRIC_EVENTS, TABLE_LOG_EVENTS];
|
|
11993
|
+
var inFlightRefreshes = /* @__PURE__ */ new Map();
|
|
11994
|
+
function startOrJoinRefresh(dedupeKey, cacheKey, refresh, upsert, logger) {
|
|
11995
|
+
const existing = inFlightRefreshes.get(dedupeKey);
|
|
11996
|
+
if (existing) return existing;
|
|
11997
|
+
const promise = (async () => {
|
|
11998
|
+
try {
|
|
11999
|
+
const values = await refresh();
|
|
12000
|
+
await upsert(values);
|
|
12001
|
+
return values;
|
|
12002
|
+
} catch (error) {
|
|
12003
|
+
const message = `[observability/v-next] background refresh failed for discovery cache key "${cacheKey}"`;
|
|
12004
|
+
if (logger) {
|
|
12005
|
+
logger.warn(message, { error });
|
|
12006
|
+
} else {
|
|
12007
|
+
console.warn(message + ":", error);
|
|
11492
12008
|
}
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
|
|
11496
|
-
* Returns all DDL statements for this domain: tables and indexes.
|
|
11497
|
-
* Used by exportSchemas to produce a complete, reproducible schema export.
|
|
11498
|
-
*/
|
|
11499
|
-
static getExportDDL(schemaName) {
|
|
11500
|
-
const statements = [];
|
|
11501
|
-
const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
|
|
11502
|
-
const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
|
|
11503
|
-
for (const tableName of _PromptBlocksPG.MANAGED_TABLES) {
|
|
11504
|
-
statements.push(
|
|
11505
|
-
generateTableSQL({
|
|
11506
|
-
tableName,
|
|
11507
|
-
schema: storage.TABLE_SCHEMAS[tableName],
|
|
11508
|
-
schemaName,
|
|
11509
|
-
includeAllConstraints: true
|
|
11510
|
-
})
|
|
11511
|
-
);
|
|
12009
|
+
throw error;
|
|
12010
|
+
} finally {
|
|
12011
|
+
inFlightRefreshes.delete(dedupeKey);
|
|
11512
12012
|
}
|
|
11513
|
-
|
|
11514
|
-
|
|
12013
|
+
})();
|
|
12014
|
+
inFlightRefreshes.set(dedupeKey, promise);
|
|
12015
|
+
return promise;
|
|
12016
|
+
}
|
|
12017
|
+
async function readWithRefresh(client, schema, cacheKey, refresh, ttlSeconds, logger) {
|
|
12018
|
+
const table = qualifiedTable(schema, TABLE_DISCOVERY);
|
|
12019
|
+
const row = await client.oneOrNone(
|
|
12020
|
+
`SELECT "values", "refreshedAt" FROM ${table} WHERE "cacheKey" = $1`,
|
|
12021
|
+
[cacheKey]
|
|
12022
|
+
);
|
|
12023
|
+
const refreshedAtMs = row ? new Date(row.refreshedAt).getTime() : 0;
|
|
12024
|
+
const stale = !row || Date.now() - refreshedAtMs > ttlSeconds * 1e3;
|
|
12025
|
+
if (!stale) return row.values;
|
|
12026
|
+
const dedupeKey = `${schema}:${cacheKey}`;
|
|
12027
|
+
const refreshing = startOrJoinRefresh(
|
|
12028
|
+
dedupeKey,
|
|
12029
|
+
cacheKey,
|
|
12030
|
+
refresh,
|
|
12031
|
+
(values) => upsertCache(client, schema, cacheKey, values),
|
|
12032
|
+
logger
|
|
12033
|
+
);
|
|
12034
|
+
if (ttlSeconds <= 0) {
|
|
12035
|
+
try {
|
|
12036
|
+
return await refreshing;
|
|
12037
|
+
} catch {
|
|
12038
|
+
return row?.values ?? [];
|
|
11515
12039
|
}
|
|
11516
|
-
return statements;
|
|
11517
|
-
}
|
|
11518
|
-
getDefaultIndexDefinitions() {
|
|
11519
|
-
const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
|
|
11520
|
-
return _PromptBlocksPG.getDefaultIndexDefs(schemaPrefix);
|
|
11521
12040
|
}
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
return;
|
|
11525
|
-
}
|
|
11526
|
-
|
|
11527
|
-
try {
|
|
11528
|
-
await this.#db.createIndex(indexDef);
|
|
11529
|
-
} catch {
|
|
11530
|
-
}
|
|
12041
|
+
if (!row) {
|
|
12042
|
+
try {
|
|
12043
|
+
return await refreshing;
|
|
12044
|
+
} catch {
|
|
12045
|
+
return [];
|
|
11531
12046
|
}
|
|
11532
12047
|
}
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
11538
|
-
|
|
11539
|
-
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11543
|
-
|
|
11544
|
-
|
|
11545
|
-
|
|
12048
|
+
refreshing.catch(() => {
|
|
12049
|
+
});
|
|
12050
|
+
return row.values;
|
|
12051
|
+
}
|
|
12052
|
+
async function upsertCache(client, schema, cacheKey, values) {
|
|
12053
|
+
const table = qualifiedTable(schema, TABLE_DISCOVERY);
|
|
12054
|
+
await client.query(
|
|
12055
|
+
`INSERT INTO ${table} ("cacheKey", "refreshedAt", "values")
|
|
12056
|
+
VALUES ($1, NOW(), $2::jsonb)
|
|
12057
|
+
ON CONFLICT ("cacheKey") DO UPDATE SET
|
|
12058
|
+
"refreshedAt" = EXCLUDED."refreshedAt",
|
|
12059
|
+
"values" = EXCLUDED."values"`,
|
|
12060
|
+
[cacheKey, JSON.stringify(values)]
|
|
12061
|
+
);
|
|
12062
|
+
}
|
|
12063
|
+
async function distinctAcrossTables(client, schema, column, tables, filterSql = "", filterParams = []) {
|
|
12064
|
+
const safeColumn = utils.parseSqlIdentifier(column, "column name");
|
|
12065
|
+
const unions = tables.map(
|
|
12066
|
+
(t) => `SELECT DISTINCT "${safeColumn}" AS v FROM ${qualifiedTable(schema, t)} WHERE "${safeColumn}" IS NOT NULL AND "${safeColumn}" <> '' ${filterSql}`
|
|
12067
|
+
).join(" UNION ");
|
|
12068
|
+
const rows = await client.manyOrNone(`SELECT v FROM (${unions}) sub ORDER BY v`, filterParams);
|
|
12069
|
+
return rows.map((r) => r.v);
|
|
12070
|
+
}
|
|
12071
|
+
async function getEntityTypes(client, schema, _args, config) {
|
|
12072
|
+
const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
12073
|
+
const values = await readWithRefresh(
|
|
12074
|
+
client,
|
|
12075
|
+
schema,
|
|
12076
|
+
"entity_types",
|
|
12077
|
+
() => distinctAcrossTables(client, schema, "entityType", ENTITY_DISCOVERY_TABLES),
|
|
12078
|
+
ttl,
|
|
12079
|
+
config.logger
|
|
12080
|
+
);
|
|
12081
|
+
return { entityTypes: values };
|
|
12082
|
+
}
|
|
12083
|
+
async function getEntityNames(client, schema, args, config) {
|
|
12084
|
+
const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
12085
|
+
const cacheKey = args.entityType ? `entity_names:${args.entityType}` : "entity_names";
|
|
12086
|
+
const filterSql = args.entityType ? `AND "entityType" = $1` : "";
|
|
12087
|
+
const filterParams = args.entityType ? [args.entityType] : [];
|
|
12088
|
+
const values = await readWithRefresh(
|
|
12089
|
+
client,
|
|
12090
|
+
schema,
|
|
12091
|
+
cacheKey,
|
|
12092
|
+
() => distinctAcrossTables(client, schema, "entityName", ENTITY_DISCOVERY_TABLES, filterSql, filterParams),
|
|
12093
|
+
ttl,
|
|
12094
|
+
config.logger
|
|
12095
|
+
);
|
|
12096
|
+
return { names: values };
|
|
12097
|
+
}
|
|
12098
|
+
async function getServiceNames(client, schema, _args, config) {
|
|
12099
|
+
const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
12100
|
+
const values = await readWithRefresh(
|
|
12101
|
+
client,
|
|
12102
|
+
schema,
|
|
12103
|
+
"service_names",
|
|
12104
|
+
() => distinctAcrossTables(client, schema, "serviceName", SIGNAL_TABLES_WITH_CONTEXT),
|
|
12105
|
+
ttl,
|
|
12106
|
+
config.logger
|
|
12107
|
+
);
|
|
12108
|
+
return { serviceNames: values };
|
|
12109
|
+
}
|
|
12110
|
+
async function getEnvironments(client, schema, _args, config) {
|
|
12111
|
+
const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
12112
|
+
const values = await readWithRefresh(
|
|
12113
|
+
client,
|
|
12114
|
+
schema,
|
|
12115
|
+
"environments",
|
|
12116
|
+
() => distinctAcrossTables(client, schema, "environment", SIGNAL_TABLES_WITH_CONTEXT),
|
|
12117
|
+
ttl,
|
|
12118
|
+
config.logger
|
|
12119
|
+
);
|
|
12120
|
+
return { environments: values };
|
|
12121
|
+
}
|
|
12122
|
+
async function getTags(client, schema, args, config) {
|
|
12123
|
+
const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
12124
|
+
const cacheKey = args.entityType ? `tags:${args.entityType}` : "tags";
|
|
12125
|
+
const refresh = async () => {
|
|
12126
|
+
const filter = args.entityType ? `AND "entityType" = $1` : "";
|
|
12127
|
+
const params = args.entityType ? [args.entityType] : [];
|
|
12128
|
+
const unions = ENTITY_DISCOVERY_TABLES.map(
|
|
12129
|
+
(t) => `SELECT DISTINCT UNNEST("tags") AS v FROM ${qualifiedTable(schema, t)} WHERE array_length("tags", 1) > 0 ${filter}`
|
|
12130
|
+
).join(" UNION ");
|
|
12131
|
+
const rows = await client.manyOrNone(
|
|
12132
|
+
`SELECT v FROM (${unions}) sub WHERE v IS NOT NULL AND v <> '' ORDER BY v`,
|
|
12133
|
+
params
|
|
12134
|
+
);
|
|
12135
|
+
return rows.map((r) => r.v);
|
|
12136
|
+
};
|
|
12137
|
+
const values = await readWithRefresh(client, schema, cacheKey, refresh, ttl, config.logger);
|
|
12138
|
+
return { tags: values };
|
|
12139
|
+
}
|
|
12140
|
+
async function getMetricNames(client, schema, args, config) {
|
|
12141
|
+
const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
12142
|
+
const values = await readWithRefresh(
|
|
12143
|
+
client,
|
|
12144
|
+
schema,
|
|
12145
|
+
"metric_names",
|
|
12146
|
+
async () => {
|
|
12147
|
+
const rows = await client.manyOrNone(
|
|
12148
|
+
`SELECT DISTINCT "name" AS v FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
|
|
12149
|
+
WHERE "name" IS NOT NULL AND "name" <> '' ORDER BY "name"`
|
|
12150
|
+
);
|
|
12151
|
+
return rows.map((r) => r.v);
|
|
12152
|
+
},
|
|
12153
|
+
ttl,
|
|
12154
|
+
config.logger
|
|
12155
|
+
);
|
|
12156
|
+
let filtered = values;
|
|
12157
|
+
if (args.prefix) filtered = filtered.filter((v) => v.startsWith(args.prefix));
|
|
12158
|
+
if (args.limit) filtered = filtered.slice(0, args.limit);
|
|
12159
|
+
return { names: filtered };
|
|
12160
|
+
}
|
|
12161
|
+
async function getMetricLabelKeys(client, schema, args, config) {
|
|
12162
|
+
const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
12163
|
+
const cacheKey = `metric_label_keys:${args.metricName}`;
|
|
12164
|
+
const values = await readWithRefresh(
|
|
12165
|
+
client,
|
|
12166
|
+
schema,
|
|
12167
|
+
cacheKey,
|
|
12168
|
+
async () => {
|
|
12169
|
+
const rows = await client.manyOrNone(
|
|
12170
|
+
`SELECT DISTINCT k AS v
|
|
12171
|
+
FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}, jsonb_object_keys("labels") k
|
|
12172
|
+
WHERE "name" = $1 ORDER BY k`,
|
|
12173
|
+
[args.metricName]
|
|
12174
|
+
);
|
|
12175
|
+
return rows.map((r) => r.v);
|
|
12176
|
+
},
|
|
12177
|
+
ttl,
|
|
12178
|
+
config.logger
|
|
12179
|
+
);
|
|
12180
|
+
return { keys: values };
|
|
12181
|
+
}
|
|
12182
|
+
async function getMetricLabelValues(client, schema, args, config) {
|
|
12183
|
+
const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
12184
|
+
const cacheKey = `metric_label_values:${args.metricName}:${args.labelKey}`;
|
|
12185
|
+
const values = await readWithRefresh(
|
|
12186
|
+
client,
|
|
12187
|
+
schema,
|
|
12188
|
+
cacheKey,
|
|
12189
|
+
async () => {
|
|
12190
|
+
const rows = await client.manyOrNone(
|
|
12191
|
+
`SELECT DISTINCT "labels" ->> $2 AS v
|
|
12192
|
+
FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
|
|
12193
|
+
WHERE "name" = $1 AND "labels" ? $2
|
|
12194
|
+
ORDER BY v`,
|
|
12195
|
+
[args.metricName, args.labelKey]
|
|
12196
|
+
);
|
|
12197
|
+
return rows.map((r) => r.v).filter((v) => v != null && v !== "");
|
|
12198
|
+
},
|
|
12199
|
+
ttl,
|
|
12200
|
+
config.logger
|
|
12201
|
+
);
|
|
12202
|
+
let filtered = values;
|
|
12203
|
+
if (args.prefix) filtered = filtered.filter((v) => v.startsWith(args.prefix));
|
|
12204
|
+
if (args.limit) filtered = filtered.slice(0, args.limit);
|
|
12205
|
+
return { values: filtered };
|
|
12206
|
+
}
|
|
12207
|
+
|
|
12208
|
+
// src/storage/domains/observability/v-next/filters.ts
|
|
12209
|
+
function newFilterAccumulator(startIndex = 1) {
|
|
12210
|
+
return { conditions: [], params: [], next: startIndex };
|
|
12211
|
+
}
|
|
12212
|
+
function pushEq(acc, column, value, prefix = "") {
|
|
12213
|
+
if (value === void 0) return;
|
|
12214
|
+
acc.conditions.push(`${prefix}"${column}" = $${acc.next++}`);
|
|
12215
|
+
acc.params.push(value);
|
|
12216
|
+
}
|
|
12217
|
+
function pushIn(acc, column, values, prefix = "") {
|
|
12218
|
+
if (!values.length) return;
|
|
12219
|
+
const placeholders = values.map(() => `$${acc.next++}`).join(", ");
|
|
12220
|
+
acc.conditions.push(`${prefix}"${column}" IN (${placeholders})`);
|
|
12221
|
+
acc.params.push(...values);
|
|
12222
|
+
}
|
|
12223
|
+
function applyCommonFilters(acc, filters, options = {}) {
|
|
12224
|
+
if (!filters) return;
|
|
12225
|
+
const tsCol = options.timestampColumn ?? "timestamp";
|
|
12226
|
+
const prefix = options.prefix ?? "";
|
|
12227
|
+
if (filters.timestamp?.start) {
|
|
12228
|
+
const op = filters.timestamp.startExclusive ? ">" : ">=";
|
|
12229
|
+
acc.conditions.push(`${prefix}"${tsCol}" ${op} $${acc.next++}`);
|
|
12230
|
+
acc.params.push(filters.timestamp.start.toISOString());
|
|
12231
|
+
}
|
|
12232
|
+
if (filters.timestamp?.end) {
|
|
12233
|
+
const op = filters.timestamp.endExclusive ? "<" : "<=";
|
|
12234
|
+
acc.conditions.push(`${prefix}"${tsCol}" ${op} $${acc.next++}`);
|
|
12235
|
+
acc.params.push(filters.timestamp.end.toISOString());
|
|
12236
|
+
}
|
|
12237
|
+
pushEq(acc, "traceId", filters.traceId, prefix);
|
|
12238
|
+
pushEq(acc, "spanId", filters.spanId, prefix);
|
|
12239
|
+
pushEq(acc, "entityType", filters.entityType, prefix);
|
|
12240
|
+
pushEq(acc, "entityName", filters.entityName, prefix);
|
|
12241
|
+
pushEq(acc, "entityVersionId", filters.entityVersionId, prefix);
|
|
12242
|
+
pushEq(acc, "parentEntityType", filters.parentEntityType, prefix);
|
|
12243
|
+
pushEq(acc, "parentEntityName", filters.parentEntityName, prefix);
|
|
12244
|
+
pushEq(acc, "parentEntityVersionId", filters.parentEntityVersionId, prefix);
|
|
12245
|
+
pushEq(acc, "rootEntityType", filters.rootEntityType, prefix);
|
|
12246
|
+
pushEq(acc, "rootEntityName", filters.rootEntityName, prefix);
|
|
12247
|
+
pushEq(acc, "rootEntityVersionId", filters.rootEntityVersionId, prefix);
|
|
12248
|
+
pushEq(acc, "userId", filters.userId, prefix);
|
|
12249
|
+
pushEq(acc, "organizationId", filters.organizationId, prefix);
|
|
12250
|
+
pushEq(acc, "resourceId", filters.resourceId, prefix);
|
|
12251
|
+
pushEq(acc, "runId", filters.runId, prefix);
|
|
12252
|
+
pushEq(acc, "sessionId", filters.sessionId, prefix);
|
|
12253
|
+
pushEq(acc, "threadId", filters.threadId, prefix);
|
|
12254
|
+
pushEq(acc, "requestId", filters.requestId, prefix);
|
|
12255
|
+
pushEq(acc, "experimentId", filters.experimentId, prefix);
|
|
12256
|
+
pushEq(acc, "environment", filters.environment, prefix);
|
|
12257
|
+
pushEq(acc, "serviceName", filters.serviceName, prefix);
|
|
12258
|
+
pushEq(acc, "executionSource", filters.executionSource ?? filters.source, prefix);
|
|
12259
|
+
if (filters.tags != null && Array.isArray(filters.tags) && filters.tags.length > 0) {
|
|
12260
|
+
acc.conditions.push(`${prefix}"tags" @> $${acc.next++}::text[]`);
|
|
12261
|
+
acc.params.push(filters.tags);
|
|
11546
12262
|
}
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
} catch (error) {
|
|
11555
|
-
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
11556
|
-
}
|
|
11557
|
-
}
|
|
12263
|
+
}
|
|
12264
|
+
function applySingleOrArrayFilter(acc, column, value, prefix = "") {
|
|
12265
|
+
if (value === void 0) return;
|
|
12266
|
+
if (Array.isArray(value)) {
|
|
12267
|
+
pushIn(acc, column, value, prefix);
|
|
12268
|
+
} else {
|
|
12269
|
+
pushEq(acc, column, value, prefix);
|
|
11558
12270
|
}
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
12271
|
+
}
|
|
12272
|
+
function whereOrEmpty(acc) {
|
|
12273
|
+
return acc.conditions.length ? `WHERE ${acc.conditions.join(" AND ")}` : "";
|
|
12274
|
+
}
|
|
12275
|
+
var PROMOTED_KEYS = /* @__PURE__ */ new Set([
|
|
12276
|
+
"experimentId",
|
|
12277
|
+
"entityType",
|
|
12278
|
+
"entityId",
|
|
12279
|
+
"entityName",
|
|
12280
|
+
"entityVersionId",
|
|
12281
|
+
"parentEntityVersionId",
|
|
12282
|
+
"rootEntityVersionId",
|
|
12283
|
+
"userId",
|
|
12284
|
+
"organizationId",
|
|
12285
|
+
"resourceId",
|
|
12286
|
+
"runId",
|
|
12287
|
+
"sessionId",
|
|
12288
|
+
"threadId",
|
|
12289
|
+
"requestId",
|
|
12290
|
+
"environment",
|
|
12291
|
+
"executionSource",
|
|
12292
|
+
"serviceName"
|
|
12293
|
+
]);
|
|
12294
|
+
function nullableString(value) {
|
|
12295
|
+
if (typeof value === "string") return value === "" ? null : value;
|
|
12296
|
+
if (value == null) return null;
|
|
12297
|
+
return String(value);
|
|
12298
|
+
}
|
|
12299
|
+
function nullableEntityType(value) {
|
|
12300
|
+
const normalized = nullableString(value);
|
|
12301
|
+
if (!normalized) return null;
|
|
12302
|
+
return Object.values(storage.EntityType).includes(normalized) ? normalized : null;
|
|
12303
|
+
}
|
|
12304
|
+
function normalizeTags(tags) {
|
|
12305
|
+
if (!Array.isArray(tags)) return [];
|
|
12306
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12307
|
+
const result = [];
|
|
12308
|
+
for (const t of tags) {
|
|
12309
|
+
if (typeof t !== "string") continue;
|
|
12310
|
+
const trimmed = t.trim();
|
|
12311
|
+
if (trimmed === "" || seen.has(trimmed)) continue;
|
|
12312
|
+
seen.add(trimmed);
|
|
12313
|
+
result.push(trimmed);
|
|
11562
12314
|
}
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
12315
|
+
return result;
|
|
12316
|
+
}
|
|
12317
|
+
function normalizeLabels(labels) {
|
|
12318
|
+
if (labels == null || typeof labels !== "object") return {};
|
|
12319
|
+
const result = {};
|
|
12320
|
+
for (const [k, v] of Object.entries(labels)) {
|
|
12321
|
+
if (typeof v !== "string") continue;
|
|
12322
|
+
const trimmedK = k.trim();
|
|
12323
|
+
const trimmedV = v.trim();
|
|
12324
|
+
if (trimmedK === "" || trimmedV === "") continue;
|
|
12325
|
+
result[trimmedK] = trimmedV;
|
|
12326
|
+
}
|
|
12327
|
+
return result;
|
|
12328
|
+
}
|
|
12329
|
+
function buildMetadataSearch(metadata) {
|
|
12330
|
+
if (metadata == null || typeof metadata !== "object") return {};
|
|
12331
|
+
const result = {};
|
|
12332
|
+
for (const [k, v] of Object.entries(metadata)) {
|
|
12333
|
+
if (PROMOTED_KEYS.has(k)) continue;
|
|
12334
|
+
if (typeof v !== "string") continue;
|
|
12335
|
+
const trimmed = v.trim();
|
|
12336
|
+
if (trimmed === "") continue;
|
|
12337
|
+
result[k] = trimmed;
|
|
12338
|
+
}
|
|
12339
|
+
return result;
|
|
12340
|
+
}
|
|
12341
|
+
function toDate(value) {
|
|
12342
|
+
if (value instanceof Date) return value;
|
|
12343
|
+
if (value == null || value === "") throw new Error(`Invalid date: ${String(value)}`);
|
|
12344
|
+
const d = new Date(value);
|
|
12345
|
+
if (isNaN(d.getTime())) throw new Error(`Invalid date: ${String(value)}`);
|
|
12346
|
+
return d;
|
|
12347
|
+
}
|
|
12348
|
+
function toDateOrNull(value) {
|
|
12349
|
+
if (value == null || value === "") return null;
|
|
12350
|
+
if (value instanceof Date) return value;
|
|
12351
|
+
const d = new Date(value);
|
|
12352
|
+
if (isNaN(d.getTime())) return null;
|
|
12353
|
+
return d;
|
|
12354
|
+
}
|
|
12355
|
+
function toIsoOrDate(value) {
|
|
12356
|
+
if (value instanceof Date) return value;
|
|
12357
|
+
if (typeof value === "number") return new Date(value);
|
|
12358
|
+
return value;
|
|
12359
|
+
}
|
|
12360
|
+
function jsonField(value) {
|
|
12361
|
+
if (value === void 0) return null;
|
|
12362
|
+
return value;
|
|
12363
|
+
}
|
|
12364
|
+
function parsedJson(value) {
|
|
12365
|
+
if (value == null) return void 0;
|
|
12366
|
+
if (typeof value === "string") {
|
|
11567
12367
|
try {
|
|
11568
|
-
|
|
12368
|
+
return JSON.parse(value);
|
|
12369
|
+
} catch {
|
|
12370
|
+
return void 0;
|
|
12371
|
+
}
|
|
12372
|
+
}
|
|
12373
|
+
return value;
|
|
12374
|
+
}
|
|
12375
|
+
function rowToCommonContext(row) {
|
|
12376
|
+
return {
|
|
12377
|
+
experimentId: nullableString(row.experimentId),
|
|
12378
|
+
entityType: nullableEntityType(row.entityType),
|
|
12379
|
+
entityId: nullableString(row.entityId),
|
|
12380
|
+
entityName: nullableString(row.entityName),
|
|
12381
|
+
entityVersionId: nullableString(row.entityVersionId),
|
|
12382
|
+
parentEntityType: nullableEntityType(row.parentEntityType),
|
|
12383
|
+
parentEntityId: nullableString(row.parentEntityId),
|
|
12384
|
+
parentEntityName: nullableString(row.parentEntityName),
|
|
12385
|
+
parentEntityVersionId: nullableString(row.parentEntityVersionId),
|
|
12386
|
+
rootEntityType: nullableEntityType(row.rootEntityType),
|
|
12387
|
+
rootEntityId: nullableString(row.rootEntityId),
|
|
12388
|
+
rootEntityName: nullableString(row.rootEntityName),
|
|
12389
|
+
rootEntityVersionId: nullableString(row.rootEntityVersionId),
|
|
12390
|
+
userId: nullableString(row.userId),
|
|
12391
|
+
organizationId: nullableString(row.organizationId),
|
|
12392
|
+
resourceId: nullableString(row.resourceId),
|
|
12393
|
+
runId: nullableString(row.runId),
|
|
12394
|
+
sessionId: nullableString(row.sessionId),
|
|
12395
|
+
threadId: nullableString(row.threadId),
|
|
12396
|
+
requestId: nullableString(row.requestId),
|
|
12397
|
+
environment: nullableString(row.environment),
|
|
12398
|
+
executionSource: nullableString(row.executionSource),
|
|
12399
|
+
serviceName: nullableString(row.serviceName)
|
|
12400
|
+
};
|
|
12401
|
+
}
|
|
12402
|
+
function commonContextToRow(record) {
|
|
12403
|
+
return {
|
|
12404
|
+
experimentId: record.experimentId ?? null,
|
|
12405
|
+
entityType: record.entityType ?? null,
|
|
12406
|
+
entityId: record.entityId ?? null,
|
|
12407
|
+
entityName: record.entityName ?? null,
|
|
12408
|
+
entityVersionId: record.entityVersionId ?? null,
|
|
12409
|
+
parentEntityType: record.parentEntityType ?? null,
|
|
12410
|
+
parentEntityId: record.parentEntityId ?? null,
|
|
12411
|
+
parentEntityName: record.parentEntityName ?? null,
|
|
12412
|
+
parentEntityVersionId: record.parentEntityVersionId ?? null,
|
|
12413
|
+
rootEntityType: record.rootEntityType ?? null,
|
|
12414
|
+
rootEntityId: record.rootEntityId ?? null,
|
|
12415
|
+
rootEntityName: record.rootEntityName ?? null,
|
|
12416
|
+
rootEntityVersionId: record.rootEntityVersionId ?? null,
|
|
12417
|
+
userId: record.userId ?? null,
|
|
12418
|
+
organizationId: record.organizationId ?? null,
|
|
12419
|
+
resourceId: record.resourceId ?? null,
|
|
12420
|
+
runId: record.runId ?? null,
|
|
12421
|
+
sessionId: record.sessionId ?? null,
|
|
12422
|
+
threadId: record.threadId ?? null,
|
|
12423
|
+
requestId: record.requestId ?? null,
|
|
12424
|
+
environment: record.environment ?? null,
|
|
12425
|
+
executionSource: record.executionSource ?? record.source ?? null,
|
|
12426
|
+
serviceName: record.serviceName ?? null
|
|
12427
|
+
};
|
|
12428
|
+
}
|
|
12429
|
+
function spanRecordToRow(span) {
|
|
12430
|
+
const endedAt = span.isEvent ? span.startedAt : span.endedAt ?? span.startedAt;
|
|
12431
|
+
const metadata = span.metadata ?? null;
|
|
12432
|
+
return {
|
|
12433
|
+
...commonContextToRow(span),
|
|
12434
|
+
traceId: span.traceId,
|
|
12435
|
+
spanId: span.spanId,
|
|
12436
|
+
parentSpanId: span.parentSpanId ?? null,
|
|
12437
|
+
name: span.name,
|
|
12438
|
+
spanType: span.spanType,
|
|
12439
|
+
isEvent: Boolean(span.isEvent),
|
|
12440
|
+
startedAt: toIsoOrDate(span.startedAt),
|
|
12441
|
+
endedAt: toIsoOrDate(endedAt),
|
|
12442
|
+
tags: normalizeTags(span.tags),
|
|
12443
|
+
metadataSearch: buildMetadataSearch(metadata),
|
|
12444
|
+
metadataRaw: jsonField(metadata),
|
|
12445
|
+
scope: jsonField(span.scope),
|
|
12446
|
+
attributes: jsonField(span.attributes),
|
|
12447
|
+
links: jsonField(span.links),
|
|
12448
|
+
input: jsonField(span.input),
|
|
12449
|
+
output: jsonField(span.output),
|
|
12450
|
+
error: jsonField(span.error),
|
|
12451
|
+
requestContext: jsonField(span.requestContext)
|
|
12452
|
+
};
|
|
12453
|
+
}
|
|
12454
|
+
function rowToSpanRecord(row) {
|
|
12455
|
+
const startedAt = toDate(row.startedAt);
|
|
12456
|
+
const endedAt = row.isEvent ? startedAt : toDateOrNull(row.endedAt);
|
|
12457
|
+
const error = parsedJson(row.error);
|
|
12458
|
+
const { executionSource, ...ctx } = rowToCommonContext(row);
|
|
12459
|
+
return {
|
|
12460
|
+
...ctx,
|
|
12461
|
+
source: executionSource,
|
|
12462
|
+
traceId: row.traceId,
|
|
12463
|
+
spanId: row.spanId,
|
|
12464
|
+
parentSpanId: nullableString(row.parentSpanId),
|
|
12465
|
+
name: row.name,
|
|
12466
|
+
spanType: row.spanType,
|
|
12467
|
+
isEvent: Boolean(row.isEvent),
|
|
12468
|
+
startedAt,
|
|
12469
|
+
endedAt,
|
|
12470
|
+
tags: normalizeTags(row.tags),
|
|
12471
|
+
metadata: parsedJson(row.metadataRaw) ?? void 0,
|
|
12472
|
+
scope: parsedJson(row.scope) ?? void 0,
|
|
12473
|
+
attributes: parsedJson(row.attributes) ?? void 0,
|
|
12474
|
+
links: parsedJson(row.links) ?? void 0,
|
|
12475
|
+
input: parsedJson(row.input) ?? void 0,
|
|
12476
|
+
output: parsedJson(row.output) ?? void 0,
|
|
12477
|
+
error: error ?? void 0,
|
|
12478
|
+
requestContext: parsedJson(row.requestContext) ?? void 0,
|
|
12479
|
+
createdAt: startedAt,
|
|
12480
|
+
updatedAt: null
|
|
12481
|
+
};
|
|
12482
|
+
}
|
|
12483
|
+
function rowToLightSpanRecord(row) {
|
|
12484
|
+
const startedAt = toDate(row.startedAt);
|
|
12485
|
+
const endedAt = row.isEvent ? startedAt : toDateOrNull(row.endedAt);
|
|
12486
|
+
return {
|
|
12487
|
+
traceId: row.traceId,
|
|
12488
|
+
spanId: row.spanId,
|
|
12489
|
+
parentSpanId: row.parentSpanId == null || row.parentSpanId === "" ? null : String(row.parentSpanId),
|
|
12490
|
+
name: row.name,
|
|
12491
|
+
spanType: row.spanType,
|
|
12492
|
+
isEvent: Boolean(row.isEvent),
|
|
12493
|
+
startedAt,
|
|
12494
|
+
endedAt,
|
|
12495
|
+
entityType: row.entityType == null || row.entityType === "" ? null : Object.values(storage.EntityType).includes(row.entityType) ? row.entityType : null,
|
|
12496
|
+
entityId: row.entityId == null || row.entityId === "" ? null : String(row.entityId),
|
|
12497
|
+
entityName: row.entityName == null || row.entityName === "" ? null : String(row.entityName),
|
|
12498
|
+
error: parsedJson(row.error) ?? void 0,
|
|
12499
|
+
createdAt: startedAt,
|
|
12500
|
+
updatedAt: null
|
|
12501
|
+
};
|
|
12502
|
+
}
|
|
12503
|
+
function logRecordToRow(log) {
|
|
12504
|
+
return {
|
|
12505
|
+
...commonContextToRow(log),
|
|
12506
|
+
logId: log.logId,
|
|
12507
|
+
timestamp: toIsoOrDate(log.timestamp),
|
|
12508
|
+
level: log.level,
|
|
12509
|
+
message: log.message,
|
|
12510
|
+
data: jsonField(log.data),
|
|
12511
|
+
traceId: log.traceId ?? null,
|
|
12512
|
+
spanId: log.spanId ?? null,
|
|
12513
|
+
tags: normalizeTags(log.tags),
|
|
12514
|
+
metadata: jsonField(log.metadata),
|
|
12515
|
+
scope: jsonField(log.scope)
|
|
12516
|
+
};
|
|
12517
|
+
}
|
|
12518
|
+
function rowToLogRecord(row) {
|
|
12519
|
+
return {
|
|
12520
|
+
...rowToCommonContext(row),
|
|
12521
|
+
logId: row.logId,
|
|
12522
|
+
timestamp: toDate(row.timestamp),
|
|
12523
|
+
level: row.level,
|
|
12524
|
+
message: row.message,
|
|
12525
|
+
data: parsedJson(row.data) ?? void 0,
|
|
12526
|
+
traceId: nullableString(row.traceId),
|
|
12527
|
+
spanId: nullableString(row.spanId),
|
|
12528
|
+
tags: normalizeTags(row.tags),
|
|
12529
|
+
metadata: parsedJson(row.metadata) ?? void 0,
|
|
12530
|
+
scope: parsedJson(row.scope) ?? void 0
|
|
12531
|
+
};
|
|
12532
|
+
}
|
|
12533
|
+
function metricRecordToRow(metric) {
|
|
12534
|
+
return {
|
|
12535
|
+
...commonContextToRow(metric),
|
|
12536
|
+
metricId: metric.metricId,
|
|
12537
|
+
timestamp: toIsoOrDate(metric.timestamp),
|
|
12538
|
+
name: metric.name,
|
|
12539
|
+
value: metric.value,
|
|
12540
|
+
traceId: metric.traceId ?? null,
|
|
12541
|
+
spanId: metric.spanId ?? null,
|
|
12542
|
+
provider: metric.provider ?? null,
|
|
12543
|
+
model: metric.model ?? null,
|
|
12544
|
+
estimatedCost: metric.estimatedCost ?? null,
|
|
12545
|
+
costUnit: metric.costUnit ?? null,
|
|
12546
|
+
tags: normalizeTags(metric.tags),
|
|
12547
|
+
labels: normalizeLabels(metric.labels),
|
|
12548
|
+
costMetadata: jsonField(metric.costMetadata),
|
|
12549
|
+
metadata: jsonField(metric.metadata),
|
|
12550
|
+
scope: jsonField(metric.scope)
|
|
12551
|
+
};
|
|
12552
|
+
}
|
|
12553
|
+
function rowToMetricRecord(row) {
|
|
12554
|
+
return {
|
|
12555
|
+
...rowToCommonContext(row),
|
|
12556
|
+
metricId: row.metricId,
|
|
12557
|
+
timestamp: toDate(row.timestamp),
|
|
12558
|
+
name: row.name,
|
|
12559
|
+
value: Number(row.value),
|
|
12560
|
+
traceId: nullableString(row.traceId),
|
|
12561
|
+
spanId: nullableString(row.spanId),
|
|
12562
|
+
provider: nullableString(row.provider),
|
|
12563
|
+
model: nullableString(row.model),
|
|
12564
|
+
estimatedCost: row.estimatedCost == null ? void 0 : Number(row.estimatedCost),
|
|
12565
|
+
costUnit: nullableString(row.costUnit),
|
|
12566
|
+
costMetadata: parsedJson(row.costMetadata) ?? void 0,
|
|
12567
|
+
tags: normalizeTags(row.tags),
|
|
12568
|
+
labels: normalizeLabels(row.labels),
|
|
12569
|
+
metadata: parsedJson(row.metadata) ?? void 0,
|
|
12570
|
+
scope: parsedJson(row.scope) ?? void 0
|
|
12571
|
+
};
|
|
12572
|
+
}
|
|
12573
|
+
function scoreRecordToRow(score) {
|
|
12574
|
+
const metadata = score.metadata ?? null;
|
|
12575
|
+
const scoreSource = score.scoreSource ?? score.source ?? null;
|
|
12576
|
+
return {
|
|
12577
|
+
...commonContextToRow(score),
|
|
12578
|
+
scoreId: score.scoreId,
|
|
12579
|
+
timestamp: toIsoOrDate(score.timestamp),
|
|
12580
|
+
traceId: score.traceId ?? null,
|
|
12581
|
+
spanId: score.spanId ?? null,
|
|
12582
|
+
scoreTraceId: score.scoreTraceId ?? null,
|
|
12583
|
+
scorerId: score.scorerId,
|
|
12584
|
+
scorerVersion: score.scorerVersion ?? null,
|
|
12585
|
+
scoreSource,
|
|
12586
|
+
score: score.score,
|
|
12587
|
+
reason: score.reason ?? null,
|
|
12588
|
+
tags: normalizeTags(score.tags),
|
|
12589
|
+
metadata: jsonField(metadata),
|
|
12590
|
+
scope: jsonField(score.scope)
|
|
12591
|
+
};
|
|
12592
|
+
}
|
|
12593
|
+
function rowToScoreRecord(row) {
|
|
12594
|
+
return {
|
|
12595
|
+
...rowToCommonContext(row),
|
|
12596
|
+
scoreId: row.scoreId,
|
|
12597
|
+
timestamp: toDate(row.timestamp),
|
|
12598
|
+
// Legacy schema types traceId as required string even though the column is nullable.
|
|
12599
|
+
traceId: nullableString(row.traceId),
|
|
12600
|
+
spanId: nullableString(row.spanId),
|
|
12601
|
+
scoreTraceId: nullableString(row.scoreTraceId),
|
|
12602
|
+
scorerId: row.scorerId,
|
|
12603
|
+
scorerVersion: nullableString(row.scorerVersion),
|
|
12604
|
+
scoreSource: nullableString(row.scoreSource),
|
|
12605
|
+
score: Number(row.score),
|
|
12606
|
+
reason: nullableString(row.reason),
|
|
12607
|
+
tags: normalizeTags(row.tags),
|
|
12608
|
+
metadata: parsedJson(row.metadata) ?? void 0,
|
|
12609
|
+
scope: parsedJson(row.scope) ?? void 0
|
|
12610
|
+
};
|
|
12611
|
+
}
|
|
12612
|
+
function feedbackRecordToRow(feedback) {
|
|
12613
|
+
const metadata = feedback.metadata ?? null;
|
|
12614
|
+
const feedbackSource = feedback.feedbackSource ?? feedback.source ?? "";
|
|
12615
|
+
return {
|
|
12616
|
+
...commonContextToRow(feedback),
|
|
12617
|
+
feedbackId: feedback.feedbackId,
|
|
12618
|
+
timestamp: toIsoOrDate(feedback.timestamp),
|
|
12619
|
+
traceId: feedback.traceId ?? null,
|
|
12620
|
+
spanId: feedback.spanId ?? null,
|
|
12621
|
+
feedbackUserId: feedback.feedbackUserId ?? null,
|
|
12622
|
+
sourceId: feedback.sourceId ?? null,
|
|
12623
|
+
feedbackSource,
|
|
12624
|
+
feedbackType: feedback.feedbackType,
|
|
12625
|
+
valueString: typeof feedback.value === "string" ? feedback.value : null,
|
|
12626
|
+
valueNumber: typeof feedback.value === "number" ? feedback.value : null,
|
|
12627
|
+
comment: feedback.comment ?? null,
|
|
12628
|
+
tags: normalizeTags(feedback.tags),
|
|
12629
|
+
metadata: jsonField(metadata),
|
|
12630
|
+
scope: jsonField(feedback.scope)
|
|
12631
|
+
};
|
|
12632
|
+
}
|
|
12633
|
+
function rowToFeedbackRecord(row) {
|
|
12634
|
+
const hasNumber = row.valueNumber != null;
|
|
12635
|
+
const feedbackSource = nullableString(row.feedbackSource);
|
|
12636
|
+
return {
|
|
12637
|
+
...rowToCommonContext(row),
|
|
12638
|
+
feedbackId: row.feedbackId,
|
|
12639
|
+
timestamp: toDate(row.timestamp),
|
|
12640
|
+
// Legacy schema types traceId as required string even though the column is nullable.
|
|
12641
|
+
traceId: nullableString(row.traceId),
|
|
12642
|
+
spanId: nullableString(row.spanId),
|
|
12643
|
+
feedbackUserId: nullableString(row.feedbackUserId),
|
|
12644
|
+
sourceId: nullableString(row.sourceId),
|
|
12645
|
+
feedbackSource,
|
|
12646
|
+
feedbackType: row.feedbackType,
|
|
12647
|
+
value: hasNumber ? Number(row.valueNumber) : nullableString(row.valueString) ?? "",
|
|
12648
|
+
comment: nullableString(row.comment),
|
|
12649
|
+
tags: normalizeTags(row.tags),
|
|
12650
|
+
metadata: parsedJson(row.metadata) ?? void 0,
|
|
12651
|
+
scope: parsedJson(row.scope) ?? void 0
|
|
12652
|
+
};
|
|
12653
|
+
}
|
|
12654
|
+
var OBSERVABILITY_DELTA_POLLING_FEATURE = "observability-delta-polling";
|
|
12655
|
+
function deltaPollingFeatureEnabled() {
|
|
12656
|
+
return features.coreFeatures.has(OBSERVABILITY_DELTA_POLLING_FEATURE);
|
|
12657
|
+
}
|
|
12658
|
+
function assertDeltaPollingEnabled() {
|
|
12659
|
+
if (deltaPollingFeatureEnabled()) return;
|
|
12660
|
+
throw new error.MastraError({
|
|
12661
|
+
id: "OBSERVABILITY_DELTA_POLLING_NOT_SUPPORTED",
|
|
12662
|
+
domain: error.ErrorDomain.MASTRA_OBSERVABILITY,
|
|
12663
|
+
category: error.ErrorCategory.SYSTEM,
|
|
12664
|
+
text: "This storage provider does not support observability delta polling"
|
|
12665
|
+
});
|
|
12666
|
+
}
|
|
12667
|
+
var PG_BIGINT_MAX = 9223372036854775807n;
|
|
12668
|
+
function invalidDeltaCursor() {
|
|
12669
|
+
throw new error.MastraError({
|
|
12670
|
+
id: "OBSERVABILITY_INVALID_DELTA_CURSOR",
|
|
12671
|
+
domain: error.ErrorDomain.MASTRA_OBSERVABILITY,
|
|
12672
|
+
category: error.ErrorCategory.USER,
|
|
12673
|
+
text: "Invalid observability delta cursor"
|
|
12674
|
+
});
|
|
12675
|
+
}
|
|
12676
|
+
function validatePgInteger(value) {
|
|
12677
|
+
if (!/^\d+$/.test(value)) {
|
|
12678
|
+
invalidDeltaCursor();
|
|
12679
|
+
}
|
|
12680
|
+
let parsed;
|
|
12681
|
+
try {
|
|
12682
|
+
parsed = BigInt(value);
|
|
12683
|
+
} catch {
|
|
12684
|
+
invalidDeltaCursor();
|
|
12685
|
+
}
|
|
12686
|
+
if (parsed < 0n || parsed > PG_BIGINT_MAX) {
|
|
12687
|
+
invalidDeltaCursor();
|
|
12688
|
+
}
|
|
12689
|
+
return value;
|
|
12690
|
+
}
|
|
12691
|
+
function encodeDeltaCursor(xactId, cursorId = 0) {
|
|
12692
|
+
return `${validatePgInteger(String(xactId ?? 0))}:${validatePgInteger(String(cursorId ?? 0))}`;
|
|
12693
|
+
}
|
|
12694
|
+
function decodeDeltaCursor(cursor) {
|
|
12695
|
+
const parts = cursor.split(":");
|
|
12696
|
+
if (parts.length !== 2) {
|
|
12697
|
+
invalidDeltaCursor();
|
|
12698
|
+
}
|
|
12699
|
+
return {
|
|
12700
|
+
xactId: validatePgInteger(parts[0]),
|
|
12701
|
+
cursorId: validatePgInteger(parts[1])
|
|
12702
|
+
};
|
|
12703
|
+
}
|
|
12704
|
+
async function readSafeXactHorizon(client) {
|
|
12705
|
+
const row = await client.one(`SELECT pg_snapshot_xmin(pg_current_snapshot())::text AS "xactId"`);
|
|
12706
|
+
return validatePgInteger(row.xactId);
|
|
12707
|
+
}
|
|
12708
|
+
|
|
12709
|
+
// src/storage/domains/observability/v-next/listing.ts
|
|
12710
|
+
function responseItems(key, items) {
|
|
12711
|
+
return { [key]: items };
|
|
12712
|
+
}
|
|
12713
|
+
async function readSignalStreamHeadCursor({
|
|
12714
|
+
client,
|
|
12715
|
+
table,
|
|
12716
|
+
filters,
|
|
12717
|
+
applyFilters
|
|
12718
|
+
}) {
|
|
12719
|
+
return encodeDeltaCursor(await readSafeXactHorizon(client), 0);
|
|
12720
|
+
}
|
|
12721
|
+
async function listSignalPage(config) {
|
|
12722
|
+
const {
|
|
12723
|
+
client,
|
|
12724
|
+
table,
|
|
12725
|
+
filters,
|
|
12726
|
+
selectColumns,
|
|
12727
|
+
responseKey,
|
|
12728
|
+
applyFilters,
|
|
12729
|
+
mapRow,
|
|
12730
|
+
page,
|
|
12731
|
+
perPage,
|
|
12732
|
+
orderField,
|
|
12733
|
+
orderDir
|
|
12734
|
+
} = config;
|
|
12735
|
+
const acc = newFilterAccumulator();
|
|
12736
|
+
applyFilters(acc, filters);
|
|
12737
|
+
const whereClause = whereOrEmpty(acc);
|
|
12738
|
+
const countRow = await client.oneOrNone(
|
|
12739
|
+
`SELECT COUNT(*)::text AS count FROM ${table} ${whereClause}`,
|
|
12740
|
+
acc.params
|
|
12741
|
+
);
|
|
12742
|
+
const total = Number(countRow?.count ?? 0);
|
|
12743
|
+
let items = [];
|
|
12744
|
+
if (total > 0) {
|
|
12745
|
+
const safeOrderField = utils.parseSqlIdentifier(orderField, "order field");
|
|
12746
|
+
const rows = await client.manyOrNone(
|
|
12747
|
+
`SELECT ${selectColumns}
|
|
12748
|
+
FROM ${table}
|
|
12749
|
+
${whereClause}
|
|
12750
|
+
ORDER BY "${safeOrderField}" ${orderDir}, "cursorId" ${orderDir}
|
|
12751
|
+
LIMIT $${acc.next++} OFFSET $${acc.next++}`,
|
|
12752
|
+
[...acc.params, perPage, page * perPage]
|
|
12753
|
+
);
|
|
12754
|
+
items = rows.map(mapRow);
|
|
12755
|
+
}
|
|
12756
|
+
const deltaCursor = config.includeDeltaCursor ? await readSignalStreamHeadCursor({ client, table, filters, applyFilters }) : void 0;
|
|
12757
|
+
return {
|
|
12758
|
+
pagination: { total, page, perPage, hasMore: (page + 1) * perPage < total },
|
|
12759
|
+
...responseItems(responseKey, items),
|
|
12760
|
+
...deltaCursor !== void 0 ? { deltaCursor } : {}
|
|
12761
|
+
};
|
|
12762
|
+
}
|
|
12763
|
+
async function listSignalDelta(config) {
|
|
12764
|
+
const { client, table, filters, selectColumns, responseKey, applyFilters, mapRow, after, limit } = config;
|
|
12765
|
+
if (after === void 0) {
|
|
12766
|
+
const deltaCursor2 = await readSignalStreamHeadCursor({ client, table, filters, applyFilters });
|
|
12767
|
+
return { ...responseItems(responseKey, []), delta: { limit, hasMore: false }, deltaCursor: deltaCursor2 };
|
|
12768
|
+
}
|
|
12769
|
+
const afterCursor = decodeDeltaCursor(after);
|
|
12770
|
+
const safeHorizon = await readSafeXactHorizon(client);
|
|
12771
|
+
const acc = newFilterAccumulator();
|
|
12772
|
+
applyFilters(acc, filters);
|
|
12773
|
+
acc.conditions.push(`("xactId", "cursorId") > ($${acc.next++}::xid8, $${acc.next++}::bigint)`);
|
|
12774
|
+
acc.params.push(afterCursor.xactId, afterCursor.cursorId);
|
|
12775
|
+
acc.conditions.push(`"xactId" < $${acc.next++}::xid8`);
|
|
12776
|
+
acc.params.push(safeHorizon);
|
|
12777
|
+
const rows = await client.manyOrNone(
|
|
12778
|
+
`SELECT ${selectColumns}
|
|
12779
|
+
FROM ${table}
|
|
12780
|
+
${whereOrEmpty(acc)}
|
|
12781
|
+
ORDER BY "xactId" ASC, "cursorId" ASC
|
|
12782
|
+
LIMIT $${acc.next++}`,
|
|
12783
|
+
[...acc.params, limit + 1]
|
|
12784
|
+
);
|
|
12785
|
+
const hasMore = rows.length > limit;
|
|
12786
|
+
const visible = rows.slice(0, limit);
|
|
12787
|
+
const deltaCursor = visible.length > 0 ? encodeDeltaCursor(visible[visible.length - 1].xactId, visible[visible.length - 1].cursorId) : encodeDeltaCursor(safeHorizon, 0);
|
|
12788
|
+
return {
|
|
12789
|
+
...responseItems(responseKey, visible.map(mapRow)),
|
|
12790
|
+
delta: { limit, hasMore },
|
|
12791
|
+
deltaCursor
|
|
12792
|
+
};
|
|
12793
|
+
}
|
|
12794
|
+
var INTERVAL_SECONDS = {
|
|
12795
|
+
"1m": 60,
|
|
12796
|
+
"5m": 300,
|
|
12797
|
+
"15m": 900,
|
|
12798
|
+
"1h": 3600,
|
|
12799
|
+
"1d": 86400
|
|
12800
|
+
};
|
|
12801
|
+
function bucketSql(column, interval) {
|
|
12802
|
+
const seconds = INTERVAL_SECONDS[interval] ?? 3600;
|
|
12803
|
+
return `to_timestamp(floor(extract(epoch from ${column}) / ${seconds}) * ${seconds})`;
|
|
12804
|
+
}
|
|
12805
|
+
function resolveDistinctColumnSql(distinctColumn) {
|
|
12806
|
+
if (!distinctColumn) {
|
|
12807
|
+
throw new Error(`count_distinct aggregation requires a 'distinctColumn' argument`);
|
|
12808
|
+
}
|
|
12809
|
+
if (!storage.METRIC_DISTINCT_COLUMNS.includes(distinctColumn)) {
|
|
12810
|
+
throw new Error(`Invalid distinctColumn: ${distinctColumn}`);
|
|
12811
|
+
}
|
|
12812
|
+
return `"${utils.parseFieldKey(distinctColumn)}"`;
|
|
12813
|
+
}
|
|
12814
|
+
function metricAggregationSql(agg, measure, timestampColumn = "timestamp", distinctColumn) {
|
|
12815
|
+
if (agg === "count_distinct") {
|
|
12816
|
+
return `COUNT(DISTINCT ${resolveDistinctColumnSql(distinctColumn)})::double precision`;
|
|
12817
|
+
}
|
|
12818
|
+
return aggregationSql(agg, measure, timestampColumn);
|
|
12819
|
+
}
|
|
12820
|
+
function aggregationSql(agg, measure, timestampColumn = "timestamp") {
|
|
12821
|
+
switch (agg) {
|
|
12822
|
+
case "sum":
|
|
12823
|
+
return `SUM(${measure})`;
|
|
12824
|
+
case "avg":
|
|
12825
|
+
return `AVG(${measure})`;
|
|
12826
|
+
case "min":
|
|
12827
|
+
return `MIN(${measure})`;
|
|
12828
|
+
case "max":
|
|
12829
|
+
return `MAX(${measure})`;
|
|
12830
|
+
case "count":
|
|
12831
|
+
return `COUNT(${measure})::double precision`;
|
|
12832
|
+
case "last":
|
|
12833
|
+
return `(array_agg(${measure} ORDER BY "${timestampColumn}" DESC))[1]`;
|
|
12834
|
+
default:
|
|
12835
|
+
return `SUM(${measure})`;
|
|
12836
|
+
}
|
|
12837
|
+
}
|
|
12838
|
+
function resolveGroupBy(acc, groupBy, options) {
|
|
12839
|
+
const labelsColumn = options.labelsColumn ?? null;
|
|
12840
|
+
const excluded = options.excludedColumns ?? /* @__PURE__ */ new Set();
|
|
12841
|
+
return groupBy.map((key, index) => {
|
|
12842
|
+
const alias = `group_by_${index}`;
|
|
12843
|
+
if (options.typedColumns.has(key)) {
|
|
12844
|
+
const parsed = utils.parseFieldKey(key);
|
|
12845
|
+
if (excluded.has(parsed)) {
|
|
12846
|
+
throw new Error(`Invalid groupBy column(s): ${key}`);
|
|
12847
|
+
}
|
|
12848
|
+
return {
|
|
12849
|
+
requestedKey: key,
|
|
12850
|
+
alias,
|
|
12851
|
+
selectSql: `"${parsed}" AS ${alias}`,
|
|
12852
|
+
valueSql: `"${parsed}"`
|
|
12853
|
+
};
|
|
12854
|
+
}
|
|
12855
|
+
if (!labelsColumn) {
|
|
12856
|
+
throw new Error(`Invalid groupBy column(s): ${key}`);
|
|
12857
|
+
}
|
|
12858
|
+
const valueSql = `"${labelsColumn}" ->> $${acc.next++}`;
|
|
12859
|
+
acc.params.push(key);
|
|
12860
|
+
return {
|
|
12861
|
+
requestedKey: key,
|
|
12862
|
+
alias,
|
|
12863
|
+
selectSql: `${valueSql} AS ${alias}`,
|
|
12864
|
+
valueSql
|
|
12865
|
+
};
|
|
12866
|
+
});
|
|
12867
|
+
}
|
|
12868
|
+
function pushLabelExclusions(acc, resolved) {
|
|
12869
|
+
for (const entry of resolved) {
|
|
12870
|
+
if (entry.valueSql.includes("->>")) {
|
|
12871
|
+
acc.conditions.push(`${entry.valueSql} IS NOT NULL`);
|
|
12872
|
+
acc.conditions.push(`${entry.valueSql} <> ''`);
|
|
12873
|
+
}
|
|
12874
|
+
}
|
|
12875
|
+
}
|
|
12876
|
+
function dimensionsFromRow(row, resolved) {
|
|
12877
|
+
const out = {};
|
|
12878
|
+
for (const entry of resolved) {
|
|
12879
|
+
const v = row[entry.alias];
|
|
12880
|
+
out[entry.requestedKey] = v == null || v === "" ? null : String(v);
|
|
12881
|
+
}
|
|
12882
|
+
return out;
|
|
12883
|
+
}
|
|
12884
|
+
function seriesNameFromDimensions(values) {
|
|
12885
|
+
return values.map((v) => v == null || v === "" ? "" : String(v)).join("|");
|
|
12886
|
+
}
|
|
12887
|
+
function shiftRange(range, period) {
|
|
12888
|
+
if (!range.start || !range.end) return null;
|
|
12889
|
+
const start = range.start.getTime();
|
|
12890
|
+
const end = range.end.getTime();
|
|
12891
|
+
const duration = end - start;
|
|
12892
|
+
let offset;
|
|
12893
|
+
switch (period) {
|
|
12894
|
+
case "previous_day":
|
|
12895
|
+
offset = 864e5;
|
|
12896
|
+
break;
|
|
12897
|
+
case "previous_week":
|
|
12898
|
+
offset = 7 * 864e5;
|
|
12899
|
+
break;
|
|
12900
|
+
case "previous_period":
|
|
12901
|
+
default:
|
|
12902
|
+
offset = duration;
|
|
12903
|
+
}
|
|
12904
|
+
return {
|
|
12905
|
+
start: new Date(start - offset),
|
|
12906
|
+
end: new Date(end - offset),
|
|
12907
|
+
startExclusive: range.startExclusive,
|
|
12908
|
+
endExclusive: range.endExclusive
|
|
12909
|
+
};
|
|
12910
|
+
}
|
|
12911
|
+
function changePercent(current, previous) {
|
|
12912
|
+
if (current === null || previous === null || previous === 0) return null;
|
|
12913
|
+
return (current - previous) / Math.abs(previous) * 100;
|
|
12914
|
+
}
|
|
12915
|
+
function bucketDate(value) {
|
|
12916
|
+
return value instanceof Date ? value : new Date(String(value));
|
|
12917
|
+
}
|
|
12918
|
+
function validatePercentiles(percentiles) {
|
|
12919
|
+
if (!percentiles.length) {
|
|
12920
|
+
throw new Error("Percentiles must include at least one value between 0 and 1.");
|
|
12921
|
+
}
|
|
12922
|
+
for (const percentile of percentiles) {
|
|
12923
|
+
if (!Number.isFinite(percentile) || percentile < 0 || percentile > 1) {
|
|
12924
|
+
throw new Error(`Percentile value must be a finite number between 0 and 1, got ${percentile}`);
|
|
12925
|
+
}
|
|
12926
|
+
}
|
|
12927
|
+
}
|
|
12928
|
+
function percentileSelectSql(percentiles, measureSql) {
|
|
12929
|
+
return percentiles.map((percentile, index) => `percentile_cont(${percentile}) WITHIN GROUP (ORDER BY ${measureSql}) AS p${index}`).join(", ");
|
|
12930
|
+
}
|
|
12931
|
+
function percentileSeriesFromRows(rows, percentiles) {
|
|
12932
|
+
return percentiles.map((percentile, index) => ({
|
|
12933
|
+
percentile,
|
|
12934
|
+
points: rows.map((row) => ({
|
|
12935
|
+
timestamp: bucketDate(row.bucket),
|
|
12936
|
+
value: Number(row[`p${index}`] ?? 0)
|
|
12937
|
+
}))
|
|
12938
|
+
}));
|
|
12939
|
+
}
|
|
12940
|
+
function collectSeriesByDimensions(rows, resolved, createEntry, appendRow) {
|
|
12941
|
+
const seriesMap = /* @__PURE__ */ new Map();
|
|
12942
|
+
for (const row of rows) {
|
|
12943
|
+
const dimensionValues = resolved.map((entry2) => row[entry2.alias]);
|
|
12944
|
+
const seriesKey = JSON.stringify(dimensionValues);
|
|
12945
|
+
let entry = seriesMap.get(seriesKey);
|
|
12946
|
+
if (!entry) {
|
|
12947
|
+
entry = createEntry(dimensionValues);
|
|
12948
|
+
seriesMap.set(seriesKey, entry);
|
|
12949
|
+
}
|
|
12950
|
+
appendRow(entry, row, dimensionValues);
|
|
12951
|
+
}
|
|
12952
|
+
return Array.from(seriesMap.values());
|
|
12953
|
+
}
|
|
12954
|
+
var COST_SUMMARY_SELECT = `
|
|
12955
|
+
SUM("estimatedCost") FILTER (WHERE "estimatedCost" IS NOT NULL) AS "agg_estimatedCost",
|
|
12956
|
+
CASE
|
|
12957
|
+
WHEN COUNT(DISTINCT "costUnit") FILTER (WHERE "costUnit" IS NOT NULL) = 1
|
|
12958
|
+
THEN MIN("costUnit") FILTER (WHERE "costUnit" IS NOT NULL)
|
|
12959
|
+
ELSE NULL
|
|
12960
|
+
END AS "agg_costUnit"
|
|
12961
|
+
`;
|
|
12962
|
+
function costSummaryFromRow(row) {
|
|
12963
|
+
return {
|
|
12964
|
+
estimatedCost: row.agg_estimatedCost == null ? null : Number(row.agg_estimatedCost),
|
|
12965
|
+
costUnit: row.agg_costUnit == null || row.agg_costUnit === "" ? null : String(row.agg_costUnit)
|
|
12966
|
+
};
|
|
12967
|
+
}
|
|
12968
|
+
var COMPLEX_GROUP_BY_EXCLUDED = /* @__PURE__ */ new Set([
|
|
12969
|
+
"metadata",
|
|
12970
|
+
"metadataRaw",
|
|
12971
|
+
"metadataSearch",
|
|
12972
|
+
"scope",
|
|
12973
|
+
"attributes",
|
|
12974
|
+
"links",
|
|
12975
|
+
"input",
|
|
12976
|
+
"output",
|
|
12977
|
+
"error",
|
|
12978
|
+
"data",
|
|
12979
|
+
"labels",
|
|
12980
|
+
"costMetadata",
|
|
12981
|
+
"tags",
|
|
12982
|
+
"requestContext"
|
|
12983
|
+
]);
|
|
12984
|
+
function encodeJsonb(value) {
|
|
12985
|
+
if (value === null || value === void 0) return null;
|
|
12986
|
+
return JSON.stringify(value);
|
|
12987
|
+
}
|
|
12988
|
+
function buildInsert(schema, table, records) {
|
|
12989
|
+
if (records.length === 0) return null;
|
|
12990
|
+
const columns = Object.keys(records[0]).map((c) => utils.parseSqlIdentifier(c, "column name"));
|
|
12991
|
+
const quotedColumns = columns.map((c) => `"${c}"`).join(", ");
|
|
12992
|
+
const values = [];
|
|
12993
|
+
const rowPlaceholders = [];
|
|
12994
|
+
let p = 1;
|
|
12995
|
+
for (const record of records) {
|
|
12996
|
+
const placeholders = columns.map((col) => {
|
|
12997
|
+
const raw = record[col];
|
|
12998
|
+
if (JSONB_COLUMNS.has(col)) {
|
|
12999
|
+
values.push(encodeJsonb(raw));
|
|
13000
|
+
return `$${p++}::jsonb`;
|
|
13001
|
+
}
|
|
13002
|
+
if (TEXT_ARRAY_COLUMNS.has(col)) {
|
|
13003
|
+
values.push(Array.isArray(raw) ? raw : []);
|
|
13004
|
+
return `$${p++}::text[]`;
|
|
13005
|
+
}
|
|
13006
|
+
values.push(raw === void 0 ? null : raw);
|
|
13007
|
+
return `$${p++}`;
|
|
13008
|
+
});
|
|
13009
|
+
rowPlaceholders.push(`(${placeholders.join(", ")})`);
|
|
13010
|
+
}
|
|
13011
|
+
const text = `INSERT INTO ${qualifiedTable(schema, table)} (${quotedColumns})
|
|
13012
|
+
VALUES ${rowPlaceholders.join(", ")}
|
|
13013
|
+
ON CONFLICT DO NOTHING`;
|
|
13014
|
+
return { text, values };
|
|
13015
|
+
}
|
|
13016
|
+
var SPAN_SELECT_COLUMNS = `
|
|
13017
|
+
${buildSelectColumns(SPAN_EVENT_COLUMNS)}`;
|
|
13018
|
+
var SPAN_LIGHT_SELECT_COLUMNS = `
|
|
13019
|
+
${buildNamedSelectColumns(SPAN_LIGHT_SELECT_COLUMN_NAMES)}`;
|
|
13020
|
+
var METRIC_SELECT_COLUMNS = `
|
|
13021
|
+
${buildSelectColumns(METRIC_EVENT_COLUMNS)}`;
|
|
13022
|
+
var LOG_SELECT_COLUMNS = `
|
|
13023
|
+
${buildSelectColumns(LOG_EVENT_COLUMNS)}`;
|
|
13024
|
+
var SCORE_SELECT_COLUMNS = `
|
|
13025
|
+
${buildSelectColumns(SCORE_EVENT_COLUMNS)}`;
|
|
13026
|
+
var FEEDBACK_SELECT_COLUMNS = `
|
|
13027
|
+
${buildSelectColumns(FEEDBACK_EVENT_COLUMNS)}`;
|
|
13028
|
+
|
|
13029
|
+
// src/storage/domains/observability/v-next/feedback.ts
|
|
13030
|
+
function applyFeedbackFilters(acc, filters) {
|
|
13031
|
+
applyCommonFilters(acc, filters);
|
|
13032
|
+
applySingleOrArrayFilter(acc, "feedbackType", filters?.feedbackType);
|
|
13033
|
+
if (filters?.feedbackSource ?? filters?.source) {
|
|
13034
|
+
acc.conditions.push(`"feedbackSource" = $${acc.next++}`);
|
|
13035
|
+
acc.params.push(filters.feedbackSource ?? filters.source);
|
|
13036
|
+
}
|
|
13037
|
+
if (filters?.feedbackUserId) {
|
|
13038
|
+
acc.conditions.push(`"feedbackUserId" = $${acc.next++}`);
|
|
13039
|
+
acc.params.push(filters.feedbackUserId);
|
|
13040
|
+
}
|
|
13041
|
+
}
|
|
13042
|
+
function pushFeedbackIdentity(acc, feedbackType, feedbackSource) {
|
|
13043
|
+
acc.conditions.push(`"feedbackType" = $${acc.next++}`);
|
|
13044
|
+
acc.params.push(feedbackType);
|
|
13045
|
+
if (feedbackSource !== void 0) {
|
|
13046
|
+
acc.conditions.push(`"feedbackSource" = $${acc.next++}`);
|
|
13047
|
+
acc.params.push(feedbackSource);
|
|
13048
|
+
}
|
|
13049
|
+
acc.conditions.push(`"valueNumber" IS NOT NULL`);
|
|
13050
|
+
}
|
|
13051
|
+
async function createFeedback(client, schema, args) {
|
|
13052
|
+
const row = feedbackRecordToRow(args.feedback);
|
|
13053
|
+
const insert = buildInsert(schema, TABLE_FEEDBACK_EVENTS, [row]);
|
|
13054
|
+
if (insert) await client.query(insert.text, insert.values);
|
|
13055
|
+
}
|
|
13056
|
+
async function batchCreateFeedback(client, schema, args) {
|
|
13057
|
+
if (args.feedbacks.length === 0) return;
|
|
13058
|
+
const rows = args.feedbacks.map(feedbackRecordToRow);
|
|
13059
|
+
const insert = buildInsert(schema, TABLE_FEEDBACK_EVENTS, rows);
|
|
13060
|
+
if (insert) await client.query(insert.text, insert.values);
|
|
13061
|
+
}
|
|
13062
|
+
async function listFeedback(client, schema, args) {
|
|
13063
|
+
const { mode, filters, pagination, orderBy, after, limit } = storage.listFeedbackArgsSchema.parse(args);
|
|
13064
|
+
const table = qualifiedTable(schema, TABLE_FEEDBACK_EVENTS);
|
|
13065
|
+
if (mode === "delta") {
|
|
13066
|
+
assertDeltaPollingEnabled();
|
|
13067
|
+
return listFeedbackDelta(client, table, filters, after, limit);
|
|
13068
|
+
}
|
|
13069
|
+
return listFeedbackPage(
|
|
13070
|
+
client,
|
|
13071
|
+
table,
|
|
13072
|
+
filters,
|
|
13073
|
+
pagination.page,
|
|
13074
|
+
pagination.perPage,
|
|
13075
|
+
orderBy.field,
|
|
13076
|
+
orderBy.direction
|
|
13077
|
+
);
|
|
13078
|
+
}
|
|
13079
|
+
async function listFeedbackPage(client, table, filters, page, perPage, orderField, orderDir) {
|
|
13080
|
+
return listSignalPage({
|
|
13081
|
+
client,
|
|
13082
|
+
table,
|
|
13083
|
+
filters,
|
|
13084
|
+
page,
|
|
13085
|
+
perPage,
|
|
13086
|
+
orderField,
|
|
13087
|
+
orderDir,
|
|
13088
|
+
includeDeltaCursor: deltaPollingFeatureEnabled(),
|
|
13089
|
+
selectColumns: FEEDBACK_SELECT_COLUMNS,
|
|
13090
|
+
responseKey: "feedback",
|
|
13091
|
+
applyFilters: applyFeedbackFilters,
|
|
13092
|
+
mapRow: rowToFeedbackRecord
|
|
13093
|
+
});
|
|
13094
|
+
}
|
|
13095
|
+
async function listFeedbackDelta(client, table, filters, after, limit) {
|
|
13096
|
+
return listSignalDelta({
|
|
13097
|
+
client,
|
|
13098
|
+
table,
|
|
13099
|
+
filters,
|
|
13100
|
+
after,
|
|
13101
|
+
limit,
|
|
13102
|
+
selectColumns: FEEDBACK_SELECT_COLUMNS,
|
|
13103
|
+
responseKey: "feedback",
|
|
13104
|
+
applyFilters: applyFeedbackFilters,
|
|
13105
|
+
mapRow: rowToFeedbackRecord
|
|
13106
|
+
});
|
|
13107
|
+
}
|
|
13108
|
+
async function runFeedbackAggregateQuery(client, schema, args, filters) {
|
|
13109
|
+
const acc = newFilterAccumulator();
|
|
13110
|
+
pushFeedbackIdentity(acc, args.feedbackType, args.feedbackSource);
|
|
13111
|
+
applyFeedbackFilters(acc, filters);
|
|
13112
|
+
const sql = `
|
|
13113
|
+
SELECT ${aggregationSql(args.aggregation, '"valueNumber"')} AS "value"
|
|
13114
|
+
FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
|
|
13115
|
+
${whereOrEmpty(acc)}
|
|
13116
|
+
`;
|
|
13117
|
+
const row = await client.oneOrNone(sql, acc.params);
|
|
13118
|
+
return row?.value == null ? null : Number(row.value);
|
|
13119
|
+
}
|
|
13120
|
+
async function getFeedbackAggregate(client, schema, args) {
|
|
13121
|
+
const value = await runFeedbackAggregateQuery(client, schema, args, args.filters);
|
|
13122
|
+
if (args.comparePeriod && args.filters?.timestamp) {
|
|
13123
|
+
const prevRange = shiftRange(args.filters.timestamp, args.comparePeriod);
|
|
13124
|
+
if (prevRange) {
|
|
13125
|
+
const previousValue = await runFeedbackAggregateQuery(client, schema, args, {
|
|
13126
|
+
...args.filters ?? {},
|
|
13127
|
+
timestamp: prevRange
|
|
13128
|
+
});
|
|
13129
|
+
return {
|
|
13130
|
+
value,
|
|
13131
|
+
previousValue,
|
|
13132
|
+
changePercent: changePercent(value, previousValue)
|
|
13133
|
+
};
|
|
13134
|
+
}
|
|
13135
|
+
}
|
|
13136
|
+
return { value };
|
|
13137
|
+
}
|
|
13138
|
+
async function getFeedbackBreakdown(client, schema, args) {
|
|
13139
|
+
const acc = newFilterAccumulator();
|
|
13140
|
+
const resolved = resolveGroupBy(acc, args.groupBy, {
|
|
13141
|
+
typedColumns: FEEDBACK_TYPED_COLUMNS,
|
|
13142
|
+
excludedColumns: COMPLEX_GROUP_BY_EXCLUDED
|
|
13143
|
+
});
|
|
13144
|
+
pushFeedbackIdentity(acc, args.feedbackType, args.feedbackSource);
|
|
13145
|
+
applyFeedbackFilters(acc, args.filters);
|
|
13146
|
+
const sql = `
|
|
13147
|
+
SELECT ${resolved.map((e) => e.selectSql).join(", ")},
|
|
13148
|
+
${aggregationSql(args.aggregation, '"valueNumber"')} AS "value"
|
|
13149
|
+
FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
|
|
13150
|
+
${whereOrEmpty(acc)}
|
|
13151
|
+
GROUP BY ${resolved.map((e) => e.alias).join(", ")}
|
|
13152
|
+
ORDER BY "value" DESC NULLS LAST
|
|
13153
|
+
`;
|
|
13154
|
+
const rows = await client.manyOrNone(sql, acc.params);
|
|
13155
|
+
return {
|
|
13156
|
+
groups: rows.map((row) => ({
|
|
13157
|
+
dimensions: dimensionsFromRow(row, resolved),
|
|
13158
|
+
value: Number(row.value ?? 0)
|
|
13159
|
+
}))
|
|
13160
|
+
};
|
|
13161
|
+
}
|
|
13162
|
+
async function getFeedbackTimeSeries(client, schema, args) {
|
|
13163
|
+
const bucket = bucketSql('"timestamp"', args.interval);
|
|
13164
|
+
if (args.groupBy && args.groupBy.length > 0) {
|
|
13165
|
+
const acc2 = newFilterAccumulator();
|
|
13166
|
+
const resolved = resolveGroupBy(acc2, args.groupBy, {
|
|
13167
|
+
typedColumns: FEEDBACK_TYPED_COLUMNS,
|
|
13168
|
+
excludedColumns: COMPLEX_GROUP_BY_EXCLUDED
|
|
13169
|
+
});
|
|
13170
|
+
pushFeedbackIdentity(acc2, args.feedbackType, args.feedbackSource);
|
|
13171
|
+
applyFeedbackFilters(acc2, args.filters);
|
|
13172
|
+
const sql2 = `
|
|
13173
|
+
SELECT ${bucket} AS bucket,
|
|
13174
|
+
${resolved.map((e) => e.selectSql).join(", ")},
|
|
13175
|
+
${aggregationSql(args.aggregation, '"valueNumber"')} AS "value"
|
|
13176
|
+
FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
|
|
13177
|
+
${whereOrEmpty(acc2)}
|
|
13178
|
+
GROUP BY bucket, ${resolved.map((e) => e.alias).join(", ")}
|
|
13179
|
+
ORDER BY bucket
|
|
13180
|
+
`;
|
|
13181
|
+
const rows2 = await client.manyOrNone(sql2, acc2.params);
|
|
13182
|
+
return {
|
|
13183
|
+
series: collectSeriesByDimensions(
|
|
13184
|
+
rows2,
|
|
13185
|
+
resolved,
|
|
13186
|
+
(dimValues) => ({
|
|
13187
|
+
name: seriesNameFromDimensions(dimValues),
|
|
13188
|
+
points: []
|
|
13189
|
+
}),
|
|
13190
|
+
(entry, row) => {
|
|
13191
|
+
entry.points.push({
|
|
13192
|
+
timestamp: bucketDate(row.bucket),
|
|
13193
|
+
value: Number(row.value ?? 0)
|
|
13194
|
+
});
|
|
13195
|
+
}
|
|
13196
|
+
)
|
|
13197
|
+
};
|
|
13198
|
+
}
|
|
13199
|
+
const acc = newFilterAccumulator();
|
|
13200
|
+
pushFeedbackIdentity(acc, args.feedbackType, args.feedbackSource);
|
|
13201
|
+
applyFeedbackFilters(acc, args.filters);
|
|
13202
|
+
const sql = `
|
|
13203
|
+
SELECT ${bucket} AS bucket,
|
|
13204
|
+
${aggregationSql(args.aggregation, '"valueNumber"')} AS "value"
|
|
13205
|
+
FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
|
|
13206
|
+
${whereOrEmpty(acc)}
|
|
13207
|
+
GROUP BY bucket
|
|
13208
|
+
ORDER BY bucket
|
|
13209
|
+
`;
|
|
13210
|
+
const rows = await client.manyOrNone(sql, acc.params);
|
|
13211
|
+
const seriesName = args.feedbackSource ? `${args.feedbackType}|${args.feedbackSource}` : args.feedbackType;
|
|
13212
|
+
return {
|
|
13213
|
+
series: [
|
|
13214
|
+
{
|
|
13215
|
+
name: seriesName,
|
|
13216
|
+
points: rows.map((row) => ({
|
|
13217
|
+
timestamp: bucketDate(row.bucket),
|
|
13218
|
+
value: Number(row.value ?? 0)
|
|
13219
|
+
}))
|
|
13220
|
+
}
|
|
13221
|
+
]
|
|
13222
|
+
};
|
|
13223
|
+
}
|
|
13224
|
+
async function getFeedbackPercentiles(client, schema, args) {
|
|
13225
|
+
validatePercentiles(args.percentiles);
|
|
13226
|
+
const bucket = bucketSql('"timestamp"', args.interval);
|
|
13227
|
+
const acc = newFilterAccumulator();
|
|
13228
|
+
pushFeedbackIdentity(acc, args.feedbackType, args.feedbackSource);
|
|
13229
|
+
applyFeedbackFilters(acc, args.filters);
|
|
13230
|
+
const percentileSelect = percentileSelectSql(args.percentiles, '"valueNumber"');
|
|
13231
|
+
const sql = `
|
|
13232
|
+
SELECT ${bucket} AS bucket, ${percentileSelect}
|
|
13233
|
+
FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
|
|
13234
|
+
${whereOrEmpty(acc)}
|
|
13235
|
+
GROUP BY bucket
|
|
13236
|
+
ORDER BY bucket
|
|
13237
|
+
`;
|
|
13238
|
+
const rows = await client.manyOrNone(sql, acc.params);
|
|
13239
|
+
return { series: percentileSeriesFromRows(rows, args.percentiles) };
|
|
13240
|
+
}
|
|
13241
|
+
function applyLogFilters(acc, filters) {
|
|
13242
|
+
applyCommonFilters(acc, filters);
|
|
13243
|
+
applySingleOrArrayFilter(acc, "level", filters?.level);
|
|
13244
|
+
}
|
|
13245
|
+
async function batchCreateLogs(client, schema, args) {
|
|
13246
|
+
if (args.logs.length === 0) return;
|
|
13247
|
+
const rows = args.logs.map(logRecordToRow);
|
|
13248
|
+
const insert = buildInsert(schema, TABLE_LOG_EVENTS, rows);
|
|
13249
|
+
if (insert) await client.query(insert.text, insert.values);
|
|
13250
|
+
}
|
|
13251
|
+
async function listLogs(client, schema, args) {
|
|
13252
|
+
const { mode, filters, pagination, orderBy, after, limit } = storage.listLogsArgsSchema.parse(args);
|
|
13253
|
+
const table = qualifiedTable(schema, TABLE_LOG_EVENTS);
|
|
13254
|
+
if (mode === "delta") {
|
|
13255
|
+
assertDeltaPollingEnabled();
|
|
13256
|
+
return listLogsDelta(client, table, filters, after, limit);
|
|
13257
|
+
}
|
|
13258
|
+
return listLogsPage(client, table, filters, pagination.page, pagination.perPage, orderBy.field, orderBy.direction);
|
|
13259
|
+
}
|
|
13260
|
+
async function listLogsPage(client, table, filters, page, perPage, orderField, orderDir) {
|
|
13261
|
+
return listSignalPage({
|
|
13262
|
+
client,
|
|
13263
|
+
table,
|
|
13264
|
+
filters,
|
|
13265
|
+
page,
|
|
13266
|
+
perPage,
|
|
13267
|
+
orderField,
|
|
13268
|
+
orderDir,
|
|
13269
|
+
includeDeltaCursor: deltaPollingFeatureEnabled(),
|
|
13270
|
+
selectColumns: LOG_SELECT_COLUMNS,
|
|
13271
|
+
responseKey: "logs",
|
|
13272
|
+
applyFilters: applyLogFilters,
|
|
13273
|
+
mapRow: rowToLogRecord
|
|
13274
|
+
});
|
|
13275
|
+
}
|
|
13276
|
+
async function listLogsDelta(client, table, filters, after, limit) {
|
|
13277
|
+
return listSignalDelta({
|
|
13278
|
+
client,
|
|
13279
|
+
table,
|
|
13280
|
+
filters,
|
|
13281
|
+
after,
|
|
13282
|
+
limit,
|
|
13283
|
+
selectColumns: LOG_SELECT_COLUMNS,
|
|
13284
|
+
responseKey: "logs",
|
|
13285
|
+
applyFilters: applyLogFilters,
|
|
13286
|
+
mapRow: rowToLogRecord
|
|
13287
|
+
});
|
|
13288
|
+
}
|
|
13289
|
+
function applyMetricFilters(acc, filters) {
|
|
13290
|
+
applyCommonFilters(acc, filters);
|
|
13291
|
+
applySingleOrArrayFilter(acc, "name", filters?.name);
|
|
13292
|
+
applySingleOrArrayFilter(acc, "provider", filters?.provider);
|
|
13293
|
+
applySingleOrArrayFilter(acc, "model", filters?.model);
|
|
13294
|
+
applySingleOrArrayFilter(acc, "costUnit", filters?.costUnit);
|
|
13295
|
+
if (filters?.labels) {
|
|
13296
|
+
acc.conditions.push(`"labels" @> $${acc.next++}::jsonb`);
|
|
13297
|
+
acc.params.push(JSON.stringify(filters.labels));
|
|
13298
|
+
}
|
|
13299
|
+
}
|
|
13300
|
+
function pushMetricNameFilter(acc, names) {
|
|
13301
|
+
if (!names.length) return;
|
|
13302
|
+
const placeholders = names.map(() => `$${acc.next++}`).join(", ");
|
|
13303
|
+
acc.conditions.push(`"name" IN (${placeholders})`);
|
|
13304
|
+
acc.params.push(...names);
|
|
13305
|
+
}
|
|
13306
|
+
async function batchCreateMetrics(client, schema, args) {
|
|
13307
|
+
if (args.metrics.length === 0) return;
|
|
13308
|
+
const rows = args.metrics.map(metricRecordToRow);
|
|
13309
|
+
const insert = buildInsert(schema, TABLE_METRIC_EVENTS, rows);
|
|
13310
|
+
if (insert) await client.query(insert.text, insert.values);
|
|
13311
|
+
}
|
|
13312
|
+
async function listMetrics(client, schema, args) {
|
|
13313
|
+
const { mode, filters, pagination, orderBy, after, limit } = storage.listMetricsArgsSchema.parse(args);
|
|
13314
|
+
const table = qualifiedTable(schema, TABLE_METRIC_EVENTS);
|
|
13315
|
+
if (mode === "delta") {
|
|
13316
|
+
assertDeltaPollingEnabled();
|
|
13317
|
+
return listMetricsDelta(client, table, filters, after, limit);
|
|
13318
|
+
}
|
|
13319
|
+
return listMetricsPage(client, table, filters, pagination.page, pagination.perPage, orderBy.field, orderBy.direction);
|
|
13320
|
+
}
|
|
13321
|
+
async function listMetricsPage(client, table, filters, page, perPage, orderField, orderDir) {
|
|
13322
|
+
return listSignalPage({
|
|
13323
|
+
client,
|
|
13324
|
+
table,
|
|
13325
|
+
filters,
|
|
13326
|
+
page,
|
|
13327
|
+
perPage,
|
|
13328
|
+
orderField,
|
|
13329
|
+
orderDir,
|
|
13330
|
+
includeDeltaCursor: deltaPollingFeatureEnabled(),
|
|
13331
|
+
selectColumns: METRIC_SELECT_COLUMNS,
|
|
13332
|
+
responseKey: "metrics",
|
|
13333
|
+
applyFilters: applyMetricFilters,
|
|
13334
|
+
mapRow: rowToMetricRecord
|
|
13335
|
+
});
|
|
13336
|
+
}
|
|
13337
|
+
async function listMetricsDelta(client, table, filters, after, limit) {
|
|
13338
|
+
return listSignalDelta({
|
|
13339
|
+
client,
|
|
13340
|
+
table,
|
|
13341
|
+
filters,
|
|
13342
|
+
after,
|
|
13343
|
+
limit,
|
|
13344
|
+
selectColumns: METRIC_SELECT_COLUMNS,
|
|
13345
|
+
responseKey: "metrics",
|
|
13346
|
+
applyFilters: applyMetricFilters,
|
|
13347
|
+
mapRow: rowToMetricRecord
|
|
13348
|
+
});
|
|
13349
|
+
}
|
|
13350
|
+
async function runMetricAggregateQuery(client, schema, filters, names, aggregation, distinctColumn) {
|
|
13351
|
+
const acc = newFilterAccumulator();
|
|
13352
|
+
pushMetricNameFilter(acc, names);
|
|
13353
|
+
applyMetricFilters(acc, filters);
|
|
13354
|
+
const where = whereOrEmpty(acc);
|
|
13355
|
+
const sql = `
|
|
13356
|
+
SELECT ${metricAggregationSql(aggregation, '"value"', "timestamp", distinctColumn)} AS "value",
|
|
13357
|
+
${COST_SUMMARY_SELECT}
|
|
13358
|
+
FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
|
|
13359
|
+
${where}
|
|
13360
|
+
`;
|
|
13361
|
+
const row = await client.oneOrNone(sql, acc.params) ?? {};
|
|
13362
|
+
return {
|
|
13363
|
+
value: row.value == null ? null : Number(row.value),
|
|
13364
|
+
cost: costSummaryFromRow(row)
|
|
13365
|
+
};
|
|
13366
|
+
}
|
|
13367
|
+
async function getMetricAggregate(client, schema, args) {
|
|
13368
|
+
const { value, cost } = await runMetricAggregateQuery(
|
|
13369
|
+
client,
|
|
13370
|
+
schema,
|
|
13371
|
+
args.filters,
|
|
13372
|
+
args.name,
|
|
13373
|
+
args.aggregation,
|
|
13374
|
+
args.distinctColumn
|
|
13375
|
+
);
|
|
13376
|
+
if (args.comparePeriod && args.filters?.timestamp) {
|
|
13377
|
+
const prevRange = shiftRange(args.filters.timestamp, args.comparePeriod);
|
|
13378
|
+
if (prevRange) {
|
|
13379
|
+
const prevFilters = { ...args.filters ?? {}, timestamp: prevRange };
|
|
13380
|
+
const prev = await runMetricAggregateQuery(
|
|
13381
|
+
client,
|
|
13382
|
+
schema,
|
|
13383
|
+
prevFilters,
|
|
13384
|
+
args.name,
|
|
13385
|
+
args.aggregation,
|
|
13386
|
+
args.distinctColumn
|
|
13387
|
+
);
|
|
13388
|
+
return {
|
|
13389
|
+
value,
|
|
13390
|
+
estimatedCost: cost.estimatedCost,
|
|
13391
|
+
costUnit: cost.costUnit,
|
|
13392
|
+
previousValue: prev.value,
|
|
13393
|
+
previousEstimatedCost: prev.cost.estimatedCost,
|
|
13394
|
+
changePercent: changePercent(value, prev.value),
|
|
13395
|
+
costChangePercent: changePercent(cost.estimatedCost, prev.cost.estimatedCost)
|
|
13396
|
+
};
|
|
13397
|
+
}
|
|
13398
|
+
}
|
|
13399
|
+
return { value, estimatedCost: cost.estimatedCost, costUnit: cost.costUnit };
|
|
13400
|
+
}
|
|
13401
|
+
async function getMetricBreakdown(client, schema, args) {
|
|
13402
|
+
const acc = newFilterAccumulator();
|
|
13403
|
+
const resolved = resolveGroupBy(acc, args.groupBy, {
|
|
13404
|
+
typedColumns: METRIC_TYPED_COLUMNS,
|
|
13405
|
+
excludedColumns: COMPLEX_GROUP_BY_EXCLUDED,
|
|
13406
|
+
labelsColumn: "labels"
|
|
13407
|
+
});
|
|
13408
|
+
pushMetricNameFilter(acc, args.name);
|
|
13409
|
+
applyMetricFilters(acc, args.filters);
|
|
13410
|
+
pushLabelExclusions(acc, resolved);
|
|
13411
|
+
const orderDirection = args.orderDirection === "ASC" ? "ASC" : "DESC";
|
|
13412
|
+
const limitClause = args.limit == null ? "" : `LIMIT $${acc.next++}`;
|
|
13413
|
+
if (args.limit != null) acc.params.push(args.limit);
|
|
13414
|
+
const sql = `
|
|
13415
|
+
SELECT ${resolved.map((e) => e.selectSql).join(", ")},
|
|
13416
|
+
${metricAggregationSql(args.aggregation, '"value"', "timestamp", args.distinctColumn)} AS "value",
|
|
13417
|
+
${COST_SUMMARY_SELECT}
|
|
13418
|
+
FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
|
|
13419
|
+
${whereOrEmpty(acc)}
|
|
13420
|
+
GROUP BY ${resolved.map((e) => e.alias).join(", ")}
|
|
13421
|
+
ORDER BY "value" ${orderDirection} NULLS LAST
|
|
13422
|
+
${limitClause}
|
|
13423
|
+
`;
|
|
13424
|
+
const rows = await client.manyOrNone(sql, acc.params);
|
|
13425
|
+
return {
|
|
13426
|
+
groups: rows.map((row) => {
|
|
13427
|
+
const cs = costSummaryFromRow(row);
|
|
13428
|
+
return {
|
|
13429
|
+
dimensions: dimensionsFromRow(row, resolved),
|
|
13430
|
+
value: Number(row.value ?? 0),
|
|
13431
|
+
estimatedCost: cs.estimatedCost,
|
|
13432
|
+
costUnit: cs.costUnit
|
|
13433
|
+
};
|
|
13434
|
+
})
|
|
13435
|
+
};
|
|
13436
|
+
}
|
|
13437
|
+
async function getMetricTimeSeries(client, schema, args) {
|
|
13438
|
+
const bucket = bucketSql('"timestamp"', args.interval);
|
|
13439
|
+
if (args.groupBy && args.groupBy.length > 0) {
|
|
13440
|
+
const acc2 = newFilterAccumulator();
|
|
13441
|
+
const resolved = resolveGroupBy(acc2, args.groupBy, {
|
|
13442
|
+
typedColumns: METRIC_TYPED_COLUMNS,
|
|
13443
|
+
excludedColumns: COMPLEX_GROUP_BY_EXCLUDED,
|
|
13444
|
+
labelsColumn: "labels"
|
|
13445
|
+
});
|
|
13446
|
+
pushMetricNameFilter(acc2, args.name);
|
|
13447
|
+
applyMetricFilters(acc2, args.filters);
|
|
13448
|
+
pushLabelExclusions(acc2, resolved);
|
|
13449
|
+
const sql2 = `
|
|
13450
|
+
SELECT ${bucket} AS bucket,
|
|
13451
|
+
${resolved.map((e) => e.selectSql).join(", ")},
|
|
13452
|
+
${metricAggregationSql(args.aggregation, '"value"', "timestamp", args.distinctColumn)} AS "value",
|
|
13453
|
+
${COST_SUMMARY_SELECT}
|
|
13454
|
+
FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
|
|
13455
|
+
${whereOrEmpty(acc2)}
|
|
13456
|
+
GROUP BY bucket, ${resolved.map((e) => e.alias).join(", ")}
|
|
13457
|
+
ORDER BY bucket
|
|
13458
|
+
`;
|
|
13459
|
+
const rows2 = await client.manyOrNone(sql2, acc2.params);
|
|
13460
|
+
const series = collectSeriesByDimensions(
|
|
13461
|
+
rows2,
|
|
13462
|
+
resolved,
|
|
13463
|
+
(dimValues) => ({
|
|
13464
|
+
name: seriesNameFromDimensions(dimValues),
|
|
13465
|
+
costUnits: /* @__PURE__ */ new Set(),
|
|
13466
|
+
points: []
|
|
13467
|
+
}),
|
|
13468
|
+
(entry, row) => {
|
|
13469
|
+
const cs = costSummaryFromRow(row);
|
|
13470
|
+
if (cs.costUnit) entry.costUnits.add(cs.costUnit);
|
|
13471
|
+
entry.points.push({
|
|
13472
|
+
timestamp: bucketDate(row.bucket),
|
|
13473
|
+
value: Number(row.value ?? 0),
|
|
13474
|
+
estimatedCost: cs.estimatedCost
|
|
13475
|
+
});
|
|
13476
|
+
}
|
|
13477
|
+
).map((s) => ({
|
|
13478
|
+
name: s.name,
|
|
13479
|
+
costUnit: s.costUnits.size === 1 ? Array.from(s.costUnits)[0] : null,
|
|
13480
|
+
points: s.points
|
|
13481
|
+
}));
|
|
13482
|
+
return { series };
|
|
13483
|
+
}
|
|
13484
|
+
const acc = newFilterAccumulator();
|
|
13485
|
+
pushMetricNameFilter(acc, args.name);
|
|
13486
|
+
applyMetricFilters(acc, args.filters);
|
|
13487
|
+
const sql = `
|
|
13488
|
+
SELECT ${bucket} AS bucket,
|
|
13489
|
+
${metricAggregationSql(args.aggregation, '"value"', "timestamp", args.distinctColumn)} AS "value",
|
|
13490
|
+
${COST_SUMMARY_SELECT}
|
|
13491
|
+
FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
|
|
13492
|
+
${whereOrEmpty(acc)}
|
|
13493
|
+
GROUP BY bucket
|
|
13494
|
+
ORDER BY bucket
|
|
13495
|
+
`;
|
|
13496
|
+
const rows = await client.manyOrNone(sql, acc.params);
|
|
13497
|
+
const overallCostUnits = /* @__PURE__ */ new Set();
|
|
13498
|
+
for (const row of rows) {
|
|
13499
|
+
const cs = costSummaryFromRow(row);
|
|
13500
|
+
if (cs.costUnit) overallCostUnits.add(cs.costUnit);
|
|
13501
|
+
}
|
|
13502
|
+
return {
|
|
13503
|
+
series: [
|
|
13504
|
+
{
|
|
13505
|
+
name: args.name.join("|"),
|
|
13506
|
+
costUnit: overallCostUnits.size === 1 ? Array.from(overallCostUnits)[0] : null,
|
|
13507
|
+
points: rows.map((row) => {
|
|
13508
|
+
const cs = costSummaryFromRow(row);
|
|
13509
|
+
return {
|
|
13510
|
+
timestamp: bucketDate(row.bucket),
|
|
13511
|
+
value: Number(row.value ?? 0),
|
|
13512
|
+
estimatedCost: cs.estimatedCost
|
|
13513
|
+
};
|
|
13514
|
+
})
|
|
13515
|
+
}
|
|
13516
|
+
]
|
|
13517
|
+
};
|
|
13518
|
+
}
|
|
13519
|
+
async function getMetricPercentiles(client, schema, args) {
|
|
13520
|
+
validatePercentiles(args.percentiles);
|
|
13521
|
+
const bucket = bucketSql('"timestamp"', args.interval);
|
|
13522
|
+
const acc = newFilterAccumulator();
|
|
13523
|
+
pushMetricNameFilter(acc, [args.name]);
|
|
13524
|
+
applyMetricFilters(acc, args.filters);
|
|
13525
|
+
const percentileSelect = percentileSelectSql(args.percentiles, '"value"');
|
|
13526
|
+
const sql = `
|
|
13527
|
+
SELECT ${bucket} AS bucket, ${percentileSelect}
|
|
13528
|
+
FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
|
|
13529
|
+
${whereOrEmpty(acc)}
|
|
13530
|
+
GROUP BY bucket
|
|
13531
|
+
ORDER BY bucket
|
|
13532
|
+
`;
|
|
13533
|
+
const rows = await client.manyOrNone(sql, acc.params);
|
|
13534
|
+
return { series: percentileSeriesFromRows(rows, args.percentiles) };
|
|
13535
|
+
}
|
|
13536
|
+
|
|
13537
|
+
// src/storage/domains/observability/v-next/pg-errors.ts
|
|
13538
|
+
function asPgError(error) {
|
|
13539
|
+
return error ?? {};
|
|
13540
|
+
}
|
|
13541
|
+
function isDuplicateRelationError(error) {
|
|
13542
|
+
const { code, constraint, message = "" } = asPgError(error);
|
|
13543
|
+
if (code === "42P07") return true;
|
|
13544
|
+
if (code === "23505" && (constraint === "pg_type_typname_nsp_index" || constraint === "pg_class_relname_nsp_index")) {
|
|
13545
|
+
return true;
|
|
13546
|
+
}
|
|
13547
|
+
return /already exists/i.test(message);
|
|
13548
|
+
}
|
|
13549
|
+
function isDuplicateSchemaError(error) {
|
|
13550
|
+
const { code, constraint, message = "" } = asPgError(error);
|
|
13551
|
+
if (code === "42P06") return true;
|
|
13552
|
+
if (code === "23505" && constraint === "pg_namespace_nspname_index") return true;
|
|
13553
|
+
return /schema .* already exists/i.test(message);
|
|
13554
|
+
}
|
|
13555
|
+
|
|
13556
|
+
// src/storage/domains/observability/v-next/partitioning.ts
|
|
13557
|
+
var DEFAULT_FUTURE_DAYS = 14;
|
|
13558
|
+
async function detectTimescale(client) {
|
|
13559
|
+
const row = await client.oneOrNone(
|
|
13560
|
+
`SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'timescaledb') AS "exists"`
|
|
13561
|
+
);
|
|
13562
|
+
return Boolean(row?.exists);
|
|
13563
|
+
}
|
|
13564
|
+
async function detectPartman(client) {
|
|
13565
|
+
const row = await client.oneOrNone(
|
|
13566
|
+
`SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pg_partman') AS "exists"`
|
|
13567
|
+
);
|
|
13568
|
+
return Boolean(row?.exists);
|
|
13569
|
+
}
|
|
13570
|
+
async function getPartmanVersion(client) {
|
|
13571
|
+
const row = await client.oneOrNone(
|
|
13572
|
+
`SELECT extversion FROM pg_extension WHERE extname = 'pg_partman'`
|
|
13573
|
+
);
|
|
13574
|
+
return row?.extversion ?? null;
|
|
13575
|
+
}
|
|
13576
|
+
function getPartmanMajor(version) {
|
|
13577
|
+
if (!version) return null;
|
|
13578
|
+
const match = /^(\d+)/.exec(version);
|
|
13579
|
+
return match ? Number(match[1]) : null;
|
|
13580
|
+
}
|
|
13581
|
+
async function resolveMode(client, options = {}) {
|
|
13582
|
+
if (options.mode && options.mode !== "auto") return options.mode;
|
|
13583
|
+
if (await detectTimescale(client)) return "timescale";
|
|
13584
|
+
if (await detectPartman(client)) return "partman";
|
|
13585
|
+
return "native";
|
|
13586
|
+
}
|
|
13587
|
+
function dayBounds(d) {
|
|
13588
|
+
const year = d.getUTCFullYear();
|
|
13589
|
+
const month = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
13590
|
+
const day = String(d.getUTCDate()).padStart(2, "0");
|
|
13591
|
+
const start = `${year}-${month}-${day} 00:00:00+00`;
|
|
13592
|
+
const next = new Date(Date.UTC(year, d.getUTCMonth(), d.getUTCDate() + 1));
|
|
13593
|
+
const ny = next.getUTCFullYear();
|
|
13594
|
+
const nm = String(next.getUTCMonth() + 1).padStart(2, "0");
|
|
13595
|
+
const nd = String(next.getUTCDate()).padStart(2, "0");
|
|
13596
|
+
const end = `${ny}-${nm}-${nd} 00:00:00+00`;
|
|
13597
|
+
return { start, end, suffix: `${year}${month}${day}` };
|
|
13598
|
+
}
|
|
13599
|
+
function partitionName(table, suffix) {
|
|
13600
|
+
return `${table}_p${suffix}`;
|
|
13601
|
+
}
|
|
13602
|
+
async function ensureNativePartitions(client, schema, options = {}) {
|
|
13603
|
+
const futureDays = options.futureDays ?? DEFAULT_FUTURE_DAYS;
|
|
13604
|
+
const includeYesterday = options.includeYesterday ?? true;
|
|
13605
|
+
const start = includeYesterday ? -1 : 0;
|
|
13606
|
+
const baseNowMs = Date.now();
|
|
13607
|
+
for (const table of ALL_SIGNAL_TABLES) {
|
|
13608
|
+
for (let i = start; i <= futureDays; i++) {
|
|
13609
|
+
const d = new Date(baseNowMs + i * 864e5);
|
|
13610
|
+
const { start: partStart, end: partEnd, suffix } = dayBounds(d);
|
|
13611
|
+
const childName = partitionName(table, suffix);
|
|
13612
|
+
const child = qualifiedName(schema, childName);
|
|
13613
|
+
const parent = qualifiedTable(schema, table);
|
|
13614
|
+
try {
|
|
13615
|
+
await client.none(`CREATE TABLE IF NOT EXISTS ${child} (LIKE ${parent} INCLUDING ALL)`);
|
|
13616
|
+
} catch (error) {
|
|
13617
|
+
if (!isDuplicateRelationError(error)) throw error;
|
|
13618
|
+
}
|
|
13619
|
+
try {
|
|
13620
|
+
await client.none(
|
|
13621
|
+
`ALTER TABLE ${parent} ATTACH PARTITION ${child}
|
|
13622
|
+
FOR VALUES FROM ('${partStart}') TO ('${partEnd}')`
|
|
13623
|
+
);
|
|
13624
|
+
} catch (error) {
|
|
13625
|
+
if (!isAlreadyAttachedError(error)) throw error;
|
|
13626
|
+
}
|
|
13627
|
+
}
|
|
13628
|
+
}
|
|
13629
|
+
}
|
|
13630
|
+
function isAlreadyAttachedError(error) {
|
|
13631
|
+
const code = error?.code;
|
|
13632
|
+
const message = error?.message ?? "";
|
|
13633
|
+
if (code === "42P17" || code === "42710") {
|
|
13634
|
+
return /is already a partition/i.test(message) || /already a partition/i.test(message);
|
|
13635
|
+
}
|
|
13636
|
+
return /is already a partition/i.test(message);
|
|
13637
|
+
}
|
|
13638
|
+
async function ensureTimescaleHypertables(client, schema) {
|
|
13639
|
+
for (const table of ALL_SIGNAL_TABLES) {
|
|
13640
|
+
const tableExpr = qualifiedTable(schema, table);
|
|
13641
|
+
const timeColumn = SIGNAL_TIME_COLUMN[table].replace(/'/g, "''");
|
|
13642
|
+
await client.none(
|
|
13643
|
+
`SELECT create_hypertable($1::regclass, '${timeColumn}', chunk_time_interval => INTERVAL '1 day', if_not_exists => true)`,
|
|
13644
|
+
[tableExpr]
|
|
13645
|
+
);
|
|
13646
|
+
}
|
|
13647
|
+
}
|
|
13648
|
+
async function ensurePartmanHypertables(client, schema) {
|
|
13649
|
+
const partmanMajor = getPartmanMajor(await getPartmanVersion(client));
|
|
13650
|
+
for (const table of ALL_SIGNAL_TABLES) {
|
|
13651
|
+
const exists = await client.oneOrNone(
|
|
13652
|
+
`SELECT EXISTS (
|
|
13653
|
+
SELECT 1 FROM partman.part_config
|
|
13654
|
+
WHERE parent_table = format('%I.%I', $1::text, $2::text)
|
|
13655
|
+
) AS "exists"`,
|
|
13656
|
+
[schema, table]
|
|
13657
|
+
);
|
|
13658
|
+
if (exists?.exists) continue;
|
|
13659
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
13660
|
+
try {
|
|
13661
|
+
if (partmanMajor != null && partmanMajor >= 5) {
|
|
13662
|
+
await client.none(
|
|
13663
|
+
`SELECT partman.create_parent(
|
|
13664
|
+
p_parent_table := format('%I.%I', $1::text, $2::text),
|
|
13665
|
+
p_control := $3,
|
|
13666
|
+
p_interval := '1 day',
|
|
13667
|
+
p_type := 'range'
|
|
13668
|
+
)`,
|
|
13669
|
+
[schema, table, SIGNAL_TIME_COLUMN[table]]
|
|
13670
|
+
);
|
|
13671
|
+
} else {
|
|
13672
|
+
await client.none(
|
|
13673
|
+
`SELECT partman.create_parent(
|
|
13674
|
+
p_parent_table := format('%I.%I', $1::text, $2::text),
|
|
13675
|
+
p_control := $3,
|
|
13676
|
+
p_type := 'native',
|
|
13677
|
+
p_interval := '1 day'
|
|
13678
|
+
)`,
|
|
13679
|
+
[schema, table, SIGNAL_TIME_COLUMN[table]]
|
|
13680
|
+
);
|
|
13681
|
+
}
|
|
13682
|
+
break;
|
|
13683
|
+
} catch (error) {
|
|
13684
|
+
const message = error?.message ?? "";
|
|
13685
|
+
const code = error?.code;
|
|
13686
|
+
const isDuplicate = code === "23505" || /already managed by pg_partman/i.test(message) || /relation .* already exists/i.test(message);
|
|
13687
|
+
if (isDuplicate) break;
|
|
13688
|
+
const isDeadlock = /deadlock detected/i.test(message);
|
|
13689
|
+
if (!isDeadlock) throw error;
|
|
13690
|
+
const registered = await client.oneOrNone(
|
|
13691
|
+
`SELECT EXISTS (
|
|
13692
|
+
SELECT 1 FROM partman.part_config
|
|
13693
|
+
WHERE parent_table = format('%I.%I', $1::text, $2::text)
|
|
13694
|
+
) AS "exists"`,
|
|
13695
|
+
[schema, table]
|
|
13696
|
+
);
|
|
13697
|
+
if (registered?.exists) break;
|
|
13698
|
+
if (attempt === 2) throw error;
|
|
13699
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
13700
|
+
}
|
|
13701
|
+
}
|
|
13702
|
+
}
|
|
13703
|
+
}
|
|
13704
|
+
async function setupPartitioning(client, schema, options = {}) {
|
|
13705
|
+
const mode = await resolveMode(client, options);
|
|
13706
|
+
switch (mode) {
|
|
13707
|
+
case "timescale":
|
|
13708
|
+
await ensureTimescaleHypertables(client, schema);
|
|
13709
|
+
return "timescale";
|
|
13710
|
+
case "partman":
|
|
13711
|
+
await ensurePartmanHypertables(client, schema);
|
|
13712
|
+
return "partman";
|
|
13713
|
+
case "native":
|
|
13714
|
+
await ensureNativePartitions(client, schema, options);
|
|
13715
|
+
return "native";
|
|
13716
|
+
}
|
|
13717
|
+
}
|
|
13718
|
+
function applyScoreFilters(acc, filters) {
|
|
13719
|
+
applyCommonFilters(acc, filters);
|
|
13720
|
+
applySingleOrArrayFilter(acc, "scorerId", filters?.scorerId);
|
|
13721
|
+
if (filters?.scoreSource ?? filters?.source) {
|
|
13722
|
+
acc.conditions.push(`"scoreSource" = $${acc.next++}`);
|
|
13723
|
+
acc.params.push(filters.scoreSource ?? filters.source);
|
|
13724
|
+
}
|
|
13725
|
+
}
|
|
13726
|
+
function pushScoreIdentity(acc, scorerId, scoreSource) {
|
|
13727
|
+
acc.conditions.push(`"scorerId" = $${acc.next++}`);
|
|
13728
|
+
acc.params.push(scorerId);
|
|
13729
|
+
if (scoreSource !== void 0) {
|
|
13730
|
+
acc.conditions.push(`"scoreSource" = $${acc.next++}`);
|
|
13731
|
+
acc.params.push(scoreSource);
|
|
13732
|
+
}
|
|
13733
|
+
}
|
|
13734
|
+
async function createScore(client, schema, args) {
|
|
13735
|
+
const row = scoreRecordToRow(args.score);
|
|
13736
|
+
const insert = buildInsert(schema, TABLE_SCORE_EVENTS, [row]);
|
|
13737
|
+
if (insert) await client.query(insert.text, insert.values);
|
|
13738
|
+
}
|
|
13739
|
+
async function batchCreateScores(client, schema, args) {
|
|
13740
|
+
if (args.scores.length === 0) return;
|
|
13741
|
+
const rows = args.scores.map(scoreRecordToRow);
|
|
13742
|
+
const insert = buildInsert(schema, TABLE_SCORE_EVENTS, rows);
|
|
13743
|
+
if (insert) await client.query(insert.text, insert.values);
|
|
13744
|
+
}
|
|
13745
|
+
async function listScores(client, schema, args) {
|
|
13746
|
+
const { mode, filters, pagination, orderBy, after, limit } = storage.listScoresArgsSchema.parse(args);
|
|
13747
|
+
const table = qualifiedTable(schema, TABLE_SCORE_EVENTS);
|
|
13748
|
+
if (mode === "delta") {
|
|
13749
|
+
assertDeltaPollingEnabled();
|
|
13750
|
+
return listScoresDelta(client, table, filters, after, limit);
|
|
13751
|
+
}
|
|
13752
|
+
return listScoresPage(client, table, filters, pagination.page, pagination.perPage, orderBy.field, orderBy.direction);
|
|
13753
|
+
}
|
|
13754
|
+
async function getScoreById(client, schema, scoreId) {
|
|
13755
|
+
const row = await client.oneOrNone(
|
|
13756
|
+
`SELECT ${SCORE_SELECT_COLUMNS}
|
|
13757
|
+
FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
|
|
13758
|
+
WHERE "scoreId" = $1
|
|
13759
|
+
ORDER BY "timestamp" DESC
|
|
13760
|
+
LIMIT 1`,
|
|
13761
|
+
[scoreId]
|
|
13762
|
+
);
|
|
13763
|
+
return row ? rowToScoreRecord(row) : null;
|
|
13764
|
+
}
|
|
13765
|
+
async function listScoresPage(client, table, filters, page, perPage, orderField, orderDir) {
|
|
13766
|
+
return listSignalPage({
|
|
13767
|
+
client,
|
|
13768
|
+
table,
|
|
13769
|
+
filters,
|
|
13770
|
+
page,
|
|
13771
|
+
perPage,
|
|
13772
|
+
orderField,
|
|
13773
|
+
orderDir,
|
|
13774
|
+
includeDeltaCursor: deltaPollingFeatureEnabled(),
|
|
13775
|
+
selectColumns: SCORE_SELECT_COLUMNS,
|
|
13776
|
+
responseKey: "scores",
|
|
13777
|
+
applyFilters: applyScoreFilters,
|
|
13778
|
+
mapRow: rowToScoreRecord
|
|
13779
|
+
});
|
|
13780
|
+
}
|
|
13781
|
+
async function listScoresDelta(client, table, filters, after, limit) {
|
|
13782
|
+
return listSignalDelta({
|
|
13783
|
+
client,
|
|
13784
|
+
table,
|
|
13785
|
+
filters,
|
|
13786
|
+
after,
|
|
13787
|
+
limit,
|
|
13788
|
+
selectColumns: SCORE_SELECT_COLUMNS,
|
|
13789
|
+
responseKey: "scores",
|
|
13790
|
+
applyFilters: applyScoreFilters,
|
|
13791
|
+
mapRow: rowToScoreRecord
|
|
13792
|
+
});
|
|
13793
|
+
}
|
|
13794
|
+
async function runScoreAggregateQuery(client, schema, args, filters) {
|
|
13795
|
+
const acc = newFilterAccumulator();
|
|
13796
|
+
pushScoreIdentity(acc, args.scorerId, args.scoreSource);
|
|
13797
|
+
applyScoreFilters(acc, filters);
|
|
13798
|
+
const sql = `
|
|
13799
|
+
SELECT ${aggregationSql(args.aggregation, '"score"')} AS "value"
|
|
13800
|
+
FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
|
|
13801
|
+
${whereOrEmpty(acc)}
|
|
13802
|
+
`;
|
|
13803
|
+
const row = await client.oneOrNone(sql, acc.params);
|
|
13804
|
+
return row?.value == null ? null : Number(row.value);
|
|
13805
|
+
}
|
|
13806
|
+
async function getScoreAggregate(client, schema, args) {
|
|
13807
|
+
const value = await runScoreAggregateQuery(client, schema, args, args.filters);
|
|
13808
|
+
if (args.comparePeriod && args.filters?.timestamp) {
|
|
13809
|
+
const prevRange = shiftRange(args.filters.timestamp, args.comparePeriod);
|
|
13810
|
+
if (prevRange) {
|
|
13811
|
+
const previousValue = await runScoreAggregateQuery(client, schema, args, {
|
|
13812
|
+
...args.filters ?? {},
|
|
13813
|
+
timestamp: prevRange
|
|
13814
|
+
});
|
|
13815
|
+
return {
|
|
13816
|
+
value,
|
|
13817
|
+
previousValue,
|
|
13818
|
+
changePercent: changePercent(value, previousValue)
|
|
13819
|
+
};
|
|
13820
|
+
}
|
|
13821
|
+
}
|
|
13822
|
+
return { value };
|
|
13823
|
+
}
|
|
13824
|
+
async function getScoreBreakdown(client, schema, args) {
|
|
13825
|
+
const acc = newFilterAccumulator();
|
|
13826
|
+
const resolved = resolveGroupBy(acc, args.groupBy, {
|
|
13827
|
+
typedColumns: SCORE_TYPED_COLUMNS,
|
|
13828
|
+
excludedColumns: COMPLEX_GROUP_BY_EXCLUDED
|
|
13829
|
+
});
|
|
13830
|
+
pushScoreIdentity(acc, args.scorerId, args.scoreSource);
|
|
13831
|
+
applyScoreFilters(acc, args.filters);
|
|
13832
|
+
const sql = `
|
|
13833
|
+
SELECT ${resolved.map((e) => e.selectSql).join(", ")},
|
|
13834
|
+
${aggregationSql(args.aggregation, '"score"')} AS "value"
|
|
13835
|
+
FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
|
|
13836
|
+
${whereOrEmpty(acc)}
|
|
13837
|
+
GROUP BY ${resolved.map((e) => e.alias).join(", ")}
|
|
13838
|
+
ORDER BY "value" DESC NULLS LAST
|
|
13839
|
+
`;
|
|
13840
|
+
const rows = await client.manyOrNone(sql, acc.params);
|
|
13841
|
+
return {
|
|
13842
|
+
groups: rows.map((row) => ({
|
|
13843
|
+
dimensions: dimensionsFromRow(row, resolved),
|
|
13844
|
+
value: Number(row.value ?? 0)
|
|
13845
|
+
}))
|
|
13846
|
+
};
|
|
13847
|
+
}
|
|
13848
|
+
async function getScoreTimeSeries(client, schema, args) {
|
|
13849
|
+
const bucket = bucketSql('"timestamp"', args.interval);
|
|
13850
|
+
if (args.groupBy && args.groupBy.length > 0) {
|
|
13851
|
+
const acc2 = newFilterAccumulator();
|
|
13852
|
+
const resolved = resolveGroupBy(acc2, args.groupBy, {
|
|
13853
|
+
typedColumns: SCORE_TYPED_COLUMNS,
|
|
13854
|
+
excludedColumns: COMPLEX_GROUP_BY_EXCLUDED
|
|
13855
|
+
});
|
|
13856
|
+
pushScoreIdentity(acc2, args.scorerId, args.scoreSource);
|
|
13857
|
+
applyScoreFilters(acc2, args.filters);
|
|
13858
|
+
const sql2 = `
|
|
13859
|
+
SELECT ${bucket} AS bucket,
|
|
13860
|
+
${resolved.map((e) => e.selectSql).join(", ")},
|
|
13861
|
+
${aggregationSql(args.aggregation, '"score"')} AS "value"
|
|
13862
|
+
FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
|
|
13863
|
+
${whereOrEmpty(acc2)}
|
|
13864
|
+
GROUP BY bucket, ${resolved.map((e) => e.alias).join(", ")}
|
|
13865
|
+
ORDER BY bucket
|
|
13866
|
+
`;
|
|
13867
|
+
const rows2 = await client.manyOrNone(sql2, acc2.params);
|
|
13868
|
+
return {
|
|
13869
|
+
series: collectSeriesByDimensions(
|
|
13870
|
+
rows2,
|
|
13871
|
+
resolved,
|
|
13872
|
+
(dimValues) => ({
|
|
13873
|
+
name: seriesNameFromDimensions(dimValues),
|
|
13874
|
+
points: []
|
|
13875
|
+
}),
|
|
13876
|
+
(entry, row) => {
|
|
13877
|
+
entry.points.push({
|
|
13878
|
+
timestamp: bucketDate(row.bucket),
|
|
13879
|
+
value: Number(row.value ?? 0)
|
|
13880
|
+
});
|
|
13881
|
+
}
|
|
13882
|
+
)
|
|
13883
|
+
};
|
|
13884
|
+
}
|
|
13885
|
+
const acc = newFilterAccumulator();
|
|
13886
|
+
pushScoreIdentity(acc, args.scorerId, args.scoreSource);
|
|
13887
|
+
applyScoreFilters(acc, args.filters);
|
|
13888
|
+
const sql = `
|
|
13889
|
+
SELECT ${bucket} AS bucket,
|
|
13890
|
+
${aggregationSql(args.aggregation, '"score"')} AS "value"
|
|
13891
|
+
FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
|
|
13892
|
+
${whereOrEmpty(acc)}
|
|
13893
|
+
GROUP BY bucket
|
|
13894
|
+
ORDER BY bucket
|
|
13895
|
+
`;
|
|
13896
|
+
const rows = await client.manyOrNone(sql, acc.params);
|
|
13897
|
+
const seriesName = args.scoreSource ? `${args.scorerId}|${args.scoreSource}` : args.scorerId;
|
|
13898
|
+
return {
|
|
13899
|
+
series: [
|
|
13900
|
+
{
|
|
13901
|
+
name: seriesName,
|
|
13902
|
+
points: rows.map((row) => ({
|
|
13903
|
+
timestamp: bucketDate(row.bucket),
|
|
13904
|
+
value: Number(row.value ?? 0)
|
|
13905
|
+
}))
|
|
13906
|
+
}
|
|
13907
|
+
]
|
|
13908
|
+
};
|
|
13909
|
+
}
|
|
13910
|
+
async function getScorePercentiles(client, schema, args) {
|
|
13911
|
+
validatePercentiles(args.percentiles);
|
|
13912
|
+
const bucket = bucketSql('"timestamp"', args.interval);
|
|
13913
|
+
const acc = newFilterAccumulator();
|
|
13914
|
+
pushScoreIdentity(acc, args.scorerId, args.scoreSource);
|
|
13915
|
+
applyScoreFilters(acc, args.filters);
|
|
13916
|
+
const percentileSelect = percentileSelectSql(args.percentiles, '"score"');
|
|
13917
|
+
const sql = `
|
|
13918
|
+
SELECT ${bucket} AS bucket, ${percentileSelect}
|
|
13919
|
+
FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
|
|
13920
|
+
${whereOrEmpty(acc)}
|
|
13921
|
+
GROUP BY bucket
|
|
13922
|
+
ORDER BY bucket
|
|
13923
|
+
`;
|
|
13924
|
+
const rows = await client.manyOrNone(sql, acc.params);
|
|
13925
|
+
return { series: percentileSeriesFromRows(rows, args.percentiles) };
|
|
13926
|
+
}
|
|
13927
|
+
function asIsoTimestamp(value) {
|
|
13928
|
+
return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
|
|
13929
|
+
}
|
|
13930
|
+
async function getRootSpan(client, schema, args) {
|
|
13931
|
+
const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
13932
|
+
const row = await client.oneOrNone(
|
|
13933
|
+
`SELECT ${SPAN_SELECT_COLUMNS}
|
|
13934
|
+
FROM ${table}
|
|
13935
|
+
WHERE "traceId" = $1 AND "parentSpanId" IS NULL
|
|
13936
|
+
ORDER BY "endedAt" DESC
|
|
13937
|
+
LIMIT 1`,
|
|
13938
|
+
[args.traceId]
|
|
13939
|
+
);
|
|
13940
|
+
if (!row) return null;
|
|
13941
|
+
return { span: rowToSpanRecord(row) };
|
|
13942
|
+
}
|
|
13943
|
+
function buildListTracesFilters(filters, spanTable, nextParamIdx) {
|
|
13944
|
+
const conditions = [`r."parentSpanId" IS NULL`];
|
|
13945
|
+
const params = [];
|
|
13946
|
+
let i = nextParamIdx;
|
|
13947
|
+
if (!filters) {
|
|
13948
|
+
return { conditions, params, nextParamIdx: i };
|
|
13949
|
+
}
|
|
13950
|
+
if (filters.startedAt?.start) {
|
|
13951
|
+
conditions.push(`r."startedAt" ${filters.startedAt.startExclusive ? ">" : ">="} $${i++}`);
|
|
13952
|
+
params.push(asIsoTimestamp(filters.startedAt.start));
|
|
13953
|
+
}
|
|
13954
|
+
if (filters.startedAt?.end) {
|
|
13955
|
+
conditions.push(`r."startedAt" ${filters.startedAt.endExclusive ? "<" : "<="} $${i++}`);
|
|
13956
|
+
params.push(asIsoTimestamp(filters.startedAt.end));
|
|
13957
|
+
}
|
|
13958
|
+
if (filters.endedAt?.start) {
|
|
13959
|
+
conditions.push(`r."endedAt" ${filters.endedAt.startExclusive ? ">" : ">="} $${i++}`);
|
|
13960
|
+
params.push(asIsoTimestamp(filters.endedAt.start));
|
|
13961
|
+
}
|
|
13962
|
+
if (filters.endedAt?.end) {
|
|
13963
|
+
conditions.push(`r."endedAt" ${filters.endedAt.endExclusive ? "<" : "<="} $${i++}`);
|
|
13964
|
+
params.push(asIsoTimestamp(filters.endedAt.end));
|
|
13965
|
+
}
|
|
13966
|
+
if (filters.spanType !== void 0) {
|
|
13967
|
+
conditions.push(`r."spanType" = $${i++}`);
|
|
13968
|
+
params.push(filters.spanType);
|
|
13969
|
+
}
|
|
13970
|
+
if (filters.entityType !== void 0) {
|
|
13971
|
+
conditions.push(`r."entityType" = $${i++}`);
|
|
13972
|
+
params.push(filters.entityType);
|
|
13973
|
+
}
|
|
13974
|
+
if (filters.entityId !== void 0) {
|
|
13975
|
+
conditions.push(`r."entityId" = $${i++}`);
|
|
13976
|
+
params.push(filters.entityId);
|
|
13977
|
+
}
|
|
13978
|
+
if (filters.entityName !== void 0) {
|
|
13979
|
+
conditions.push(`r."entityName" = $${i++}`);
|
|
13980
|
+
params.push(filters.entityName);
|
|
13981
|
+
}
|
|
13982
|
+
if (filters.userId !== void 0) {
|
|
13983
|
+
conditions.push(`r."userId" = $${i++}`);
|
|
13984
|
+
params.push(filters.userId);
|
|
13985
|
+
}
|
|
13986
|
+
if (filters.organizationId !== void 0) {
|
|
13987
|
+
conditions.push(`r."organizationId" = $${i++}`);
|
|
13988
|
+
params.push(filters.organizationId);
|
|
13989
|
+
}
|
|
13990
|
+
if (filters.resourceId !== void 0) {
|
|
13991
|
+
conditions.push(`r."resourceId" = $${i++}`);
|
|
13992
|
+
params.push(filters.resourceId);
|
|
13993
|
+
}
|
|
13994
|
+
if (filters.runId !== void 0) {
|
|
13995
|
+
conditions.push(`r."runId" = $${i++}`);
|
|
13996
|
+
params.push(filters.runId);
|
|
13997
|
+
}
|
|
13998
|
+
if (filters.sessionId !== void 0) {
|
|
13999
|
+
conditions.push(`r."sessionId" = $${i++}`);
|
|
14000
|
+
params.push(filters.sessionId);
|
|
14001
|
+
}
|
|
14002
|
+
if (filters.threadId !== void 0) {
|
|
14003
|
+
conditions.push(`r."threadId" = $${i++}`);
|
|
14004
|
+
params.push(filters.threadId);
|
|
14005
|
+
}
|
|
14006
|
+
if (filters.requestId !== void 0) {
|
|
14007
|
+
conditions.push(`r."requestId" = $${i++}`);
|
|
14008
|
+
params.push(filters.requestId);
|
|
14009
|
+
}
|
|
14010
|
+
if (filters.environment !== void 0) {
|
|
14011
|
+
conditions.push(`r."environment" = $${i++}`);
|
|
14012
|
+
params.push(filters.environment);
|
|
14013
|
+
}
|
|
14014
|
+
if (filters.source !== void 0) {
|
|
14015
|
+
conditions.push(`r."executionSource" = $${i++}`);
|
|
14016
|
+
params.push(filters.source);
|
|
14017
|
+
}
|
|
14018
|
+
if (filters.serviceName !== void 0) {
|
|
14019
|
+
conditions.push(`r."serviceName" = $${i++}`);
|
|
14020
|
+
params.push(filters.serviceName);
|
|
14021
|
+
}
|
|
14022
|
+
if (filters.metadata != null) {
|
|
14023
|
+
conditions.push(`r."metadataSearch" @> $${i++}::jsonb`);
|
|
14024
|
+
params.push(JSON.stringify(filters.metadata));
|
|
14025
|
+
}
|
|
14026
|
+
if (filters.tags != null && filters.tags.length > 0) {
|
|
14027
|
+
conditions.push(`r."tags" @> $${i++}::text[]`);
|
|
14028
|
+
params.push(filters.tags);
|
|
14029
|
+
}
|
|
14030
|
+
if (filters.status !== void 0) {
|
|
14031
|
+
switch (filters.status) {
|
|
14032
|
+
case storage.TraceStatus.ERROR:
|
|
14033
|
+
conditions.push(`r."error" IS NOT NULL`);
|
|
14034
|
+
break;
|
|
14035
|
+
case storage.TraceStatus.RUNNING:
|
|
14036
|
+
conditions.push(`FALSE`);
|
|
14037
|
+
break;
|
|
14038
|
+
case storage.TraceStatus.SUCCESS:
|
|
14039
|
+
conditions.push(`r."error" IS NULL`);
|
|
14040
|
+
break;
|
|
14041
|
+
}
|
|
14042
|
+
}
|
|
14043
|
+
if (filters.hasChildError !== void 0) {
|
|
14044
|
+
const sub = `EXISTS (
|
|
14045
|
+
SELECT 1 FROM ${spanTable} c
|
|
14046
|
+
WHERE c."traceId" = r."traceId" AND c."spanId" <> r."spanId" AND c."error" IS NOT NULL
|
|
14047
|
+
)`;
|
|
14048
|
+
conditions.push(filters.hasChildError ? sub : `NOT ${sub}`);
|
|
14049
|
+
}
|
|
14050
|
+
return { conditions, params, nextParamIdx: i };
|
|
14051
|
+
}
|
|
14052
|
+
var SPAN_SELECT_COLUMNS_ALIASED = SPAN_SELECT_COLUMNS.replace(/\n/g, " ").split(",").map((c) => `r.${c.trim()}`).join(", ");
|
|
14053
|
+
async function listTraces(client, schema, args) {
|
|
14054
|
+
const { mode, filters, pagination, orderBy, after, limit } = storage.listTracesArgsSchema.parse(args);
|
|
14055
|
+
const span = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
14056
|
+
if (mode === "delta") {
|
|
14057
|
+
assertDeltaPollingEnabled();
|
|
14058
|
+
return listTracesDelta(client, span, filters, after, limit);
|
|
14059
|
+
}
|
|
14060
|
+
return listTracesPage(client, span, filters, pagination.page, pagination.perPage, orderBy.field, orderBy.direction);
|
|
14061
|
+
}
|
|
14062
|
+
async function listTracesPage(client, span, filters, page, perPage, orderField, orderDir) {
|
|
14063
|
+
const { conditions, params, nextParamIdx } = buildListTracesFilters(filters, span, 1);
|
|
14064
|
+
let i = nextParamIdx;
|
|
14065
|
+
const whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
14066
|
+
const orderClause = orderField === "endedAt" ? `ORDER BY r."endedAt" ${orderDir} NULLS ${orderDir === "DESC" ? "FIRST" : "LAST"}, r."cursorId" ${orderDir}` : `ORDER BY r."${orderField}" ${orderDir}, r."cursorId" ${orderDir}`;
|
|
14067
|
+
const countRow = await client.oneOrNone(
|
|
14068
|
+
`SELECT COUNT(*)::text AS count FROM ${span} r ${whereClause}`,
|
|
14069
|
+
params
|
|
14070
|
+
);
|
|
14071
|
+
const count = Number(countRow?.count ?? 0);
|
|
14072
|
+
let spans = [];
|
|
14073
|
+
if (count > 0) {
|
|
14074
|
+
const rows = await client.manyOrNone(
|
|
14075
|
+
`SELECT ${SPAN_SELECT_COLUMNS_ALIASED}
|
|
14076
|
+
FROM ${span} r
|
|
14077
|
+
${whereClause}
|
|
14078
|
+
${orderClause}
|
|
14079
|
+
LIMIT $${i++} OFFSET $${i++}`,
|
|
14080
|
+
[...params, perPage, page * perPage]
|
|
14081
|
+
);
|
|
14082
|
+
spans = rows.map(rowToSpanRecord);
|
|
14083
|
+
}
|
|
14084
|
+
const deltaCursor = deltaPollingFeatureEnabled() ? await readTracesStreamHeadCursor(client) : void 0;
|
|
14085
|
+
return {
|
|
14086
|
+
pagination: { total: count, page, perPage, hasMore: (page + 1) * perPage < count },
|
|
14087
|
+
spans: storage.toTraceSpans(spans),
|
|
14088
|
+
...deltaCursor !== void 0 ? { deltaCursor } : {}
|
|
14089
|
+
};
|
|
14090
|
+
}
|
|
14091
|
+
async function listTracesDelta(client, span, filters, after, limit) {
|
|
14092
|
+
if (after === void 0) {
|
|
14093
|
+
const deltaCursor2 = await readTracesStreamHeadCursor(client);
|
|
14094
|
+
return { spans: [], delta: { limit, hasMore: false }, deltaCursor: deltaCursor2 };
|
|
14095
|
+
}
|
|
14096
|
+
const afterCursor = decodeDeltaCursor(after);
|
|
14097
|
+
const safeHorizon = await readSafeXactHorizon(client);
|
|
14098
|
+
const { conditions, params, nextParamIdx } = buildListTracesFilters(filters, span, 1);
|
|
14099
|
+
let i = nextParamIdx;
|
|
14100
|
+
conditions.push(`(r."xactId", r."cursorId") > ($${i++}::xid8, $${i++}::bigint)`);
|
|
14101
|
+
params.push(afterCursor.xactId, afterCursor.cursorId);
|
|
14102
|
+
conditions.push(`r."xactId" < $${i++}::xid8`);
|
|
14103
|
+
params.push(safeHorizon);
|
|
14104
|
+
const rows = await client.manyOrNone(
|
|
14105
|
+
`SELECT ${SPAN_SELECT_COLUMNS_ALIASED}
|
|
14106
|
+
FROM ${span} r
|
|
14107
|
+
WHERE ${conditions.join(" AND ")}
|
|
14108
|
+
ORDER BY r."xactId" ASC, r."cursorId" ASC
|
|
14109
|
+
LIMIT $${i++}`,
|
|
14110
|
+
[...params, limit + 1]
|
|
14111
|
+
);
|
|
14112
|
+
const hasMore = rows.length > limit;
|
|
14113
|
+
const visible = rows.slice(0, limit);
|
|
14114
|
+
const deltaCursor = visible.length > 0 ? encodeDeltaCursor(visible[visible.length - 1].xactId, visible[visible.length - 1].cursorId) : encodeDeltaCursor(safeHorizon, 0);
|
|
14115
|
+
return {
|
|
14116
|
+
spans: storage.toTraceSpans(visible.map(rowToSpanRecord)),
|
|
14117
|
+
delta: { limit, hasMore },
|
|
14118
|
+
deltaCursor
|
|
14119
|
+
};
|
|
14120
|
+
}
|
|
14121
|
+
async function readTracesStreamHeadCursor(client, span, filters) {
|
|
14122
|
+
return encodeDeltaCursor(await readSafeXactHorizon(client), 0);
|
|
14123
|
+
}
|
|
14124
|
+
var BRANCH_SPAN_TYPE_SET = new Set(storage.BRANCH_SPAN_TYPES);
|
|
14125
|
+
function buildBranchSpanTypeClause(userSpanType, params, startIdx) {
|
|
14126
|
+
if (userSpanType !== void 0) {
|
|
14127
|
+
if (!BRANCH_SPAN_TYPE_SET.has(userSpanType)) {
|
|
14128
|
+
return null;
|
|
14129
|
+
}
|
|
14130
|
+
params.push(userSpanType);
|
|
14131
|
+
return { clause: `r."spanType" = $${startIdx}`, nextIdx: startIdx + 1 };
|
|
14132
|
+
}
|
|
14133
|
+
const placeholders = [];
|
|
14134
|
+
for (const t of storage.BRANCH_SPAN_TYPES) {
|
|
14135
|
+
placeholders.push(`$${startIdx + placeholders.length}`);
|
|
14136
|
+
params.push(t);
|
|
14137
|
+
}
|
|
14138
|
+
return { clause: `r."spanType" IN (${placeholders.join(", ")})`, nextIdx: startIdx + placeholders.length };
|
|
14139
|
+
}
|
|
14140
|
+
function buildListBranchesFilters(filters, spanType, nextParamIdx) {
|
|
14141
|
+
const conditions = [];
|
|
14142
|
+
const params = [];
|
|
14143
|
+
let i = nextParamIdx;
|
|
14144
|
+
const spanTypeClause = buildBranchSpanTypeClause(spanType, params, i);
|
|
14145
|
+
if (!spanTypeClause) return null;
|
|
14146
|
+
conditions.push(spanTypeClause.clause);
|
|
14147
|
+
i = spanTypeClause.nextIdx;
|
|
14148
|
+
if (!filters) return { conditions, params, nextParamIdx: i };
|
|
14149
|
+
if (filters.startedAt?.start) {
|
|
14150
|
+
conditions.push(`r."startedAt" ${filters.startedAt.startExclusive ? ">" : ">="} $${i++}`);
|
|
14151
|
+
params.push(asIsoTimestamp(filters.startedAt.start));
|
|
14152
|
+
}
|
|
14153
|
+
if (filters.startedAt?.end) {
|
|
14154
|
+
conditions.push(`r."startedAt" ${filters.startedAt.endExclusive ? "<" : "<="} $${i++}`);
|
|
14155
|
+
params.push(asIsoTimestamp(filters.startedAt.end));
|
|
14156
|
+
}
|
|
14157
|
+
if (filters.endedAt?.start) {
|
|
14158
|
+
conditions.push(`r."endedAt" ${filters.endedAt.startExclusive ? ">" : ">="} $${i++}`);
|
|
14159
|
+
params.push(asIsoTimestamp(filters.endedAt.start));
|
|
14160
|
+
}
|
|
14161
|
+
if (filters.endedAt?.end) {
|
|
14162
|
+
conditions.push(`r."endedAt" ${filters.endedAt.endExclusive ? "<" : "<="} $${i++}`);
|
|
14163
|
+
params.push(asIsoTimestamp(filters.endedAt.end));
|
|
14164
|
+
}
|
|
14165
|
+
if (filters.traceId !== void 0) {
|
|
14166
|
+
conditions.push(`r."traceId" = $${i++}`);
|
|
14167
|
+
params.push(filters.traceId);
|
|
14168
|
+
}
|
|
14169
|
+
if (filters.entityType !== void 0) {
|
|
14170
|
+
conditions.push(`r."entityType" = $${i++}`);
|
|
14171
|
+
params.push(filters.entityType);
|
|
14172
|
+
}
|
|
14173
|
+
if (filters.entityId !== void 0) {
|
|
14174
|
+
conditions.push(`r."entityId" = $${i++}`);
|
|
14175
|
+
params.push(filters.entityId);
|
|
14176
|
+
}
|
|
14177
|
+
if (filters.entityName !== void 0) {
|
|
14178
|
+
conditions.push(`r."entityName" = $${i++}`);
|
|
14179
|
+
params.push(filters.entityName);
|
|
14180
|
+
}
|
|
14181
|
+
if (filters.entityVersionId !== void 0) {
|
|
14182
|
+
conditions.push(`r."entityVersionId" = $${i++}`);
|
|
14183
|
+
params.push(filters.entityVersionId);
|
|
14184
|
+
}
|
|
14185
|
+
if (filters.parentEntityType !== void 0) {
|
|
14186
|
+
conditions.push(`r."parentEntityType" = $${i++}`);
|
|
14187
|
+
params.push(filters.parentEntityType);
|
|
14188
|
+
}
|
|
14189
|
+
if (filters.parentEntityId !== void 0) {
|
|
14190
|
+
conditions.push(`r."parentEntityId" = $${i++}`);
|
|
14191
|
+
params.push(filters.parentEntityId);
|
|
14192
|
+
}
|
|
14193
|
+
if (filters.parentEntityName !== void 0) {
|
|
14194
|
+
conditions.push(`r."parentEntityName" = $${i++}`);
|
|
14195
|
+
params.push(filters.parentEntityName);
|
|
14196
|
+
}
|
|
14197
|
+
if (filters.parentEntityVersionId !== void 0) {
|
|
14198
|
+
conditions.push(`r."parentEntityVersionId" = $${i++}`);
|
|
14199
|
+
params.push(filters.parentEntityVersionId);
|
|
14200
|
+
}
|
|
14201
|
+
if (filters.rootEntityType !== void 0) {
|
|
14202
|
+
conditions.push(`r."rootEntityType" = $${i++}`);
|
|
14203
|
+
params.push(filters.rootEntityType);
|
|
14204
|
+
}
|
|
14205
|
+
if (filters.rootEntityId !== void 0) {
|
|
14206
|
+
conditions.push(`r."rootEntityId" = $${i++}`);
|
|
14207
|
+
params.push(filters.rootEntityId);
|
|
14208
|
+
}
|
|
14209
|
+
if (filters.rootEntityName !== void 0) {
|
|
14210
|
+
conditions.push(`r."rootEntityName" = $${i++}`);
|
|
14211
|
+
params.push(filters.rootEntityName);
|
|
14212
|
+
}
|
|
14213
|
+
if (filters.rootEntityVersionId !== void 0) {
|
|
14214
|
+
conditions.push(`r."rootEntityVersionId" = $${i++}`);
|
|
14215
|
+
params.push(filters.rootEntityVersionId);
|
|
14216
|
+
}
|
|
14217
|
+
if (filters.userId !== void 0) {
|
|
14218
|
+
conditions.push(`r."userId" = $${i++}`);
|
|
14219
|
+
params.push(filters.userId);
|
|
14220
|
+
}
|
|
14221
|
+
if (filters.organizationId !== void 0) {
|
|
14222
|
+
conditions.push(`r."organizationId" = $${i++}`);
|
|
14223
|
+
params.push(filters.organizationId);
|
|
14224
|
+
}
|
|
14225
|
+
if (filters.resourceId !== void 0) {
|
|
14226
|
+
conditions.push(`r."resourceId" = $${i++}`);
|
|
14227
|
+
params.push(filters.resourceId);
|
|
14228
|
+
}
|
|
14229
|
+
if (filters.runId !== void 0) {
|
|
14230
|
+
conditions.push(`r."runId" = $${i++}`);
|
|
14231
|
+
params.push(filters.runId);
|
|
14232
|
+
}
|
|
14233
|
+
if (filters.sessionId !== void 0) {
|
|
14234
|
+
conditions.push(`r."sessionId" = $${i++}`);
|
|
14235
|
+
params.push(filters.sessionId);
|
|
14236
|
+
}
|
|
14237
|
+
if (filters.threadId !== void 0) {
|
|
14238
|
+
conditions.push(`r."threadId" = $${i++}`);
|
|
14239
|
+
params.push(filters.threadId);
|
|
14240
|
+
}
|
|
14241
|
+
if (filters.requestId !== void 0) {
|
|
14242
|
+
conditions.push(`r."requestId" = $${i++}`);
|
|
14243
|
+
params.push(filters.requestId);
|
|
14244
|
+
}
|
|
14245
|
+
if (filters.experimentId !== void 0) {
|
|
14246
|
+
conditions.push(`r."experimentId" = $${i++}`);
|
|
14247
|
+
params.push(filters.experimentId);
|
|
14248
|
+
}
|
|
14249
|
+
if (filters.environment !== void 0) {
|
|
14250
|
+
conditions.push(`r."environment" = $${i++}`);
|
|
14251
|
+
params.push(filters.environment);
|
|
14252
|
+
}
|
|
14253
|
+
if (filters.serviceName !== void 0) {
|
|
14254
|
+
conditions.push(`r."serviceName" = $${i++}`);
|
|
14255
|
+
params.push(filters.serviceName);
|
|
14256
|
+
}
|
|
14257
|
+
if (filters.source !== void 0) {
|
|
14258
|
+
conditions.push(`r."executionSource" = $${i++}`);
|
|
14259
|
+
params.push(filters.source);
|
|
14260
|
+
}
|
|
14261
|
+
if (filters.metadata != null) {
|
|
14262
|
+
conditions.push(`r."metadataSearch" @> $${i++}::jsonb`);
|
|
14263
|
+
params.push(JSON.stringify(filters.metadata));
|
|
14264
|
+
}
|
|
14265
|
+
if (filters.tags != null && filters.tags.length > 0) {
|
|
14266
|
+
conditions.push(`r."tags" @> $${i++}::text[]`);
|
|
14267
|
+
params.push(filters.tags);
|
|
14268
|
+
}
|
|
14269
|
+
if (filters.status !== void 0) {
|
|
14270
|
+
switch (filters.status) {
|
|
14271
|
+
case storage.TraceStatus.ERROR:
|
|
14272
|
+
conditions.push(`r."error" IS NOT NULL`);
|
|
14273
|
+
break;
|
|
14274
|
+
case storage.TraceStatus.RUNNING:
|
|
14275
|
+
conditions.push(`FALSE`);
|
|
14276
|
+
break;
|
|
14277
|
+
case storage.TraceStatus.SUCCESS:
|
|
14278
|
+
conditions.push(`r."error" IS NULL`);
|
|
14279
|
+
break;
|
|
14280
|
+
}
|
|
14281
|
+
}
|
|
14282
|
+
return { conditions, params, nextParamIdx: i };
|
|
14283
|
+
}
|
|
14284
|
+
async function listBranches(client, schema, args) {
|
|
14285
|
+
const { mode, filters, pagination, orderBy, after, limit } = storage.listBranchesArgsSchema.parse(args);
|
|
14286
|
+
const span = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
14287
|
+
if (mode === "delta") {
|
|
14288
|
+
assertDeltaPollingEnabled();
|
|
14289
|
+
return listBranchesDelta(client, span, filters, after, limit);
|
|
14290
|
+
}
|
|
14291
|
+
return listBranchesPage(client, span, filters, pagination.page, pagination.perPage, orderBy.field, orderBy.direction);
|
|
14292
|
+
}
|
|
14293
|
+
async function listBranchesPage(client, span, filters, page, perPage, orderField, orderDir) {
|
|
14294
|
+
const built = buildListBranchesFilters(filters, filters?.spanType, 1);
|
|
14295
|
+
if (!built) {
|
|
14296
|
+
const deltaCursor2 = deltaPollingFeatureEnabled() ? await readBranchesStreamHeadCursor(client) : void 0;
|
|
14297
|
+
return {
|
|
14298
|
+
pagination: { total: 0, page, perPage, hasMore: false },
|
|
14299
|
+
branches: [],
|
|
14300
|
+
...deltaCursor2 !== void 0 ? { deltaCursor: deltaCursor2 } : {}
|
|
14301
|
+
};
|
|
14302
|
+
}
|
|
14303
|
+
const { conditions, params, nextParamIdx } = built;
|
|
14304
|
+
let i = nextParamIdx;
|
|
14305
|
+
const whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
14306
|
+
const orderClause = orderField === "endedAt" ? `ORDER BY r."endedAt" ${orderDir} NULLS ${orderDir === "DESC" ? "FIRST" : "LAST"}, r."cursorId" ${orderDir}` : `ORDER BY r."${orderField}" ${orderDir}, r."cursorId" ${orderDir}`;
|
|
14307
|
+
const countRow = await client.oneOrNone(
|
|
14308
|
+
`SELECT COUNT(*)::text AS count FROM ${span} r ${whereClause}`,
|
|
14309
|
+
params
|
|
14310
|
+
);
|
|
14311
|
+
const count = Number(countRow?.count ?? 0);
|
|
14312
|
+
let spans = [];
|
|
14313
|
+
if (count > 0) {
|
|
14314
|
+
const rows = await client.manyOrNone(
|
|
14315
|
+
`SELECT ${SPAN_SELECT_COLUMNS_ALIASED}
|
|
14316
|
+
FROM ${span} r
|
|
14317
|
+
${whereClause}
|
|
14318
|
+
${orderClause}
|
|
14319
|
+
LIMIT $${i++} OFFSET $${i++}`,
|
|
14320
|
+
[...params, perPage, page * perPage]
|
|
14321
|
+
);
|
|
14322
|
+
spans = rows.map(rowToSpanRecord);
|
|
14323
|
+
}
|
|
14324
|
+
const deltaCursor = deltaPollingFeatureEnabled() ? await readBranchesStreamHeadCursor(client) : void 0;
|
|
14325
|
+
return {
|
|
14326
|
+
pagination: { total: count, page, perPage, hasMore: (page + 1) * perPage < count },
|
|
14327
|
+
branches: storage.toTraceSpans(spans),
|
|
14328
|
+
...deltaCursor !== void 0 ? { deltaCursor } : {}
|
|
14329
|
+
};
|
|
14330
|
+
}
|
|
14331
|
+
async function listBranchesDelta(client, span, filters, after, limit) {
|
|
14332
|
+
if (after === void 0) {
|
|
14333
|
+
const deltaCursor2 = await readBranchesStreamHeadCursor(client);
|
|
14334
|
+
return { branches: [], delta: { limit, hasMore: false }, deltaCursor: deltaCursor2 };
|
|
14335
|
+
}
|
|
14336
|
+
const built = buildListBranchesFilters(filters, filters?.spanType, 1);
|
|
14337
|
+
if (!built) {
|
|
14338
|
+
return {
|
|
14339
|
+
branches: [],
|
|
14340
|
+
delta: { limit, hasMore: false },
|
|
14341
|
+
deltaCursor: await readBranchesStreamHeadCursor(client)
|
|
14342
|
+
};
|
|
14343
|
+
}
|
|
14344
|
+
const { conditions, params, nextParamIdx } = built;
|
|
14345
|
+
let i = nextParamIdx;
|
|
14346
|
+
const afterCursor = decodeDeltaCursor(after);
|
|
14347
|
+
const safeHorizon = await readSafeXactHorizon(client);
|
|
14348
|
+
conditions.push(`(r."xactId", r."cursorId") > ($${i++}::xid8, $${i++}::bigint)`);
|
|
14349
|
+
params.push(afterCursor.xactId, afterCursor.cursorId);
|
|
14350
|
+
conditions.push(`r."xactId" < $${i++}::xid8`);
|
|
14351
|
+
params.push(safeHorizon);
|
|
14352
|
+
const rows = await client.manyOrNone(
|
|
14353
|
+
`SELECT ${SPAN_SELECT_COLUMNS_ALIASED}
|
|
14354
|
+
FROM ${span} r
|
|
14355
|
+
WHERE ${conditions.join(" AND ")}
|
|
14356
|
+
ORDER BY r."xactId" ASC, r."cursorId" ASC
|
|
14357
|
+
LIMIT $${i++}`,
|
|
14358
|
+
[...params, limit + 1]
|
|
14359
|
+
);
|
|
14360
|
+
const hasMore = rows.length > limit;
|
|
14361
|
+
const visible = rows.slice(0, limit);
|
|
14362
|
+
const deltaCursor = visible.length > 0 ? encodeDeltaCursor(visible[visible.length - 1].xactId, visible[visible.length - 1].cursorId) : encodeDeltaCursor(safeHorizon, 0);
|
|
14363
|
+
return {
|
|
14364
|
+
branches: storage.toTraceSpans(visible.map(rowToSpanRecord)),
|
|
14365
|
+
delta: { limit, hasMore },
|
|
14366
|
+
deltaCursor
|
|
14367
|
+
};
|
|
14368
|
+
}
|
|
14369
|
+
async function readBranchesStreamHeadCursor(client, span, filters) {
|
|
14370
|
+
return encodeDeltaCursor(await readSafeXactHorizon(client), 0);
|
|
14371
|
+
}
|
|
14372
|
+
|
|
14373
|
+
// src/storage/domains/observability/v-next/tracing.ts
|
|
14374
|
+
async function createSpan(client, schema, args) {
|
|
14375
|
+
const row = spanRecordToRow(args.span);
|
|
14376
|
+
const insert = buildInsert(schema, TABLE_SPAN_EVENTS, [row]);
|
|
14377
|
+
if (insert) await client.query(insert.text, insert.values);
|
|
14378
|
+
}
|
|
14379
|
+
async function batchCreateSpans(client, schema, args) {
|
|
14380
|
+
if (args.records.length === 0) return;
|
|
14381
|
+
const rows = args.records.map(spanRecordToRow);
|
|
14382
|
+
const insert = buildInsert(schema, TABLE_SPAN_EVENTS, rows);
|
|
14383
|
+
if (insert) await client.query(insert.text, insert.values);
|
|
14384
|
+
}
|
|
14385
|
+
async function getSpans(client, schema, args) {
|
|
14386
|
+
if (args.spanIds.length === 0) {
|
|
14387
|
+
return { traceId: args.traceId, spans: [] };
|
|
14388
|
+
}
|
|
14389
|
+
const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
14390
|
+
const rows = await client.manyOrNone(
|
|
14391
|
+
`SELECT ${SPAN_SELECT_COLUMNS}
|
|
14392
|
+
FROM ${table}
|
|
14393
|
+
WHERE "traceId" = $1
|
|
14394
|
+
AND "spanId" = ANY($2::text[])
|
|
14395
|
+
ORDER BY "startedAt" ASC`,
|
|
14396
|
+
[args.traceId, args.spanIds]
|
|
14397
|
+
);
|
|
14398
|
+
return { traceId: args.traceId, spans: rows.map(rowToSpanRecord) };
|
|
14399
|
+
}
|
|
14400
|
+
async function getSpan(client, schema, args) {
|
|
14401
|
+
const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
14402
|
+
const row = await client.oneOrNone(
|
|
14403
|
+
`SELECT ${SPAN_SELECT_COLUMNS}
|
|
14404
|
+
FROM ${table}
|
|
14405
|
+
WHERE "traceId" = $1 AND "spanId" = $2
|
|
14406
|
+
ORDER BY "endedAt" DESC
|
|
14407
|
+
LIMIT 1`,
|
|
14408
|
+
[args.traceId, args.spanId]
|
|
14409
|
+
);
|
|
14410
|
+
if (!row) return null;
|
|
14411
|
+
return { span: rowToSpanRecord(row) };
|
|
14412
|
+
}
|
|
14413
|
+
async function getTrace(client, schema, args) {
|
|
14414
|
+
const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
14415
|
+
const rows = await client.manyOrNone(
|
|
14416
|
+
`SELECT ${SPAN_SELECT_COLUMNS}
|
|
14417
|
+
FROM ${table}
|
|
14418
|
+
WHERE "traceId" = $1
|
|
14419
|
+
ORDER BY "startedAt" ASC`,
|
|
14420
|
+
[args.traceId]
|
|
14421
|
+
);
|
|
14422
|
+
if (!rows.length) return null;
|
|
14423
|
+
return { traceId: args.traceId, spans: rows.map(rowToSpanRecord) };
|
|
14424
|
+
}
|
|
14425
|
+
async function getTraceLight(client, schema, args) {
|
|
14426
|
+
const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
14427
|
+
const rows = await client.manyOrNone(
|
|
14428
|
+
`SELECT ${SPAN_LIGHT_SELECT_COLUMNS}
|
|
14429
|
+
FROM ${table}
|
|
14430
|
+
WHERE "traceId" = $1
|
|
14431
|
+
ORDER BY "startedAt" ASC`,
|
|
14432
|
+
[args.traceId]
|
|
14433
|
+
);
|
|
14434
|
+
if (!rows.length) return null;
|
|
14435
|
+
return {
|
|
14436
|
+
traceId: args.traceId,
|
|
14437
|
+
spans: rows.map(rowToLightSpanRecord)
|
|
14438
|
+
};
|
|
14439
|
+
}
|
|
14440
|
+
async function batchDeleteTraces(client, schema, args) {
|
|
14441
|
+
if (args.traceIds.length === 0) return;
|
|
14442
|
+
const span = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
14443
|
+
const placeholders = args.traceIds.map((_, i) => `$${i + 1}`).join(", ");
|
|
14444
|
+
await client.query(`DELETE FROM ${span} WHERE "traceId" IN (${placeholders})`, args.traceIds);
|
|
14445
|
+
}
|
|
14446
|
+
async function dangerouslyClearTracing(client, schema) {
|
|
14447
|
+
const span = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
14448
|
+
await client.none(`TRUNCATE TABLE ${span} RESTART IDENTITY`);
|
|
14449
|
+
}
|
|
14450
|
+
|
|
14451
|
+
// src/storage/domains/observability/v-next/index.ts
|
|
14452
|
+
function wrapError(op, error$1, details) {
|
|
14453
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
14454
|
+
throw new error.MastraError(
|
|
14455
|
+
{
|
|
14456
|
+
id: storage.createStorageErrorId("PG", op, "FAILED"),
|
|
14457
|
+
domain: error.ErrorDomain.STORAGE,
|
|
14458
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
14459
|
+
details
|
|
14460
|
+
},
|
|
14461
|
+
error$1
|
|
14462
|
+
);
|
|
14463
|
+
}
|
|
14464
|
+
var ObservabilityStoragePostgresVNext = class extends storage.ObservabilityStorage {
|
|
14465
|
+
#client;
|
|
14466
|
+
#schema;
|
|
14467
|
+
#partitioning;
|
|
14468
|
+
#discoveryConfig;
|
|
14469
|
+
#partitionMode;
|
|
14470
|
+
constructor(config) {
|
|
14471
|
+
super();
|
|
14472
|
+
const { client, schemaName } = resolvePgConfig(config);
|
|
14473
|
+
this.#client = client;
|
|
14474
|
+
this.#schema = schemaName ?? "public";
|
|
14475
|
+
this.#partitioning = config.partitioning ?? {};
|
|
14476
|
+
this.#discoveryConfig = config.discovery ?? {};
|
|
14477
|
+
}
|
|
14478
|
+
/**
|
|
14479
|
+
* Build the discovery config used at each call site, with the framework
|
|
14480
|
+
* logger injected so background refresh failures land in the same log
|
|
14481
|
+
* stream as the rest of the store. Reads `this.logger` lazily so
|
|
14482
|
+
* `__setLogger()` calls (e.g. when the domain is mounted under a Mastra
|
|
14483
|
+
* instance) propagate without rebuilding the domain.
|
|
14484
|
+
*/
|
|
14485
|
+
get #discovery() {
|
|
14486
|
+
return { ...this.#discoveryConfig, logger: this.logger };
|
|
14487
|
+
}
|
|
14488
|
+
// -------------------------------------------------------------------------
|
|
14489
|
+
// Initialization
|
|
14490
|
+
// -------------------------------------------------------------------------
|
|
14491
|
+
/**
|
|
14492
|
+
* Create the signal tables, indexes, and (if Timescale / pg_partman is
|
|
14493
|
+
* present) hypertable / partman registrations.
|
|
14494
|
+
*
|
|
14495
|
+
* Not transactional: each `CREATE TABLE IF NOT EXISTS`, `CREATE INDEX IF
|
|
14496
|
+
* NOT EXISTS`, and `create_hypertable()` / `create_parent()` runs in its
|
|
14497
|
+
* own implicit transaction. Re-running `init()` after a failure is safe
|
|
14498
|
+
* (every statement is idempotent), but a failure partway through against
|
|
14499
|
+
* Timescale can leave some signal tables as hypertables and others as
|
|
14500
|
+
* plain tables. If that happens, fix the underlying error and call
|
|
14501
|
+
* `init()` again — the partially-converted state is recoverable.
|
|
14502
|
+
*/
|
|
14503
|
+
async init() {
|
|
14504
|
+
try {
|
|
14505
|
+
const explicit = this.#partitioning.mode;
|
|
14506
|
+
let mode;
|
|
14507
|
+
if (explicit && explicit !== "auto") {
|
|
14508
|
+
mode = explicit;
|
|
14509
|
+
} else if (await detectTimescale(this.#client)) {
|
|
14510
|
+
mode = "timescale";
|
|
14511
|
+
} else if (await detectPartman(this.#client)) {
|
|
14512
|
+
mode = "partman";
|
|
14513
|
+
} else {
|
|
14514
|
+
mode = "native";
|
|
14515
|
+
}
|
|
14516
|
+
const ddlMode = mode === "timescale" ? "timescale" : "partitioned";
|
|
14517
|
+
try {
|
|
14518
|
+
await this.#client.none(schemaDDL(this.#schema));
|
|
14519
|
+
} catch (error) {
|
|
14520
|
+
if (!isDuplicateSchemaError(error)) throw error;
|
|
14521
|
+
}
|
|
14522
|
+
for (const ddl of allTableDDL(this.#schema, ddlMode)) {
|
|
14523
|
+
try {
|
|
14524
|
+
await this.#client.none(ddl);
|
|
14525
|
+
} catch (error) {
|
|
14526
|
+
if (!isDuplicateRelationError(error)) throw error;
|
|
14527
|
+
}
|
|
14528
|
+
}
|
|
14529
|
+
for (const ddl of allIndexDDL(this.#schema)) {
|
|
14530
|
+
try {
|
|
14531
|
+
await this.#client.none(ddl);
|
|
14532
|
+
} catch (error) {
|
|
14533
|
+
if (!isDuplicateRelationError(error)) throw error;
|
|
14534
|
+
}
|
|
14535
|
+
}
|
|
14536
|
+
this.#partitionMode = await setupPartitioning(this.#client, this.#schema, {
|
|
14537
|
+
...this.#partitioning,
|
|
14538
|
+
mode
|
|
14539
|
+
});
|
|
14540
|
+
} catch (error) {
|
|
14541
|
+
wrapError("VNEXT_INIT", error);
|
|
14542
|
+
}
|
|
14543
|
+
}
|
|
14544
|
+
/** Resolved partition mode after init(). Useful for tests and diagnostics. */
|
|
14545
|
+
get partitionMode() {
|
|
14546
|
+
return this.#partitionMode;
|
|
14547
|
+
}
|
|
14548
|
+
get observabilityStrategy() {
|
|
14549
|
+
return { preferred: "insert-only", supported: ["insert-only"] };
|
|
14550
|
+
}
|
|
14551
|
+
getFeatures() {
|
|
14552
|
+
if (!deltaPollingFeatureEnabled()) return void 0;
|
|
14553
|
+
return ["delta-polling"];
|
|
14554
|
+
}
|
|
14555
|
+
async #run(op, fn, details) {
|
|
14556
|
+
try {
|
|
14557
|
+
return await fn();
|
|
14558
|
+
} catch (error) {
|
|
14559
|
+
wrapError(op, error, details);
|
|
14560
|
+
}
|
|
14561
|
+
}
|
|
14562
|
+
// -------------------------------------------------------------------------
|
|
14563
|
+
// Tracing — writes
|
|
14564
|
+
// -------------------------------------------------------------------------
|
|
14565
|
+
async createSpan(args) {
|
|
14566
|
+
await this.#run("CREATE_SPAN", () => createSpan(this.#client, this.#schema, args), {
|
|
14567
|
+
traceId: args.span.traceId,
|
|
14568
|
+
spanId: args.span.spanId
|
|
14569
|
+
});
|
|
14570
|
+
}
|
|
14571
|
+
async batchCreateSpans(args) {
|
|
14572
|
+
await this.#run("BATCH_CREATE_SPANS", () => batchCreateSpans(this.#client, this.#schema, args), {
|
|
14573
|
+
count: args.records.length
|
|
14574
|
+
});
|
|
14575
|
+
}
|
|
14576
|
+
// -------------------------------------------------------------------------
|
|
14577
|
+
// Tracing — reads
|
|
14578
|
+
// -------------------------------------------------------------------------
|
|
14579
|
+
async getSpan(args) {
|
|
14580
|
+
return this.#run("GET_SPAN", () => getSpan(this.#client, this.#schema, args), {
|
|
14581
|
+
traceId: args.traceId,
|
|
14582
|
+
spanId: args.spanId
|
|
14583
|
+
});
|
|
14584
|
+
}
|
|
14585
|
+
async getSpans(args) {
|
|
14586
|
+
return this.#run("GET_SPANS", () => getSpans(this.#client, this.#schema, args), {
|
|
14587
|
+
traceId: args.traceId,
|
|
14588
|
+
count: args.spanIds.length
|
|
14589
|
+
});
|
|
14590
|
+
}
|
|
14591
|
+
async getRootSpan(args) {
|
|
14592
|
+
return this.#run("GET_ROOT_SPAN", () => getRootSpan(this.#client, this.#schema, args), {
|
|
14593
|
+
traceId: args.traceId
|
|
14594
|
+
});
|
|
14595
|
+
}
|
|
14596
|
+
async getTrace(args) {
|
|
14597
|
+
return this.#run("GET_TRACE", () => getTrace(this.#client, this.#schema, args), {
|
|
14598
|
+
traceId: args.traceId
|
|
14599
|
+
});
|
|
14600
|
+
}
|
|
14601
|
+
async getTraceLight(args) {
|
|
14602
|
+
return this.#run("GET_TRACE_LIGHT", () => getTraceLight(this.#client, this.#schema, args), {
|
|
14603
|
+
traceId: args.traceId
|
|
14604
|
+
});
|
|
14605
|
+
}
|
|
14606
|
+
async listTraces(args) {
|
|
14607
|
+
return this.#run("LIST_TRACES", () => listTraces(this.#client, this.#schema, args));
|
|
14608
|
+
}
|
|
14609
|
+
async listBranches(args) {
|
|
14610
|
+
return this.#run("LIST_BRANCHES", () => listBranches(this.#client, this.#schema, args));
|
|
14611
|
+
}
|
|
14612
|
+
// -------------------------------------------------------------------------
|
|
14613
|
+
// Logs / metrics / scores / feedback — writes
|
|
14614
|
+
// -------------------------------------------------------------------------
|
|
14615
|
+
async batchCreateLogs(args) {
|
|
14616
|
+
await this.#run("BATCH_CREATE_LOGS", () => batchCreateLogs(this.#client, this.#schema, args), {
|
|
14617
|
+
count: args.logs.length
|
|
14618
|
+
});
|
|
14619
|
+
}
|
|
14620
|
+
async batchCreateMetrics(args) {
|
|
14621
|
+
await this.#run("BATCH_CREATE_METRICS", () => batchCreateMetrics(this.#client, this.#schema, args), {
|
|
14622
|
+
count: args.metrics.length
|
|
14623
|
+
});
|
|
14624
|
+
}
|
|
14625
|
+
async createScore(args) {
|
|
14626
|
+
await this.#run("CREATE_SCORE", () => createScore(this.#client, this.#schema, args));
|
|
14627
|
+
}
|
|
14628
|
+
async batchCreateScores(args) {
|
|
14629
|
+
await this.#run("BATCH_CREATE_SCORES", () => batchCreateScores(this.#client, this.#schema, args), {
|
|
14630
|
+
count: args.scores.length
|
|
14631
|
+
});
|
|
14632
|
+
}
|
|
14633
|
+
async createFeedback(args) {
|
|
14634
|
+
await this.#run("CREATE_FEEDBACK", () => createFeedback(this.#client, this.#schema, args));
|
|
14635
|
+
}
|
|
14636
|
+
async batchCreateFeedback(args) {
|
|
14637
|
+
await this.#run("BATCH_CREATE_FEEDBACK", () => batchCreateFeedback(this.#client, this.#schema, args), {
|
|
14638
|
+
count: args.feedbacks.length
|
|
14639
|
+
});
|
|
14640
|
+
}
|
|
14641
|
+
// -------------------------------------------------------------------------
|
|
14642
|
+
// Logs / metrics / scores / feedback — list reads
|
|
14643
|
+
// -------------------------------------------------------------------------
|
|
14644
|
+
async listLogs(args) {
|
|
14645
|
+
return this.#run("LIST_LOGS", () => listLogs(this.#client, this.#schema, args));
|
|
14646
|
+
}
|
|
14647
|
+
async listMetrics(args) {
|
|
14648
|
+
return this.#run("LIST_METRICS", () => listMetrics(this.#client, this.#schema, args));
|
|
14649
|
+
}
|
|
14650
|
+
async listScores(args) {
|
|
14651
|
+
return this.#run("LIST_SCORES", () => listScores(this.#client, this.#schema, args));
|
|
14652
|
+
}
|
|
14653
|
+
async getScoreById(scoreId) {
|
|
14654
|
+
return this.#run("GET_SCORE_BY_ID", () => getScoreById(this.#client, this.#schema, scoreId), {
|
|
14655
|
+
scoreId
|
|
14656
|
+
});
|
|
14657
|
+
}
|
|
14658
|
+
async listFeedback(args) {
|
|
14659
|
+
return this.#run("LIST_FEEDBACK", () => listFeedback(this.#client, this.#schema, args));
|
|
14660
|
+
}
|
|
14661
|
+
// -------------------------------------------------------------------------
|
|
14662
|
+
// OLAP — metrics
|
|
14663
|
+
// -------------------------------------------------------------------------
|
|
14664
|
+
async getMetricAggregate(args) {
|
|
14665
|
+
return this.#run("GET_METRIC_AGGREGATE", () => getMetricAggregate(this.#client, this.#schema, args));
|
|
14666
|
+
}
|
|
14667
|
+
async getMetricBreakdown(args) {
|
|
14668
|
+
return this.#run("GET_METRIC_BREAKDOWN", () => getMetricBreakdown(this.#client, this.#schema, args));
|
|
14669
|
+
}
|
|
14670
|
+
async getMetricTimeSeries(args) {
|
|
14671
|
+
return this.#run("GET_METRIC_TIME_SERIES", () => getMetricTimeSeries(this.#client, this.#schema, args));
|
|
14672
|
+
}
|
|
14673
|
+
async getMetricPercentiles(args) {
|
|
14674
|
+
return this.#run("GET_METRIC_PERCENTILES", () => getMetricPercentiles(this.#client, this.#schema, args));
|
|
14675
|
+
}
|
|
14676
|
+
// -------------------------------------------------------------------------
|
|
14677
|
+
// OLAP — scores
|
|
14678
|
+
// -------------------------------------------------------------------------
|
|
14679
|
+
async getScoreAggregate(args) {
|
|
14680
|
+
return this.#run("GET_SCORE_AGGREGATE", () => getScoreAggregate(this.#client, this.#schema, args));
|
|
14681
|
+
}
|
|
14682
|
+
async getScoreBreakdown(args) {
|
|
14683
|
+
return this.#run("GET_SCORE_BREAKDOWN", () => getScoreBreakdown(this.#client, this.#schema, args));
|
|
14684
|
+
}
|
|
14685
|
+
async getScoreTimeSeries(args) {
|
|
14686
|
+
return this.#run("GET_SCORE_TIME_SERIES", () => getScoreTimeSeries(this.#client, this.#schema, args));
|
|
14687
|
+
}
|
|
14688
|
+
async getScorePercentiles(args) {
|
|
14689
|
+
return this.#run("GET_SCORE_PERCENTILES", () => getScorePercentiles(this.#client, this.#schema, args));
|
|
14690
|
+
}
|
|
14691
|
+
// -------------------------------------------------------------------------
|
|
14692
|
+
// OLAP — feedback
|
|
14693
|
+
// -------------------------------------------------------------------------
|
|
14694
|
+
async getFeedbackAggregate(args) {
|
|
14695
|
+
return this.#run(
|
|
14696
|
+
"GET_FEEDBACK_AGGREGATE",
|
|
14697
|
+
() => getFeedbackAggregate(this.#client, this.#schema, args)
|
|
14698
|
+
);
|
|
14699
|
+
}
|
|
14700
|
+
async getFeedbackBreakdown(args) {
|
|
14701
|
+
return this.#run(
|
|
14702
|
+
"GET_FEEDBACK_BREAKDOWN",
|
|
14703
|
+
() => getFeedbackBreakdown(this.#client, this.#schema, args)
|
|
14704
|
+
);
|
|
14705
|
+
}
|
|
14706
|
+
async getFeedbackTimeSeries(args) {
|
|
14707
|
+
return this.#run(
|
|
14708
|
+
"GET_FEEDBACK_TIME_SERIES",
|
|
14709
|
+
() => getFeedbackTimeSeries(this.#client, this.#schema, args)
|
|
14710
|
+
);
|
|
14711
|
+
}
|
|
14712
|
+
async getFeedbackPercentiles(args) {
|
|
14713
|
+
return this.#run(
|
|
14714
|
+
"GET_FEEDBACK_PERCENTILES",
|
|
14715
|
+
() => getFeedbackPercentiles(this.#client, this.#schema, args)
|
|
14716
|
+
);
|
|
14717
|
+
}
|
|
14718
|
+
// -------------------------------------------------------------------------
|
|
14719
|
+
// Discovery
|
|
14720
|
+
// -------------------------------------------------------------------------
|
|
14721
|
+
async getEntityTypes(args) {
|
|
14722
|
+
return this.#run(
|
|
14723
|
+
"GET_ENTITY_TYPES",
|
|
14724
|
+
() => getEntityTypes(this.#client, this.#schema, args, this.#discovery)
|
|
14725
|
+
);
|
|
14726
|
+
}
|
|
14727
|
+
async getEntityNames(args) {
|
|
14728
|
+
return this.#run(
|
|
14729
|
+
"GET_ENTITY_NAMES",
|
|
14730
|
+
() => getEntityNames(this.#client, this.#schema, args, this.#discovery)
|
|
14731
|
+
);
|
|
14732
|
+
}
|
|
14733
|
+
async getServiceNames(args) {
|
|
14734
|
+
return this.#run(
|
|
14735
|
+
"GET_SERVICE_NAMES",
|
|
14736
|
+
() => getServiceNames(this.#client, this.#schema, args, this.#discovery)
|
|
14737
|
+
);
|
|
14738
|
+
}
|
|
14739
|
+
async getEnvironments(args) {
|
|
14740
|
+
return this.#run(
|
|
14741
|
+
"GET_ENVIRONMENTS",
|
|
14742
|
+
() => getEnvironments(this.#client, this.#schema, args, this.#discovery)
|
|
14743
|
+
);
|
|
14744
|
+
}
|
|
14745
|
+
async getTags(args) {
|
|
14746
|
+
return this.#run("GET_TAGS", () => getTags(this.#client, this.#schema, args, this.#discovery));
|
|
14747
|
+
}
|
|
14748
|
+
async getMetricNames(args) {
|
|
14749
|
+
return this.#run(
|
|
14750
|
+
"GET_METRIC_NAMES",
|
|
14751
|
+
() => getMetricNames(this.#client, this.#schema, args, this.#discovery)
|
|
14752
|
+
);
|
|
14753
|
+
}
|
|
14754
|
+
async getMetricLabelKeys(args) {
|
|
14755
|
+
return this.#run(
|
|
14756
|
+
"GET_METRIC_LABEL_KEYS",
|
|
14757
|
+
() => getMetricLabelKeys(this.#client, this.#schema, args, this.#discovery)
|
|
14758
|
+
);
|
|
14759
|
+
}
|
|
14760
|
+
async getMetricLabelValues(args) {
|
|
14761
|
+
return this.#run(
|
|
14762
|
+
"GET_METRIC_LABEL_VALUES",
|
|
14763
|
+
() => getMetricLabelValues(this.#client, this.#schema, args, this.#discovery)
|
|
14764
|
+
);
|
|
14765
|
+
}
|
|
14766
|
+
// -------------------------------------------------------------------------
|
|
14767
|
+
// Tracing — deletes / clear
|
|
14768
|
+
// -------------------------------------------------------------------------
|
|
14769
|
+
async batchDeleteTraces(args) {
|
|
14770
|
+
await this.#run("BATCH_DELETE_TRACES", () => batchDeleteTraces(this.#client, this.#schema, args), {
|
|
14771
|
+
count: args.traceIds.length
|
|
14772
|
+
});
|
|
14773
|
+
}
|
|
14774
|
+
async dangerouslyClearAll() {
|
|
14775
|
+
try {
|
|
14776
|
+
await dangerouslyClearTracing(this.#client, this.#schema);
|
|
14777
|
+
for (const t of ALL_SIGNAL_TABLES) {
|
|
14778
|
+
if (t === TABLE_SPAN_EVENTS) continue;
|
|
14779
|
+
await this.#client.none(`TRUNCATE TABLE ${qualifiedTable(this.#schema, t)} RESTART IDENTITY`);
|
|
14780
|
+
}
|
|
14781
|
+
await this.#client.none(`TRUNCATE TABLE ${qualifiedTable(this.#schema, TABLE_DISCOVERY)} RESTART IDENTITY`);
|
|
14782
|
+
} catch (error) {
|
|
14783
|
+
wrapError("DANGEROUSLY_CLEAR_ALL", error);
|
|
14784
|
+
}
|
|
14785
|
+
}
|
|
14786
|
+
};
|
|
14787
|
+
var SNAPSHOT_FIELDS3 = ["name", "description", "content", "rules", "requestContextSchema"];
|
|
14788
|
+
var PromptBlocksPG = class _PromptBlocksPG extends storage.PromptBlocksStorage {
|
|
14789
|
+
#db;
|
|
14790
|
+
#schema;
|
|
14791
|
+
#skipDefaultIndexes;
|
|
14792
|
+
#indexes;
|
|
14793
|
+
static MANAGED_TABLES = [storage.TABLE_PROMPT_BLOCKS, storage.TABLE_PROMPT_BLOCK_VERSIONS];
|
|
14794
|
+
constructor(config) {
|
|
14795
|
+
super();
|
|
14796
|
+
const { client, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
|
|
14797
|
+
this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
|
|
14798
|
+
this.#schema = schemaName || "public";
|
|
14799
|
+
this.#skipDefaultIndexes = skipDefaultIndexes;
|
|
14800
|
+
this.#indexes = indexes?.filter((idx) => _PromptBlocksPG.MANAGED_TABLES.includes(idx.table));
|
|
14801
|
+
}
|
|
14802
|
+
/**
|
|
14803
|
+
* Returns default index definitions for the prompt blocks domain tables.
|
|
14804
|
+
* @param schemaPrefix - Prefix for index names (e.g. "my_schema_" or "")
|
|
14805
|
+
*/
|
|
14806
|
+
static getDefaultIndexDefs(schemaPrefix) {
|
|
14807
|
+
return [
|
|
14808
|
+
{
|
|
14809
|
+
name: `${schemaPrefix}idx_prompt_block_versions_block_version`,
|
|
14810
|
+
table: storage.TABLE_PROMPT_BLOCK_VERSIONS,
|
|
14811
|
+
columns: ["blockId", "versionNumber"],
|
|
14812
|
+
unique: true
|
|
14813
|
+
}
|
|
14814
|
+
];
|
|
14815
|
+
}
|
|
14816
|
+
/**
|
|
14817
|
+
* Returns all DDL statements for this domain: tables and indexes.
|
|
14818
|
+
* Used by exportSchemas to produce a complete, reproducible schema export.
|
|
14819
|
+
*/
|
|
14820
|
+
static getExportDDL(schemaName) {
|
|
14821
|
+
const statements = [];
|
|
14822
|
+
const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
|
|
14823
|
+
const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
|
|
14824
|
+
for (const tableName of _PromptBlocksPG.MANAGED_TABLES) {
|
|
14825
|
+
statements.push(
|
|
14826
|
+
generateTableSQL({
|
|
14827
|
+
tableName,
|
|
14828
|
+
schema: storage.TABLE_SCHEMAS[tableName],
|
|
14829
|
+
schemaName,
|
|
14830
|
+
includeAllConstraints: true
|
|
14831
|
+
})
|
|
14832
|
+
);
|
|
14833
|
+
}
|
|
14834
|
+
for (const idx of _PromptBlocksPG.getDefaultIndexDefs(schemaPrefix)) {
|
|
14835
|
+
statements.push(generateIndexSQL(idx, schemaName));
|
|
14836
|
+
}
|
|
14837
|
+
return statements;
|
|
14838
|
+
}
|
|
14839
|
+
getDefaultIndexDefinitions() {
|
|
14840
|
+
const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
|
|
14841
|
+
return _PromptBlocksPG.getDefaultIndexDefs(schemaPrefix);
|
|
14842
|
+
}
|
|
14843
|
+
async createDefaultIndexes() {
|
|
14844
|
+
if (this.#skipDefaultIndexes) {
|
|
14845
|
+
return;
|
|
14846
|
+
}
|
|
14847
|
+
for (const indexDef of this.getDefaultIndexDefinitions()) {
|
|
14848
|
+
try {
|
|
14849
|
+
await this.#db.createIndex(indexDef);
|
|
14850
|
+
} catch {
|
|
14851
|
+
}
|
|
14852
|
+
}
|
|
14853
|
+
}
|
|
14854
|
+
async init() {
|
|
14855
|
+
await this.#db.createTable({ tableName: storage.TABLE_PROMPT_BLOCKS, schema: storage.TABLE_SCHEMAS[storage.TABLE_PROMPT_BLOCKS] });
|
|
14856
|
+
await this.#db.createTable({
|
|
14857
|
+
tableName: storage.TABLE_PROMPT_BLOCK_VERSIONS,
|
|
14858
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_PROMPT_BLOCK_VERSIONS]
|
|
14859
|
+
});
|
|
14860
|
+
await this.#db.alterTable({
|
|
14861
|
+
tableName: storage.TABLE_PROMPT_BLOCK_VERSIONS,
|
|
14862
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_PROMPT_BLOCK_VERSIONS],
|
|
14863
|
+
ifNotExists: ["requestContextSchema"]
|
|
14864
|
+
});
|
|
14865
|
+
await this.createDefaultIndexes();
|
|
14866
|
+
await this.createCustomIndexes();
|
|
14867
|
+
}
|
|
14868
|
+
async createCustomIndexes() {
|
|
14869
|
+
if (!this.#indexes || this.#indexes.length === 0) {
|
|
14870
|
+
return;
|
|
14871
|
+
}
|
|
14872
|
+
for (const indexDef of this.#indexes) {
|
|
14873
|
+
try {
|
|
14874
|
+
await this.#db.createIndex(indexDef);
|
|
14875
|
+
} catch (error) {
|
|
14876
|
+
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
14877
|
+
}
|
|
14878
|
+
}
|
|
14879
|
+
}
|
|
14880
|
+
async dangerouslyClearAll() {
|
|
14881
|
+
await this.#db.clearTable({ tableName: storage.TABLE_PROMPT_BLOCK_VERSIONS });
|
|
14882
|
+
await this.#db.clearTable({ tableName: storage.TABLE_PROMPT_BLOCKS });
|
|
14883
|
+
}
|
|
14884
|
+
// ==========================================================================
|
|
14885
|
+
// Prompt Block CRUD Methods
|
|
14886
|
+
// ==========================================================================
|
|
14887
|
+
async getById(id) {
|
|
14888
|
+
try {
|
|
14889
|
+
const tableName = getTableName2({ indexName: storage.TABLE_PROMPT_BLOCKS, schemaName: getSchemaName2(this.#schema) });
|
|
11569
14890
|
const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1`, [id]);
|
|
11570
14891
|
if (!result) {
|
|
11571
14892
|
return null;
|
|
@@ -13534,16 +16855,39 @@ var SkillsPG = class _SkillsPG extends storage.SkillsStorage {
|
|
|
13534
16855
|
this.#skipDefaultIndexes = skipDefaultIndexes;
|
|
13535
16856
|
this.#indexes = indexes?.filter((idx) => _SkillsPG.MANAGED_TABLES.includes(idx.table));
|
|
13536
16857
|
}
|
|
13537
|
-
|
|
16858
|
+
static getDefaultIndexDefs(schemaPrefix) {
|
|
13538
16859
|
return [
|
|
13539
16860
|
{
|
|
13540
|
-
name:
|
|
16861
|
+
name: `${schemaPrefix}idx_skill_versions_skill_version`,
|
|
13541
16862
|
table: storage.TABLE_SKILL_VERSIONS,
|
|
13542
16863
|
columns: ["skillId", "versionNumber"],
|
|
13543
16864
|
unique: true
|
|
13544
16865
|
}
|
|
13545
16866
|
];
|
|
13546
16867
|
}
|
|
16868
|
+
static getExportDDL(schemaName) {
|
|
16869
|
+
const statements = [];
|
|
16870
|
+
const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
|
|
16871
|
+
const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
|
|
16872
|
+
for (const tableName of _SkillsPG.MANAGED_TABLES) {
|
|
16873
|
+
statements.push(
|
|
16874
|
+
generateTableSQL({
|
|
16875
|
+
tableName,
|
|
16876
|
+
schema: storage.TABLE_SCHEMAS[tableName],
|
|
16877
|
+
schemaName,
|
|
16878
|
+
includeAllConstraints: true
|
|
16879
|
+
})
|
|
16880
|
+
);
|
|
16881
|
+
}
|
|
16882
|
+
for (const idx of _SkillsPG.getDefaultIndexDefs(schemaPrefix)) {
|
|
16883
|
+
statements.push(generateIndexSQL(idx, schemaName));
|
|
16884
|
+
}
|
|
16885
|
+
return statements;
|
|
16886
|
+
}
|
|
16887
|
+
getDefaultIndexDefinitions() {
|
|
16888
|
+
const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
|
|
16889
|
+
return _SkillsPG.getDefaultIndexDefs(schemaPrefix);
|
|
16890
|
+
}
|
|
13547
16891
|
async createDefaultIndexes() {
|
|
13548
16892
|
if (this.#skipDefaultIndexes) {
|
|
13549
16893
|
return;
|
|
@@ -14241,6 +17585,254 @@ var SkillsPG = class _SkillsPG extends storage.SkillsStorage {
|
|
|
14241
17585
|
};
|
|
14242
17586
|
}
|
|
14243
17587
|
};
|
|
17588
|
+
function normaliseScope(raw) {
|
|
17589
|
+
const value = raw == null ? "per-author" : String(raw);
|
|
17590
|
+
if (value === "shared") return "shared";
|
|
17591
|
+
if (value === "caller-supplied") return "caller-supplied";
|
|
17592
|
+
return "per-author";
|
|
17593
|
+
}
|
|
17594
|
+
function rowToToolProviderConnection(row) {
|
|
17595
|
+
return {
|
|
17596
|
+
authorId: String(row.authorId),
|
|
17597
|
+
providerId: String(row.providerId),
|
|
17598
|
+
toolkit: String(row.toolkit),
|
|
17599
|
+
connectionId: String(row.connectionId),
|
|
17600
|
+
label: row.label == null ? null : String(row.label),
|
|
17601
|
+
scope: normaliseScope(row.scope),
|
|
17602
|
+
createdAt: new Date(String(row.createdAtZ ?? row.createdAt)),
|
|
17603
|
+
updatedAt: new Date(String(row.updatedAtZ ?? row.updatedAt))
|
|
17604
|
+
};
|
|
17605
|
+
}
|
|
17606
|
+
var ToolProviderConnectionsPG = class _ToolProviderConnectionsPG extends storage.ToolProviderConnectionsStorage {
|
|
17607
|
+
#db;
|
|
17608
|
+
#schema;
|
|
17609
|
+
#skipDefaultIndexes;
|
|
17610
|
+
#indexes;
|
|
17611
|
+
static MANAGED_TABLES = [storage.TABLE_TOOL_PROVIDER_CONNECTIONS];
|
|
17612
|
+
constructor(config) {
|
|
17613
|
+
super();
|
|
17614
|
+
const { client, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
|
|
17615
|
+
this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
|
|
17616
|
+
this.#schema = schemaName || "public";
|
|
17617
|
+
this.#skipDefaultIndexes = skipDefaultIndexes;
|
|
17618
|
+
this.#indexes = indexes?.filter(
|
|
17619
|
+
(idx) => _ToolProviderConnectionsPG.MANAGED_TABLES.includes(idx.table)
|
|
17620
|
+
);
|
|
17621
|
+
}
|
|
17622
|
+
async init() {
|
|
17623
|
+
await this.#db.createTable({
|
|
17624
|
+
tableName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
|
|
17625
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_TOOL_PROVIDER_CONNECTIONS],
|
|
17626
|
+
compositePrimaryKey: ["authorId", "providerId", "connectionId"]
|
|
17627
|
+
});
|
|
17628
|
+
await this.createDefaultIndexes();
|
|
17629
|
+
await this.createCustomIndexes();
|
|
17630
|
+
}
|
|
17631
|
+
static getDefaultIndexDefs(schemaPrefix) {
|
|
17632
|
+
return [
|
|
17633
|
+
{
|
|
17634
|
+
name: `${schemaPrefix}idx_tool_provider_connections_author`,
|
|
17635
|
+
table: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
|
|
17636
|
+
columns: ["authorId", "providerId", "toolkit"]
|
|
17637
|
+
}
|
|
17638
|
+
];
|
|
17639
|
+
}
|
|
17640
|
+
static getExportDDL(schemaName) {
|
|
17641
|
+
const statements = [];
|
|
17642
|
+
const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
|
|
17643
|
+
const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
|
|
17644
|
+
statements.push(
|
|
17645
|
+
generateTableSQL({
|
|
17646
|
+
tableName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
|
|
17647
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_TOOL_PROVIDER_CONNECTIONS],
|
|
17648
|
+
schemaName,
|
|
17649
|
+
compositePrimaryKey: ["authorId", "providerId", "connectionId"],
|
|
17650
|
+
includeAllConstraints: true
|
|
17651
|
+
})
|
|
17652
|
+
);
|
|
17653
|
+
for (const idx of _ToolProviderConnectionsPG.getDefaultIndexDefs(schemaPrefix)) {
|
|
17654
|
+
statements.push(generateIndexSQL(idx, schemaName));
|
|
17655
|
+
}
|
|
17656
|
+
return statements;
|
|
17657
|
+
}
|
|
17658
|
+
getDefaultIndexDefinitions() {
|
|
17659
|
+
const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
|
|
17660
|
+
return _ToolProviderConnectionsPG.getDefaultIndexDefs(schemaPrefix);
|
|
17661
|
+
}
|
|
17662
|
+
async createDefaultIndexes() {
|
|
17663
|
+
if (this.#skipDefaultIndexes) return;
|
|
17664
|
+
for (const indexDef of this.getDefaultIndexDefinitions()) {
|
|
17665
|
+
try {
|
|
17666
|
+
await this.#db.createIndex(indexDef);
|
|
17667
|
+
} catch (error) {
|
|
17668
|
+
this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
|
|
17669
|
+
}
|
|
17670
|
+
}
|
|
17671
|
+
}
|
|
17672
|
+
async createCustomIndexes() {
|
|
17673
|
+
if (!this.#indexes || this.#indexes.length === 0) return;
|
|
17674
|
+
for (const indexDef of this.#indexes) {
|
|
17675
|
+
try {
|
|
17676
|
+
await this.#db.createIndex(indexDef);
|
|
17677
|
+
} catch (error) {
|
|
17678
|
+
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
17679
|
+
}
|
|
17680
|
+
}
|
|
17681
|
+
}
|
|
17682
|
+
async dangerouslyClearAll() {
|
|
17683
|
+
await this.#db.clearTable({ tableName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS });
|
|
17684
|
+
}
|
|
17685
|
+
async getConnectionById({
|
|
17686
|
+
authorId,
|
|
17687
|
+
providerId,
|
|
17688
|
+
connectionId
|
|
17689
|
+
}) {
|
|
17690
|
+
const tableName = getTableName2({
|
|
17691
|
+
indexName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
|
|
17692
|
+
schemaName: getSchemaName2(this.#schema)
|
|
17693
|
+
});
|
|
17694
|
+
try {
|
|
17695
|
+
const row = await this.#db.client.oneOrNone(
|
|
17696
|
+
`SELECT * FROM ${tableName} WHERE "authorId" = $1 AND "providerId" = $2 AND "connectionId" = $3 LIMIT 1`,
|
|
17697
|
+
[authorId, providerId, connectionId]
|
|
17698
|
+
);
|
|
17699
|
+
return row ? rowToToolProviderConnection(row) : null;
|
|
17700
|
+
} catch (error$1) {
|
|
17701
|
+
throw new error.MastraError(
|
|
17702
|
+
{
|
|
17703
|
+
id: storage.createStorageErrorId("PG", "TOOL_PROVIDER_CONNECTION_GET", "FAILED"),
|
|
17704
|
+
domain: error.ErrorDomain.STORAGE,
|
|
17705
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
17706
|
+
details: { authorId, providerId, connectionId }
|
|
17707
|
+
},
|
|
17708
|
+
error$1
|
|
17709
|
+
);
|
|
17710
|
+
}
|
|
17711
|
+
}
|
|
17712
|
+
async upsertConnection(input) {
|
|
17713
|
+
const { authorId, providerId, toolkit, connectionId, label } = input;
|
|
17714
|
+
const tableName = getTableName2({
|
|
17715
|
+
indexName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
|
|
17716
|
+
schemaName: getSchemaName2(this.#schema)
|
|
17717
|
+
});
|
|
17718
|
+
const now = /* @__PURE__ */ new Date();
|
|
17719
|
+
const nowIso = now.toISOString();
|
|
17720
|
+
const labelValue = label == null ? null : label;
|
|
17721
|
+
try {
|
|
17722
|
+
return await this.#db.client.tx(async (t) => {
|
|
17723
|
+
const existing = await t.oneOrNone(
|
|
17724
|
+
`SELECT "createdAt", "createdAtZ", scope FROM ${tableName} WHERE "authorId" = $1 AND "providerId" = $2 AND "connectionId" = $3 LIMIT 1`,
|
|
17725
|
+
[authorId, providerId, connectionId]
|
|
17726
|
+
);
|
|
17727
|
+
const existingCreatedAt = existing ? existing.createdAtZ ?? existing.createdAt : null;
|
|
17728
|
+
const createdAt = existingCreatedAt != null ? new Date(existingCreatedAt).toISOString() : nowIso;
|
|
17729
|
+
const existingScope = existing && existing.scope != null ? normaliseScope(existing.scope) : void 0;
|
|
17730
|
+
const scope = input.scope ?? existingScope ?? "per-author";
|
|
17731
|
+
await t.none(
|
|
17732
|
+
`INSERT INTO ${tableName} ("authorId", "providerId", toolkit, "connectionId", label, scope, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ")
|
|
17733
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
17734
|
+
ON CONFLICT ("authorId", "providerId", "connectionId") DO UPDATE SET
|
|
17735
|
+
toolkit = EXCLUDED.toolkit,
|
|
17736
|
+
label = EXCLUDED.label,
|
|
17737
|
+
scope = EXCLUDED.scope,
|
|
17738
|
+
"updatedAt" = EXCLUDED."updatedAt",
|
|
17739
|
+
"updatedAtZ" = EXCLUDED."updatedAtZ"`,
|
|
17740
|
+
[authorId, providerId, toolkit, connectionId, labelValue, scope, createdAt, createdAt, nowIso, nowIso]
|
|
17741
|
+
);
|
|
17742
|
+
return {
|
|
17743
|
+
authorId,
|
|
17744
|
+
providerId,
|
|
17745
|
+
toolkit,
|
|
17746
|
+
connectionId,
|
|
17747
|
+
label: labelValue,
|
|
17748
|
+
scope,
|
|
17749
|
+
createdAt: new Date(createdAt),
|
|
17750
|
+
updatedAt: now
|
|
17751
|
+
};
|
|
17752
|
+
});
|
|
17753
|
+
} catch (error$1) {
|
|
17754
|
+
throw new error.MastraError(
|
|
17755
|
+
{
|
|
17756
|
+
id: storage.createStorageErrorId("PG", "TOOL_PROVIDER_CONNECTION_UPSERT", "FAILED"),
|
|
17757
|
+
domain: error.ErrorDomain.STORAGE,
|
|
17758
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
17759
|
+
details: { authorId, providerId, connectionId }
|
|
17760
|
+
},
|
|
17761
|
+
error$1
|
|
17762
|
+
);
|
|
17763
|
+
}
|
|
17764
|
+
}
|
|
17765
|
+
async listConnectionsByAuthor({
|
|
17766
|
+
authorId,
|
|
17767
|
+
providerId,
|
|
17768
|
+
toolkit,
|
|
17769
|
+
scope
|
|
17770
|
+
}) {
|
|
17771
|
+
const tableName = getTableName2({
|
|
17772
|
+
indexName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
|
|
17773
|
+
schemaName: getSchemaName2(this.#schema)
|
|
17774
|
+
});
|
|
17775
|
+
try {
|
|
17776
|
+
const clauses = [];
|
|
17777
|
+
const args = [];
|
|
17778
|
+
if (authorId !== void 0) {
|
|
17779
|
+
args.push(authorId);
|
|
17780
|
+
clauses.push(`"authorId" = $${args.length}`);
|
|
17781
|
+
}
|
|
17782
|
+
if (providerId) {
|
|
17783
|
+
args.push(providerId);
|
|
17784
|
+
clauses.push(`"providerId" = $${args.length}`);
|
|
17785
|
+
}
|
|
17786
|
+
if (toolkit) {
|
|
17787
|
+
args.push(toolkit);
|
|
17788
|
+
clauses.push(`toolkit = $${args.length}`);
|
|
17789
|
+
}
|
|
17790
|
+
if (scope) {
|
|
17791
|
+
args.push(scope);
|
|
17792
|
+
clauses.push(`scope = $${args.length}`);
|
|
17793
|
+
}
|
|
17794
|
+
const whereClause = clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : "";
|
|
17795
|
+
const rows = await this.#db.client.manyOrNone(`SELECT * FROM ${tableName}${whereClause}`, args);
|
|
17796
|
+
return rows.map((row) => rowToToolProviderConnection(row));
|
|
17797
|
+
} catch (error$1) {
|
|
17798
|
+
throw new error.MastraError(
|
|
17799
|
+
{
|
|
17800
|
+
id: storage.createStorageErrorId("PG", "TOOL_PROVIDER_CONNECTION_LIST", "FAILED"),
|
|
17801
|
+
domain: error.ErrorDomain.STORAGE,
|
|
17802
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
17803
|
+
details: { authorId: authorId ?? "", providerId: providerId ?? "", toolkit: toolkit ?? "" }
|
|
17804
|
+
},
|
|
17805
|
+
error$1
|
|
17806
|
+
);
|
|
17807
|
+
}
|
|
17808
|
+
}
|
|
17809
|
+
async deleteConnection({
|
|
17810
|
+
authorId,
|
|
17811
|
+
providerId,
|
|
17812
|
+
connectionId
|
|
17813
|
+
}) {
|
|
17814
|
+
const tableName = getTableName2({
|
|
17815
|
+
indexName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
|
|
17816
|
+
schemaName: getSchemaName2(this.#schema)
|
|
17817
|
+
});
|
|
17818
|
+
try {
|
|
17819
|
+
await this.#db.client.none(
|
|
17820
|
+
`DELETE FROM ${tableName} WHERE "authorId" = $1 AND "providerId" = $2 AND "connectionId" = $3`,
|
|
17821
|
+
[authorId, providerId, connectionId]
|
|
17822
|
+
);
|
|
17823
|
+
} catch (error$1) {
|
|
17824
|
+
throw new error.MastraError(
|
|
17825
|
+
{
|
|
17826
|
+
id: storage.createStorageErrorId("PG", "TOOL_PROVIDER_CONNECTION_DELETE", "FAILED"),
|
|
17827
|
+
domain: error.ErrorDomain.STORAGE,
|
|
17828
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
17829
|
+
details: { authorId, providerId, connectionId }
|
|
17830
|
+
},
|
|
17831
|
+
error$1
|
|
17832
|
+
);
|
|
17833
|
+
}
|
|
17834
|
+
}
|
|
17835
|
+
};
|
|
14244
17836
|
function getSchemaName7(schema) {
|
|
14245
17837
|
return schema ? `"${schema}"` : '"public"';
|
|
14246
17838
|
}
|
|
@@ -14381,8 +17973,7 @@ var WorkflowsPG = class _WorkflowsPG extends storage.WorkflowsStorage {
|
|
|
14381
17973
|
const existingSnapshot = existingSnapshotResult.snapshot;
|
|
14382
17974
|
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
14383
17975
|
}
|
|
14384
|
-
snapshot
|
|
14385
|
-
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
17976
|
+
storage.mergeWorkflowStepResult({ snapshot, stepId, result, requestContext });
|
|
14386
17977
|
const now = /* @__PURE__ */ new Date();
|
|
14387
17978
|
const sanitizedSnapshot = sanitizeJsonForPg(JSON.stringify(snapshot));
|
|
14388
17979
|
await t.none(
|
|
@@ -14574,7 +18165,7 @@ var WorkflowsPG = class _WorkflowsPG extends storage.WorkflowsStorage {
|
|
|
14574
18165
|
async listWorkflowRuns({
|
|
14575
18166
|
workflowName,
|
|
14576
18167
|
fromDate,
|
|
14577
|
-
toDate,
|
|
18168
|
+
toDate: toDate2,
|
|
14578
18169
|
perPage,
|
|
14579
18170
|
page,
|
|
14580
18171
|
resourceId,
|
|
@@ -14611,9 +18202,9 @@ var WorkflowsPG = class _WorkflowsPG extends storage.WorkflowsStorage {
|
|
|
14611
18202
|
values.push(fromDate);
|
|
14612
18203
|
paramIndex++;
|
|
14613
18204
|
}
|
|
14614
|
-
if (
|
|
18205
|
+
if (toDate2) {
|
|
14615
18206
|
conditions.push(`"createdAt" <= $${paramIndex}`);
|
|
14616
|
-
values.push(
|
|
18207
|
+
values.push(toDate2);
|
|
14617
18208
|
paramIndex++;
|
|
14618
18209
|
}
|
|
14619
18210
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
@@ -14681,16 +18272,39 @@ var WorkspacesPG = class _WorkspacesPG extends storage.WorkspacesStorage {
|
|
|
14681
18272
|
this.#skipDefaultIndexes = skipDefaultIndexes;
|
|
14682
18273
|
this.#indexes = indexes?.filter((idx) => _WorkspacesPG.MANAGED_TABLES.includes(idx.table));
|
|
14683
18274
|
}
|
|
14684
|
-
|
|
18275
|
+
static getDefaultIndexDefs(schemaPrefix) {
|
|
14685
18276
|
return [
|
|
14686
18277
|
{
|
|
14687
|
-
name:
|
|
18278
|
+
name: `${schemaPrefix}idx_workspace_versions_workspace_version`,
|
|
14688
18279
|
table: storage.TABLE_WORKSPACE_VERSIONS,
|
|
14689
18280
|
columns: ["workspaceId", "versionNumber"],
|
|
14690
18281
|
unique: true
|
|
14691
18282
|
}
|
|
14692
18283
|
];
|
|
14693
18284
|
}
|
|
18285
|
+
static getExportDDL(schemaName) {
|
|
18286
|
+
const statements = [];
|
|
18287
|
+
const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
|
|
18288
|
+
const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
|
|
18289
|
+
for (const tableName of _WorkspacesPG.MANAGED_TABLES) {
|
|
18290
|
+
statements.push(
|
|
18291
|
+
generateTableSQL({
|
|
18292
|
+
tableName,
|
|
18293
|
+
schema: storage.TABLE_SCHEMAS[tableName],
|
|
18294
|
+
schemaName,
|
|
18295
|
+
includeAllConstraints: true
|
|
18296
|
+
})
|
|
18297
|
+
);
|
|
18298
|
+
}
|
|
18299
|
+
for (const idx of _WorkspacesPG.getDefaultIndexDefs(schemaPrefix)) {
|
|
18300
|
+
statements.push(generateIndexSQL(idx, schemaName));
|
|
18301
|
+
}
|
|
18302
|
+
return statements;
|
|
18303
|
+
}
|
|
18304
|
+
getDefaultIndexDefinitions() {
|
|
18305
|
+
const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
|
|
18306
|
+
return _WorkspacesPG.getDefaultIndexDefs(schemaPrefix);
|
|
18307
|
+
}
|
|
14694
18308
|
async createDefaultIndexes() {
|
|
14695
18309
|
if (this.#skipDefaultIndexes) {
|
|
14696
18310
|
return;
|
|
@@ -15332,19 +18946,30 @@ var WorkspacesPG = class _WorkspacesPG extends storage.WorkspacesStorage {
|
|
|
15332
18946
|
};
|
|
15333
18947
|
}
|
|
15334
18948
|
};
|
|
15335
|
-
function buildConnectionStringPoolConfig(config, defaults) {
|
|
15336
|
-
const parsed = pgConnectionString.parse(config.connectionString);
|
|
15337
|
-
return {
|
|
15338
|
-
...parsed,
|
|
15339
|
-
...config.ssl !== void 0 ? { ssl: config.ssl } : {},
|
|
15340
|
-
max: config.max ?? defaults.max,
|
|
15341
|
-
idleTimeoutMillis: config.idleTimeoutMillis ?? defaults.idleTimeoutMillis
|
|
15342
|
-
};
|
|
15343
|
-
}
|
|
15344
18949
|
|
|
15345
18950
|
// src/storage/index.ts
|
|
15346
18951
|
var DEFAULT_MAX_CONNECTIONS = 20;
|
|
15347
18952
|
var DEFAULT_IDLE_TIMEOUT_MS = 3e4;
|
|
18953
|
+
function createConnectionStringPool(config) {
|
|
18954
|
+
return new pg.Pool(
|
|
18955
|
+
buildConnectionStringPoolConfig(config, {
|
|
18956
|
+
max: DEFAULT_MAX_CONNECTIONS,
|
|
18957
|
+
idleTimeoutMillis: DEFAULT_IDLE_TIMEOUT_MS
|
|
18958
|
+
})
|
|
18959
|
+
);
|
|
18960
|
+
}
|
|
18961
|
+
function createHostPool(config) {
|
|
18962
|
+
return new pg.Pool({
|
|
18963
|
+
host: config.host,
|
|
18964
|
+
port: config.port,
|
|
18965
|
+
database: config.database,
|
|
18966
|
+
user: config.user,
|
|
18967
|
+
password: config.password,
|
|
18968
|
+
ssl: config.ssl,
|
|
18969
|
+
max: config.max ?? DEFAULT_MAX_CONNECTIONS,
|
|
18970
|
+
idleTimeoutMillis: config.idleTimeoutMillis ?? DEFAULT_IDLE_TIMEOUT_MS
|
|
18971
|
+
});
|
|
18972
|
+
}
|
|
15348
18973
|
var ALL_DOMAINS = [
|
|
15349
18974
|
MemoryPG,
|
|
15350
18975
|
NotificationsPG,
|
|
@@ -15353,6 +18978,12 @@ var ALL_DOMAINS = [
|
|
|
15353
18978
|
ScorerDefinitionsPG,
|
|
15354
18979
|
PromptBlocksPG,
|
|
15355
18980
|
AgentsPG,
|
|
18981
|
+
MCPClientsPG,
|
|
18982
|
+
MCPServersPG,
|
|
18983
|
+
WorkspacesPG,
|
|
18984
|
+
SkillsPG,
|
|
18985
|
+
BlobsPG,
|
|
18986
|
+
ToolProviderConnectionsPG,
|
|
15356
18987
|
WorkflowsPG,
|
|
15357
18988
|
DatasetsPG,
|
|
15358
18989
|
ExperimentsPG,
|
|
@@ -15377,6 +19008,7 @@ var PostgresStore = class extends storage.MastraCompositeStore {
|
|
|
15377
19008
|
#pool;
|
|
15378
19009
|
#db;
|
|
15379
19010
|
#ownsPool;
|
|
19011
|
+
#poolClosed = false;
|
|
15380
19012
|
schema;
|
|
15381
19013
|
isInitialized = false;
|
|
15382
19014
|
stores;
|
|
@@ -15413,6 +19045,7 @@ var PostgresStore = class extends storage.MastraCompositeStore {
|
|
|
15413
19045
|
workspaces: new WorkspacesPG(domainConfig),
|
|
15414
19046
|
skills: new SkillsPG(domainConfig),
|
|
15415
19047
|
favorites: new FavoritesPG(domainConfig),
|
|
19048
|
+
toolProviderConnections: new ToolProviderConnectionsPG(domainConfig),
|
|
15416
19049
|
blobs: new BlobsPG(domainConfig),
|
|
15417
19050
|
datasets: new DatasetsPG(domainConfig),
|
|
15418
19051
|
experiments: new ExperimentsPG(domainConfig),
|
|
@@ -15433,24 +19066,10 @@ var PostgresStore = class extends storage.MastraCompositeStore {
|
|
|
15433
19066
|
}
|
|
15434
19067
|
createPool(config) {
|
|
15435
19068
|
if (isConnectionStringConfig(config)) {
|
|
15436
|
-
return
|
|
15437
|
-
buildConnectionStringPoolConfig(config, {
|
|
15438
|
-
max: DEFAULT_MAX_CONNECTIONS,
|
|
15439
|
-
idleTimeoutMillis: DEFAULT_IDLE_TIMEOUT_MS
|
|
15440
|
-
})
|
|
15441
|
-
);
|
|
19069
|
+
return createConnectionStringPool(config);
|
|
15442
19070
|
}
|
|
15443
19071
|
if (isHostConfig(config)) {
|
|
15444
|
-
return
|
|
15445
|
-
host: config.host,
|
|
15446
|
-
port: config.port,
|
|
15447
|
-
database: config.database,
|
|
15448
|
-
user: config.user,
|
|
15449
|
-
password: config.password,
|
|
15450
|
-
ssl: config.ssl,
|
|
15451
|
-
max: config.max ?? DEFAULT_MAX_CONNECTIONS,
|
|
15452
|
-
idleTimeoutMillis: config.idleTimeoutMillis ?? DEFAULT_IDLE_TIMEOUT_MS
|
|
15453
|
-
});
|
|
19072
|
+
return createHostPool(config);
|
|
15454
19073
|
}
|
|
15455
19074
|
if (isCloudSqlConfig(config)) {
|
|
15456
19075
|
return new pg.Pool(config);
|
|
@@ -15500,13 +19119,81 @@ var PostgresStore = class extends storage.MastraCompositeStore {
|
|
|
15500
19119
|
/**
|
|
15501
19120
|
* Closes the connection pool if it was created by this store.
|
|
15502
19121
|
* If a pool was passed in via config, it will not be closed.
|
|
19122
|
+
* Safe to call multiple times — subsequent calls are no-ops.
|
|
15503
19123
|
*/
|
|
15504
19124
|
async close() {
|
|
15505
|
-
if (this.#ownsPool) {
|
|
19125
|
+
if (this.#ownsPool && !this.#poolClosed) {
|
|
19126
|
+
this.#poolClosed = true;
|
|
15506
19127
|
await this.#pool.end();
|
|
15507
19128
|
}
|
|
15508
19129
|
}
|
|
15509
19130
|
};
|
|
19131
|
+
function isSameConnectionTarget(primary, observability) {
|
|
19132
|
+
if ("pool" in primary && "pool" in observability) {
|
|
19133
|
+
return primary.pool === observability.pool;
|
|
19134
|
+
}
|
|
19135
|
+
if ("connectionString" in primary && "connectionString" in observability) {
|
|
19136
|
+
return primary.connectionString === observability.connectionString;
|
|
19137
|
+
}
|
|
19138
|
+
if ("host" in primary && "host" in observability) {
|
|
19139
|
+
return primary.host === observability.host && (primary.port ?? 5432) === (observability.port ?? 5432) && primary.database === observability.database;
|
|
19140
|
+
}
|
|
19141
|
+
return false;
|
|
19142
|
+
}
|
|
19143
|
+
var COLLISION_WARNING = "PostgresStoreVNext: the `observability` connection appears to point at the same Postgres instance as the primary store. For production workloads, point observability at a dedicated Postgres instance to avoid degrading your application database performance.";
|
|
19144
|
+
var PostgresStoreVNext = class extends PostgresStore {
|
|
19145
|
+
#observabilityPool;
|
|
19146
|
+
#ownsObservabilityPool = false;
|
|
19147
|
+
#observabilityPoolClosed = false;
|
|
19148
|
+
constructor(config) {
|
|
19149
|
+
super(config);
|
|
19150
|
+
this.name = "PostgresStoreVNext";
|
|
19151
|
+
const obsConfig = config.observability;
|
|
19152
|
+
if (isSameConnectionTarget(config, obsConfig)) {
|
|
19153
|
+
console.warn(COLLISION_WARNING);
|
|
19154
|
+
}
|
|
19155
|
+
const built = this.#createObservabilityClient(obsConfig);
|
|
19156
|
+
const observabilityClient = built.client;
|
|
19157
|
+
this.#observabilityPool = built.pool;
|
|
19158
|
+
this.#ownsObservabilityPool = built.owned;
|
|
19159
|
+
const observability = new ObservabilityStoragePostgresVNext({
|
|
19160
|
+
client: observabilityClient,
|
|
19161
|
+
schemaName: obsConfig.schemaName ?? config.schemaName,
|
|
19162
|
+
partitioning: obsConfig.partitioning,
|
|
19163
|
+
discovery: obsConfig.discovery
|
|
19164
|
+
});
|
|
19165
|
+
this.stores = {
|
|
19166
|
+
...this.stores,
|
|
19167
|
+
observability
|
|
19168
|
+
};
|
|
19169
|
+
}
|
|
19170
|
+
#createObservabilityClient(cfg) {
|
|
19171
|
+
if ("pool" in cfg && cfg.pool) {
|
|
19172
|
+
return { client: new PoolAdapter(cfg.pool), pool: cfg.pool, owned: false };
|
|
19173
|
+
}
|
|
19174
|
+
if ("connectionString" in cfg && typeof cfg.connectionString === "string") {
|
|
19175
|
+
const pool2 = createConnectionStringPool(cfg);
|
|
19176
|
+
return { client: new PoolAdapter(pool2), pool: pool2, owned: true };
|
|
19177
|
+
}
|
|
19178
|
+
if ("host" in cfg) {
|
|
19179
|
+
const pool2 = createHostPool(cfg);
|
|
19180
|
+
return { client: new PoolAdapter(pool2), pool: pool2, owned: true };
|
|
19181
|
+
}
|
|
19182
|
+
const pool = new pg.Pool(cfg);
|
|
19183
|
+
return { client: new PoolAdapter(pool), pool, owned: true };
|
|
19184
|
+
}
|
|
19185
|
+
/**
|
|
19186
|
+
* Closes both the primary pool (when owned) and the observability pool
|
|
19187
|
+
* (when this store created it). Safe to call multiple times.
|
|
19188
|
+
*/
|
|
19189
|
+
async close() {
|
|
19190
|
+
await super.close();
|
|
19191
|
+
if (this.#ownsObservabilityPool && this.#observabilityPool && !this.#observabilityPoolClosed) {
|
|
19192
|
+
this.#observabilityPoolClosed = true;
|
|
19193
|
+
await this.#observabilityPool.end();
|
|
19194
|
+
}
|
|
19195
|
+
}
|
|
19196
|
+
};
|
|
15510
19197
|
|
|
15511
19198
|
// src/vector/prompt.ts
|
|
15512
19199
|
var PGVECTOR_PROMPT = `When querying PG Vector, you can ONLY use the operators listed below. Any other operators will be rejected.
|
|
@@ -15619,15 +19306,18 @@ exports.MCPServersPG = MCPServersPG;
|
|
|
15619
19306
|
exports.MemoryPG = MemoryPG;
|
|
15620
19307
|
exports.NotificationsPG = NotificationsPG;
|
|
15621
19308
|
exports.ObservabilityPG = ObservabilityPG;
|
|
19309
|
+
exports.ObservabilityStoragePostgresVNext = ObservabilityStoragePostgresVNext;
|
|
15622
19310
|
exports.PGVECTOR_PROMPT = PGVECTOR_PROMPT;
|
|
15623
19311
|
exports.PgVector = PgVector;
|
|
15624
19312
|
exports.PoolAdapter = PoolAdapter;
|
|
15625
19313
|
exports.PostgresStore = PostgresStore;
|
|
19314
|
+
exports.PostgresStoreVNext = PostgresStoreVNext;
|
|
15626
19315
|
exports.PromptBlocksPG = PromptBlocksPG;
|
|
15627
19316
|
exports.SchedulesPG = SchedulesPG;
|
|
15628
19317
|
exports.ScorerDefinitionsPG = ScorerDefinitionsPG;
|
|
15629
19318
|
exports.ScoresPG = ScoresPG;
|
|
15630
19319
|
exports.SkillsPG = SkillsPG;
|
|
19320
|
+
exports.ToolProviderConnectionsPG = ToolProviderConnectionsPG;
|
|
15631
19321
|
exports.WorkflowsPG = WorkflowsPG;
|
|
15632
19322
|
exports.WorkspacesPG = WorkspacesPG;
|
|
15633
19323
|
exports.exportSchemas = exportSchemas;
|