duron 0.3.0-beta.12 → 0.3.0-beta.13
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.
|
@@ -183,19 +183,28 @@ export declare class PostgresBaseAdapter<Database extends DrizzleDatabase, Conne
|
|
|
183
183
|
protected _insertSpans(spans: InsertSpanOptions[]): Promise<number>;
|
|
184
184
|
/**
|
|
185
185
|
* Internal method to get spans for a job or step.
|
|
186
|
+
* For step queries, uses a recursive CTE to find all descendant spans.
|
|
186
187
|
*/
|
|
187
188
|
protected _getSpans(options: GetSpansOptions): Promise<GetSpansResult>;
|
|
189
|
+
/**
|
|
190
|
+
* Get spans for a step using a recursive CTE to traverse the span hierarchy.
|
|
191
|
+
* This returns the step's span and all its descendant spans (children, grandchildren, etc.)
|
|
192
|
+
*/
|
|
193
|
+
protected _getStepSpansRecursive(stepId: string, sortField: string, sortOrder: string, _filters?: GetSpansOptions['filters']): Promise<GetSpansResult>;
|
|
188
194
|
/**
|
|
189
195
|
* Internal method to delete all spans for a job.
|
|
190
196
|
*/
|
|
191
197
|
protected _deleteSpans(options: DeleteSpansOptions): Promise<number>;
|
|
192
198
|
/**
|
|
193
|
-
* Build WHERE clause for spans queries.
|
|
194
|
-
* When querying by jobId
|
|
195
|
-
* as spans with that job
|
|
199
|
+
* Build WHERE clause for spans queries (used for job queries only).
|
|
200
|
+
* When querying by jobId, we find all spans that share the same trace_id
|
|
201
|
+
* as spans with that job. This includes spans from external libraries that
|
|
196
202
|
* don't have the duron.job.id attribute but are part of the same trace.
|
|
203
|
+
*
|
|
204
|
+
* Note: Step queries are handled separately by _getStepSpansRecursive using
|
|
205
|
+
* a recursive CTE to traverse the span hierarchy.
|
|
197
206
|
*/
|
|
198
|
-
protected _buildSpansWhereClause(jobId?: string,
|
|
207
|
+
protected _buildSpansWhereClause(jobId?: string, _stepId?: string, filters?: GetSpansOptions['filters']): import("drizzle-orm").SQL<unknown> | undefined;
|
|
199
208
|
/**
|
|
200
209
|
* Send a PostgreSQL notification.
|
|
201
210
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/adapters/postgres/base.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/adapters/postgres/base.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAY,MAAM,qBAAqB,CAAA;AAapE,OAAO,EACL,OAAO,EACP,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,6BAA6B,EAClC,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,GAAG,EAER,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EAEpB,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAA;AACtB,OAAO,YAAY,MAAM,aAAa,CAAA;AAEtC,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAA;AAG7C,YAAY,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEjD,KAAK,eAAe,GAAG,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;AAEnD,MAAM,WAAW,cAAc,CAAC,UAAU;IACxC,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,qBAAa,mBAAmB,CAAC,QAAQ,SAAS,eAAe,EAAE,UAAU,CAAE,SAAQ,OAAO;;IAC5F,SAAS,CAAC,UAAU,EAAE,UAAU,CAAA;IAChC,SAAS,CAAC,EAAE,EAAG,QAAQ,CAAA;IACvB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAU;IAClC,SAAS,CAAC,cAAc,EAAE,OAAO,CAAO;IAMxC;;;;OAIG;gBACS,OAAO,EAAE,cAAc,CAAC,UAAU,CAAC;IAY/C;;OAEG;IACH,SAAS,CAAC,OAAO;IAQjB;;;;;OAKG;cACa,MAAM;cAqBN,KAAK;IAQrB;;;;OAIG;cACa,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,EAAE,EAAE,gBAAgB;IAqB9G;;;;OAIG;cACa,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,kBAAkB;IAsBlE;;;;OAIG;cACa,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,cAAc;IAqBzD;;;;OAIG;cACa,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,gBAAgB;IAmBtD;;;;;OAKG;cACa,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAgF7E;;;;;;;;;;;;;;;;;;OAkBG;cACa,cAAc,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;IA2KzF;;;;;OAKG;cACa,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAczE;;;;;OAKG;cACa,WAAW,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAWzE;;;;;;OAMG;cACa,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY;IAmH9C;;;;;OAKG;cACa,YAAY,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAiF1E;;;;OAIG;cACa,uBAAuB,CAAC,EACtC,KAAK,EACL,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,QAAgB,GACjB,EAAE,6BAA6B,GAAG,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC;IAwG/E;;;;OAIG;cACa,gBAAgB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,sBAAsB;IAwB3E;;;;OAIG;cACa,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,kBAAkB;IAuBlE;;;;OAIG;cACa,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,mBAAmB;IAkC7E;;;;OAIG;cACa,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE,oBAAoB;IA6B/D;;OAEG;cACa,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAsC/D;;;;OAIG;cACa,YAAY,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAkDrF,SAAS,CAAC,qBAAqB,CAAC,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC;IA6ElE;;;OAGG;cACa,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAqF1E;;OAEG;cACa,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IA6BxE;;OAEG;cACa,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAa7E;;OAEG;cACa,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAatF;;OAEG;cACa,WAAW,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAgDxD;;OAEG;cACa,YAAY,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IA6BzE;;;OAGG;cACa,SAAS,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IA0E5E;;;OAGG;cACa,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,eAAe,CAAC,SAAS,CAAC,GACpC,OAAO,CAAC,cAAc,CAAC;IA0E1B;;OAEG;cACa,YAAY,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAS1E;;;;;;;;OAQG;IACH,SAAS,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,SAAS,CAAC;IAyIvG;;;;;;OAMG;cACa,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlE;;;;;;OAMG;cACa,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAShH;;;;;;OAMG;IACH,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG;CAG3B"}
|
|
@@ -1139,19 +1139,26 @@ export class PostgresBaseAdapter extends Adapter {
|
|
|
1139
1139
|
}
|
|
1140
1140
|
/**
|
|
1141
1141
|
* Internal method to get spans for a job or step.
|
|
1142
|
+
* For step queries, uses a recursive CTE to find all descendant spans.
|
|
1142
1143
|
*/
|
|
1143
1144
|
async _getSpans(options) {
|
|
1144
1145
|
const spansTable = this.tables.spansTable;
|
|
1145
1146
|
const filters = options.filters ?? {};
|
|
1146
|
-
// Build WHERE clause
|
|
1147
|
-
const where = this._buildSpansWhereClause(options.jobId, options.stepId, filters);
|
|
1148
1147
|
// Build sort
|
|
1149
1148
|
const sortInput = options.sort ?? { field: 'startTimeUnixNano', order: 'asc' };
|
|
1150
1149
|
const sortFieldMap = {
|
|
1151
|
-
name:
|
|
1152
|
-
startTimeUnixNano:
|
|
1153
|
-
endTimeUnixNano:
|
|
1150
|
+
name: 'name',
|
|
1151
|
+
startTimeUnixNano: 'start_time_unix_nano',
|
|
1152
|
+
endTimeUnixNano: 'end_time_unix_nano',
|
|
1154
1153
|
};
|
|
1154
|
+
const sortField = sortFieldMap[sortInput.field];
|
|
1155
|
+
const sortOrder = sortInput.order === 'asc' ? 'ASC' : 'DESC';
|
|
1156
|
+
// For step queries, use a recursive CTE to get descendant spans
|
|
1157
|
+
if (options.stepId) {
|
|
1158
|
+
return this._getStepSpansRecursive(options.stepId, sortField, sortOrder, filters);
|
|
1159
|
+
}
|
|
1160
|
+
// Build WHERE clause for job queries
|
|
1161
|
+
const where = this._buildSpansWhereClause(options.jobId, undefined, filters);
|
|
1155
1162
|
// Get total count
|
|
1156
1163
|
const total = await this.db.$count(spansTable, where);
|
|
1157
1164
|
if (!total) {
|
|
@@ -1160,8 +1167,10 @@ export class PostgresBaseAdapter extends Adapter {
|
|
|
1160
1167
|
total: 0,
|
|
1161
1168
|
};
|
|
1162
1169
|
}
|
|
1163
|
-
const
|
|
1164
|
-
const orderByClause = sortInput.order === 'asc'
|
|
1170
|
+
const sortFieldColumn = sortFieldMap[sortInput.field];
|
|
1171
|
+
const orderByClause = sortInput.order === 'asc'
|
|
1172
|
+
? asc(spansTable[sortFieldColumn])
|
|
1173
|
+
: desc(spansTable[sortFieldColumn]);
|
|
1165
1174
|
const rows = await this.db
|
|
1166
1175
|
.select({
|
|
1167
1176
|
id: spansTable.id,
|
|
@@ -1196,6 +1205,61 @@ export class PostgresBaseAdapter extends Adapter {
|
|
|
1196
1205
|
total,
|
|
1197
1206
|
};
|
|
1198
1207
|
}
|
|
1208
|
+
/**
|
|
1209
|
+
* Get spans for a step using a recursive CTE to traverse the span hierarchy.
|
|
1210
|
+
* This returns the step's span and all its descendant spans (children, grandchildren, etc.)
|
|
1211
|
+
*/
|
|
1212
|
+
async _getStepSpansRecursive(stepId, sortField, sortOrder, _filters) {
|
|
1213
|
+
const schemaName = this.schema;
|
|
1214
|
+
// Use a recursive CTE to find all descendant spans
|
|
1215
|
+
// 1. Base case: find the span with step_id = stepId
|
|
1216
|
+
// 2. Recursive case: find all spans where parent_span_id = span_id of a span we've already found
|
|
1217
|
+
const query = sql `
|
|
1218
|
+
WITH RECURSIVE span_tree AS (
|
|
1219
|
+
-- Base case: the span(s) for the step
|
|
1220
|
+
SELECT * FROM ${sql.identifier(schemaName)}.spans WHERE step_id = ${stepId}::uuid
|
|
1221
|
+
UNION ALL
|
|
1222
|
+
-- Recursive case: children of spans we've found
|
|
1223
|
+
SELECT s.* FROM ${sql.identifier(schemaName)}.spans s
|
|
1224
|
+
INNER JOIN span_tree st ON s.parent_span_id = st.span_id
|
|
1225
|
+
)
|
|
1226
|
+
SELECT
|
|
1227
|
+
id,
|
|
1228
|
+
trace_id as "traceId",
|
|
1229
|
+
span_id as "spanId",
|
|
1230
|
+
parent_span_id as "parentSpanId",
|
|
1231
|
+
job_id as "jobId",
|
|
1232
|
+
step_id as "stepId",
|
|
1233
|
+
name,
|
|
1234
|
+
kind,
|
|
1235
|
+
start_time_unix_nano as "startTimeUnixNano",
|
|
1236
|
+
end_time_unix_nano as "endTimeUnixNano",
|
|
1237
|
+
status_code as "statusCode",
|
|
1238
|
+
status_message as "statusMessage",
|
|
1239
|
+
attributes,
|
|
1240
|
+
events
|
|
1241
|
+
FROM span_tree
|
|
1242
|
+
ORDER BY ${sql.identifier(sortField)} ${sql.raw(sortOrder)}
|
|
1243
|
+
`;
|
|
1244
|
+
// Raw SQL returns numeric types as strings, so we type them as such
|
|
1245
|
+
const rows = (await this.db.execute(query));
|
|
1246
|
+
// Convert types: raw SQL returns numeric types as strings
|
|
1247
|
+
const spans = rows.map((row) => ({
|
|
1248
|
+
...row,
|
|
1249
|
+
// Convert id to number (bigserial comes as string from raw SQL)
|
|
1250
|
+
id: typeof row.id === 'string' ? Number.parseInt(row.id, 10) : row.id,
|
|
1251
|
+
// Convert kind and statusCode to proper types
|
|
1252
|
+
kind: (typeof row.kind === 'string' ? Number.parseInt(row.kind, 10) : row.kind),
|
|
1253
|
+
statusCode: (typeof row.statusCode === 'string' ? Number.parseInt(row.statusCode, 10) : row.statusCode),
|
|
1254
|
+
// Convert BigInt to string for JSON serialization
|
|
1255
|
+
startTimeUnixNano: row.startTimeUnixNano?.toString() ?? null,
|
|
1256
|
+
endTimeUnixNano: row.endTimeUnixNano?.toString() ?? null,
|
|
1257
|
+
}));
|
|
1258
|
+
return {
|
|
1259
|
+
spans,
|
|
1260
|
+
total: spans.length,
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1199
1263
|
/**
|
|
1200
1264
|
* Internal method to delete all spans for a job.
|
|
1201
1265
|
*/
|
|
@@ -1207,12 +1271,15 @@ export class PostgresBaseAdapter extends Adapter {
|
|
|
1207
1271
|
return result.length;
|
|
1208
1272
|
}
|
|
1209
1273
|
/**
|
|
1210
|
-
* Build WHERE clause for spans queries.
|
|
1211
|
-
* When querying by jobId
|
|
1212
|
-
* as spans with that job
|
|
1274
|
+
* Build WHERE clause for spans queries (used for job queries only).
|
|
1275
|
+
* When querying by jobId, we find all spans that share the same trace_id
|
|
1276
|
+
* as spans with that job. This includes spans from external libraries that
|
|
1213
1277
|
* don't have the duron.job.id attribute but are part of the same trace.
|
|
1278
|
+
*
|
|
1279
|
+
* Note: Step queries are handled separately by _getStepSpansRecursive using
|
|
1280
|
+
* a recursive CTE to traverse the span hierarchy.
|
|
1214
1281
|
*/
|
|
1215
|
-
_buildSpansWhereClause(jobId,
|
|
1282
|
+
_buildSpansWhereClause(jobId, _stepId, filters) {
|
|
1216
1283
|
const spansTable = this.tables.spansTable;
|
|
1217
1284
|
// Build condition for finding spans by trace_id (includes external spans)
|
|
1218
1285
|
let traceCondition;
|
|
@@ -1221,10 +1288,6 @@ export class PostgresBaseAdapter extends Adapter {
|
|
|
1221
1288
|
// This includes external spans (like from AI SDK) that don't have duron.job.id
|
|
1222
1289
|
traceCondition = inArray(spansTable.trace_id, this.db.select({ traceId: spansTable.trace_id }).from(spansTable).where(eq(spansTable.job_id, jobId)));
|
|
1223
1290
|
}
|
|
1224
|
-
else if (stepId) {
|
|
1225
|
-
// Find all spans that share a trace_id with any span that has this step_id
|
|
1226
|
-
traceCondition = inArray(spansTable.trace_id, this.db.select({ traceId: spansTable.trace_id }).from(spansTable).where(eq(spansTable.step_id, stepId)));
|
|
1227
|
-
}
|
|
1228
1291
|
return and(traceCondition, filters?.name
|
|
1229
1292
|
? Array.isArray(filters.name)
|
|
1230
1293
|
? or(...filters.name.map((n) => ilike(spansTable.name, `%${n}%`)))
|
package/package.json
CHANGED
|
@@ -1418,22 +1418,30 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1418
1418
|
|
|
1419
1419
|
/**
|
|
1420
1420
|
* Internal method to get spans for a job or step.
|
|
1421
|
+
* For step queries, uses a recursive CTE to find all descendant spans.
|
|
1421
1422
|
*/
|
|
1422
1423
|
protected async _getSpans(options: GetSpansOptions): Promise<GetSpansResult> {
|
|
1423
1424
|
const spansTable = this.tables.spansTable
|
|
1424
1425
|
const filters = options.filters ?? {}
|
|
1425
1426
|
|
|
1426
|
-
// Build WHERE clause
|
|
1427
|
-
const where = this._buildSpansWhereClause(options.jobId, options.stepId, filters)
|
|
1428
|
-
|
|
1429
1427
|
// Build sort
|
|
1430
1428
|
const sortInput = options.sort ?? { field: 'startTimeUnixNano', order: 'asc' }
|
|
1431
|
-
const sortFieldMap: Record<SpanSort['field'],
|
|
1432
|
-
name:
|
|
1433
|
-
startTimeUnixNano:
|
|
1434
|
-
endTimeUnixNano:
|
|
1429
|
+
const sortFieldMap: Record<SpanSort['field'], string> = {
|
|
1430
|
+
name: 'name',
|
|
1431
|
+
startTimeUnixNano: 'start_time_unix_nano',
|
|
1432
|
+
endTimeUnixNano: 'end_time_unix_nano',
|
|
1433
|
+
}
|
|
1434
|
+
const sortField = sortFieldMap[sortInput.field]
|
|
1435
|
+
const sortOrder = sortInput.order === 'asc' ? 'ASC' : 'DESC'
|
|
1436
|
+
|
|
1437
|
+
// For step queries, use a recursive CTE to get descendant spans
|
|
1438
|
+
if (options.stepId) {
|
|
1439
|
+
return this._getStepSpansRecursive(options.stepId, sortField, sortOrder, filters)
|
|
1435
1440
|
}
|
|
1436
1441
|
|
|
1442
|
+
// Build WHERE clause for job queries
|
|
1443
|
+
const where = this._buildSpansWhereClause(options.jobId, undefined, filters)
|
|
1444
|
+
|
|
1437
1445
|
// Get total count
|
|
1438
1446
|
const total = await this.db.$count(spansTable, where)
|
|
1439
1447
|
if (!total) {
|
|
@@ -1443,8 +1451,11 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1443
1451
|
}
|
|
1444
1452
|
}
|
|
1445
1453
|
|
|
1446
|
-
const
|
|
1447
|
-
const orderByClause =
|
|
1454
|
+
const sortFieldColumn = sortFieldMap[sortInput.field]
|
|
1455
|
+
const orderByClause =
|
|
1456
|
+
sortInput.order === 'asc'
|
|
1457
|
+
? asc(spansTable[sortFieldColumn as keyof typeof spansTable] as any)
|
|
1458
|
+
: desc(spansTable[sortFieldColumn as keyof typeof spansTable] as any)
|
|
1448
1459
|
|
|
1449
1460
|
const rows = await this.db
|
|
1450
1461
|
.select({
|
|
@@ -1483,6 +1494,89 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1483
1494
|
}
|
|
1484
1495
|
}
|
|
1485
1496
|
|
|
1497
|
+
/**
|
|
1498
|
+
* Get spans for a step using a recursive CTE to traverse the span hierarchy.
|
|
1499
|
+
* This returns the step's span and all its descendant spans (children, grandchildren, etc.)
|
|
1500
|
+
*/
|
|
1501
|
+
protected async _getStepSpansRecursive(
|
|
1502
|
+
stepId: string,
|
|
1503
|
+
sortField: string,
|
|
1504
|
+
sortOrder: string,
|
|
1505
|
+
_filters?: GetSpansOptions['filters'],
|
|
1506
|
+
): Promise<GetSpansResult> {
|
|
1507
|
+
const schemaName = this.schema
|
|
1508
|
+
|
|
1509
|
+
// Use a recursive CTE to find all descendant spans
|
|
1510
|
+
// 1. Base case: find the span with step_id = stepId
|
|
1511
|
+
// 2. Recursive case: find all spans where parent_span_id = span_id of a span we've already found
|
|
1512
|
+
const query = sql`
|
|
1513
|
+
WITH RECURSIVE span_tree AS (
|
|
1514
|
+
-- Base case: the span(s) for the step
|
|
1515
|
+
SELECT * FROM ${sql.identifier(schemaName)}.spans WHERE step_id = ${stepId}::uuid
|
|
1516
|
+
UNION ALL
|
|
1517
|
+
-- Recursive case: children of spans we've found
|
|
1518
|
+
SELECT s.* FROM ${sql.identifier(schemaName)}.spans s
|
|
1519
|
+
INNER JOIN span_tree st ON s.parent_span_id = st.span_id
|
|
1520
|
+
)
|
|
1521
|
+
SELECT
|
|
1522
|
+
id,
|
|
1523
|
+
trace_id as "traceId",
|
|
1524
|
+
span_id as "spanId",
|
|
1525
|
+
parent_span_id as "parentSpanId",
|
|
1526
|
+
job_id as "jobId",
|
|
1527
|
+
step_id as "stepId",
|
|
1528
|
+
name,
|
|
1529
|
+
kind,
|
|
1530
|
+
start_time_unix_nano as "startTimeUnixNano",
|
|
1531
|
+
end_time_unix_nano as "endTimeUnixNano",
|
|
1532
|
+
status_code as "statusCode",
|
|
1533
|
+
status_message as "statusMessage",
|
|
1534
|
+
attributes,
|
|
1535
|
+
events
|
|
1536
|
+
FROM span_tree
|
|
1537
|
+
ORDER BY ${sql.identifier(sortField)} ${sql.raw(sortOrder)}
|
|
1538
|
+
`
|
|
1539
|
+
|
|
1540
|
+
// Raw SQL returns numeric types as strings, so we type them as such
|
|
1541
|
+
const rows = (await this.db.execute(query)) as unknown as Array<{
|
|
1542
|
+
id: string | number
|
|
1543
|
+
traceId: string
|
|
1544
|
+
spanId: string
|
|
1545
|
+
parentSpanId: string | null
|
|
1546
|
+
jobId: string | null
|
|
1547
|
+
stepId: string | null
|
|
1548
|
+
name: string
|
|
1549
|
+
kind: string | number
|
|
1550
|
+
startTimeUnixNano: string | bigint | null
|
|
1551
|
+
endTimeUnixNano: string | bigint | null
|
|
1552
|
+
statusCode: string | number
|
|
1553
|
+
statusMessage: string | null
|
|
1554
|
+
attributes: Record<string, any>
|
|
1555
|
+
events: Array<{ name: string; timeUnixNano: string; attributes?: Record<string, any> }>
|
|
1556
|
+
}>
|
|
1557
|
+
|
|
1558
|
+
// Convert types: raw SQL returns numeric types as strings
|
|
1559
|
+
const spans = rows.map((row) => ({
|
|
1560
|
+
...row,
|
|
1561
|
+
// Convert id to number (bigserial comes as string from raw SQL)
|
|
1562
|
+
id: typeof row.id === 'string' ? Number.parseInt(row.id, 10) : row.id,
|
|
1563
|
+
// Convert kind and statusCode to proper types
|
|
1564
|
+
kind: (typeof row.kind === 'string' ? Number.parseInt(row.kind, 10) : row.kind) as 0 | 1 | 2 | 3 | 4,
|
|
1565
|
+
statusCode: (typeof row.statusCode === 'string' ? Number.parseInt(row.statusCode, 10) : row.statusCode) as
|
|
1566
|
+
| 0
|
|
1567
|
+
| 1
|
|
1568
|
+
| 2,
|
|
1569
|
+
// Convert BigInt to string for JSON serialization
|
|
1570
|
+
startTimeUnixNano: row.startTimeUnixNano?.toString() ?? null,
|
|
1571
|
+
endTimeUnixNano: row.endTimeUnixNano?.toString() ?? null,
|
|
1572
|
+
}))
|
|
1573
|
+
|
|
1574
|
+
return {
|
|
1575
|
+
spans,
|
|
1576
|
+
total: spans.length,
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1486
1580
|
/**
|
|
1487
1581
|
* Internal method to delete all spans for a job.
|
|
1488
1582
|
*/
|
|
@@ -1496,12 +1590,15 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1496
1590
|
}
|
|
1497
1591
|
|
|
1498
1592
|
/**
|
|
1499
|
-
* Build WHERE clause for spans queries.
|
|
1500
|
-
* When querying by jobId
|
|
1501
|
-
* as spans with that job
|
|
1593
|
+
* Build WHERE clause for spans queries (used for job queries only).
|
|
1594
|
+
* When querying by jobId, we find all spans that share the same trace_id
|
|
1595
|
+
* as spans with that job. This includes spans from external libraries that
|
|
1502
1596
|
* don't have the duron.job.id attribute but are part of the same trace.
|
|
1597
|
+
*
|
|
1598
|
+
* Note: Step queries are handled separately by _getStepSpansRecursive using
|
|
1599
|
+
* a recursive CTE to traverse the span hierarchy.
|
|
1503
1600
|
*/
|
|
1504
|
-
protected _buildSpansWhereClause(jobId?: string,
|
|
1601
|
+
protected _buildSpansWhereClause(jobId?: string, _stepId?: string, filters?: GetSpansOptions['filters']) {
|
|
1505
1602
|
const spansTable = this.tables.spansTable
|
|
1506
1603
|
|
|
1507
1604
|
// Build condition for finding spans by trace_id (includes external spans)
|
|
@@ -1514,12 +1611,6 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1514
1611
|
spansTable.trace_id,
|
|
1515
1612
|
this.db.select({ traceId: spansTable.trace_id }).from(spansTable).where(eq(spansTable.job_id, jobId)),
|
|
1516
1613
|
)
|
|
1517
|
-
} else if (stepId) {
|
|
1518
|
-
// Find all spans that share a trace_id with any span that has this step_id
|
|
1519
|
-
traceCondition = inArray(
|
|
1520
|
-
spansTable.trace_id,
|
|
1521
|
-
this.db.select({ traceId: spansTable.trace_id }).from(spansTable).where(eq(spansTable.step_id, stepId)),
|
|
1522
|
-
)
|
|
1523
1614
|
}
|
|
1524
1615
|
|
|
1525
1616
|
return and(
|