@mastra/pg 1.25.0 → 1.26.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/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-memory-memory-class.md +2 -0
- package/dist/docs/references/reference-rag-vector-databases.md +39 -0
- package/dist/index.cjs +193 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +193 -3
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +5 -0
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts +4 -2
- package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts +5 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts.map +1 -1
- package/dist/storage/factory-storage.d.ts.map +1 -1
- package/dist/storage/test-utils.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -2460,6 +2460,7 @@ async function loadSchemaSnapshot(client, schemaName) {
|
|
|
2460
2460
|
}
|
|
2461
2461
|
//#endregion
|
|
2462
2462
|
//#region src/storage/db/index.ts
|
|
2463
|
+
const POSTGRES_MAX_BIND_PARAMETERS$1 = 65535;
|
|
2463
2464
|
/**
|
|
2464
2465
|
* Resolves PgDomainConfig to a database client and schema.
|
|
2465
2466
|
* Handles creating a new pool if config is provided.
|
|
@@ -3013,6 +3014,90 @@ var PgDB = class extends MastraBase {
|
|
|
3013
3014
|
ON CONFLICT ("traceId", "spanId") DO NOTHING`, values);
|
|
3014
3015
|
} else await client.none(`INSERT INTO ${fullTableName} (${columnList}) VALUES (${placeholders})`, values);
|
|
3015
3016
|
}
|
|
3017
|
+
getChunkRowLimit(columnCount) {
|
|
3018
|
+
if (columnCount === 0) return 0;
|
|
3019
|
+
return Math.max(1, Math.floor(POSTGRES_MAX_BIND_PARAMETERS$1 / columnCount));
|
|
3020
|
+
}
|
|
3021
|
+
getSpanConflictIdentifier(record) {
|
|
3022
|
+
const traceId = record.traceId;
|
|
3023
|
+
const spanId = record.spanId;
|
|
3024
|
+
if (traceId === void 0 || spanId === void 0) return;
|
|
3025
|
+
return `${String(traceId)}|${String(spanId)}`;
|
|
3026
|
+
}
|
|
3027
|
+
async normalizeForInsert(tableName, record) {
|
|
3028
|
+
this.addTimestampZColumns(record);
|
|
3029
|
+
const filteredRecord = await this.filterRecordToKnownColumns(tableName, record);
|
|
3030
|
+
return {
|
|
3031
|
+
columns: Object.keys(filteredRecord).map((column) => parseSqlIdentifier(column, "column name")),
|
|
3032
|
+
values: this.prepareValuesForInsert(filteredRecord, tableName),
|
|
3033
|
+
conflictKey: tableName === TABLE_SPANS ? this.getSpanConflictIdentifier(filteredRecord) : void 0
|
|
3034
|
+
};
|
|
3035
|
+
}
|
|
3036
|
+
buildMultiRowInsertStatement({ tableName, columns, rows }) {
|
|
3037
|
+
const fullTableName = getTableName$6({
|
|
3038
|
+
indexName: tableName,
|
|
3039
|
+
schemaName: getSchemaName$6(this.schemaName)
|
|
3040
|
+
});
|
|
3041
|
+
const columnList = columns.map((column) => `"${column}"`).join(", ");
|
|
3042
|
+
const bindParams = [];
|
|
3043
|
+
const values = [];
|
|
3044
|
+
let bindIndex = 1;
|
|
3045
|
+
for (const rowValues of rows) {
|
|
3046
|
+
const placeholders = rowValues.map(() => `$${bindIndex++}`);
|
|
3047
|
+
bindParams.push(`(${placeholders.join(", ")})`);
|
|
3048
|
+
values.push(...rowValues);
|
|
3049
|
+
}
|
|
3050
|
+
let query = `INSERT INTO ${fullTableName} (${columnList}) VALUES ${bindParams.join(", ")}`;
|
|
3051
|
+
if (tableName === TABLE_SPANS) {
|
|
3052
|
+
const updateColumns = columns.filter((column) => column !== "traceId" && column !== "spanId");
|
|
3053
|
+
if (updateColumns.length > 0) {
|
|
3054
|
+
const updateClause = updateColumns.map((column) => `"${column}" = EXCLUDED."${column}"`).join(", ");
|
|
3055
|
+
query += ` ON CONFLICT ("traceId", "spanId") DO UPDATE SET ${updateClause}`;
|
|
3056
|
+
} else query += ` ON CONFLICT ("traceId", "spanId") DO NOTHING`;
|
|
3057
|
+
}
|
|
3058
|
+
return {
|
|
3059
|
+
query,
|
|
3060
|
+
values
|
|
3061
|
+
};
|
|
3062
|
+
}
|
|
3063
|
+
async executeBatchInsert(client, { tableName, records }) {
|
|
3064
|
+
const preparedRecords = [];
|
|
3065
|
+
for (const record of records) preparedRecords.push(await this.normalizeForInsert(tableName, record));
|
|
3066
|
+
let pendingColumns;
|
|
3067
|
+
let pendingConflictKeys = /* @__PURE__ */ new Set();
|
|
3068
|
+
let pendingRows = [];
|
|
3069
|
+
let pendingLimit = 0;
|
|
3070
|
+
const flush = async () => {
|
|
3071
|
+
if (!pendingColumns || pendingRows.length === 0) return;
|
|
3072
|
+
const statement = this.buildMultiRowInsertStatement({
|
|
3073
|
+
tableName,
|
|
3074
|
+
columns: pendingColumns,
|
|
3075
|
+
rows: pendingRows
|
|
3076
|
+
});
|
|
3077
|
+
await client.none(statement.query, statement.values);
|
|
3078
|
+
pendingColumns = void 0;
|
|
3079
|
+
pendingRows = [];
|
|
3080
|
+
pendingConflictKeys = /* @__PURE__ */ new Set();
|
|
3081
|
+
pendingLimit = 0;
|
|
3082
|
+
};
|
|
3083
|
+
for (const { columns, values, conflictKey } of preparedRecords) {
|
|
3084
|
+
if (columns.length === 0) continue;
|
|
3085
|
+
const columnsSignature = columns.join("\0");
|
|
3086
|
+
const currentPendingColumns = pendingColumns;
|
|
3087
|
+
const isSpans = tableName === TABLE_SPANS;
|
|
3088
|
+
const conflictDuplicate = isSpans && conflictKey !== void 0 && pendingConflictKeys.has(conflictKey);
|
|
3089
|
+
const exceedsLimit = pendingRows.length >= pendingLimit;
|
|
3090
|
+
if (currentPendingColumns === void 0 || columnsSignature !== currentPendingColumns.join("\0") || conflictDuplicate || exceedsLimit) {
|
|
3091
|
+
await flush();
|
|
3092
|
+
pendingColumns = columns;
|
|
3093
|
+
pendingLimit = this.getChunkRowLimit(columns.length);
|
|
3094
|
+
pendingRows = [values];
|
|
3095
|
+
pendingConflictKeys = /* @__PURE__ */ new Set();
|
|
3096
|
+
} else pendingRows.push(values);
|
|
3097
|
+
if (isSpans && conflictKey !== void 0) pendingConflictKeys.add(conflictKey);
|
|
3098
|
+
}
|
|
3099
|
+
await flush();
|
|
3100
|
+
}
|
|
3016
3101
|
async insert({ tableName, record }) {
|
|
3017
3102
|
try {
|
|
3018
3103
|
await this.executeInsert(this.client, {
|
|
@@ -3461,9 +3546,9 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
3461
3546
|
async batchInsert({ tableName, records }) {
|
|
3462
3547
|
try {
|
|
3463
3548
|
await this.client.tx(async (tx) => {
|
|
3464
|
-
|
|
3549
|
+
await this.executeBatchInsert(tx, {
|
|
3465
3550
|
tableName,
|
|
3466
|
-
|
|
3551
|
+
records
|
|
3467
3552
|
});
|
|
3468
3553
|
});
|
|
3469
3554
|
} catch (error) {
|
|
@@ -17607,6 +17692,75 @@ LIMIT $${values.length}`,
|
|
|
17607
17692
|
values
|
|
17608
17693
|
};
|
|
17609
17694
|
}
|
|
17695
|
+
function discoveryRegistry(scope) {
|
|
17696
|
+
if (scope === "trace") return TRACE_FIELDS;
|
|
17697
|
+
if (scope === "spans") return SPAN_FIELDS;
|
|
17698
|
+
if (scope === "scores") return SCORE_FIELDS;
|
|
17699
|
+
return FEEDBACK_FIELDS;
|
|
17700
|
+
}
|
|
17701
|
+
function discoverySource(scope) {
|
|
17702
|
+
if (scope === "trace") return "root_scope r";
|
|
17703
|
+
if (scope === "spans") return "current_spans s";
|
|
17704
|
+
if (scope === "scores") return "current_scores s";
|
|
17705
|
+
return "current_feedback s";
|
|
17706
|
+
}
|
|
17707
|
+
function discoveryCollections(scope) {
|
|
17708
|
+
return scope === "trace" ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([scope]);
|
|
17709
|
+
}
|
|
17710
|
+
function compilePostgresTraceQueryObservedFields(schema, plan) {
|
|
17711
|
+
const { ctes, values } = compilePostgresTraceScope(schema, plan, /* @__PURE__ */ new Set());
|
|
17712
|
+
const searchParameter = values.length + 1;
|
|
17713
|
+
const search = plan.search ? `AND strpos(lower('metadata.' || entry.key), lower($${searchParameter})) > 0` : "";
|
|
17714
|
+
if (plan.search) values.push(plan.search);
|
|
17715
|
+
values.push(plan.limit + 1);
|
|
17716
|
+
return {
|
|
17717
|
+
text: `WITH ${ctes.join(",\n")}
|
|
17718
|
+
SELECT 'metadata.' || entry.key AS path, count(*)::bigint AS occurrences
|
|
17719
|
+
FROM root_scope r
|
|
17720
|
+
CROSS JOIN LATERAL jsonb_each(CASE WHEN jsonb_typeof(r."metadataRaw") = 'object' THEN r."metadataRaw" ELSE '{}'::jsonb END) entry
|
|
17721
|
+
WHERE jsonb_typeof(entry.value) = 'string'
|
|
17722
|
+
AND btrim(entry.value #>> '{}') <> ''
|
|
17723
|
+
AND entry.key <> ''
|
|
17724
|
+
AND strpos(entry.key, '.') = 0
|
|
17725
|
+
AND octet_length('metadata.' || entry.key) <= ${coreStorage.TRACE_QUERY_MAX_PATH_BYTES}
|
|
17726
|
+
AND octet_length(entry.value #>> '{}') <= ${coreStorage.TRACE_QUERY_MAX_STRING_BYTES}
|
|
17727
|
+
${search}
|
|
17728
|
+
GROUP BY entry.key
|
|
17729
|
+
ORDER BY occurrences DESC, ('metadata.' || entry.key) COLLATE "C" ASC
|
|
17730
|
+
LIMIT $${values.length}`,
|
|
17731
|
+
values
|
|
17732
|
+
};
|
|
17733
|
+
}
|
|
17734
|
+
function compilePostgresTraceQueryValues(schema, plan) {
|
|
17735
|
+
const { ctes, values } = compilePostgresTraceScope(schema, plan, discoveryCollections(plan.predicateScope));
|
|
17736
|
+
let field;
|
|
17737
|
+
if (plan.predicateScope === "trace" && plan.path.startsWith("metadata.")) {
|
|
17738
|
+
const keyParameter = `$${values.length + 1}`;
|
|
17739
|
+
field = `COALESCE(
|
|
17740
|
+
CASE WHEN jsonb_typeof(r."metadataSearch" -> ${keyParameter}) = 'string' THEN r."metadataSearch" ->> ${keyParameter} END,
|
|
17741
|
+
CASE WHEN jsonb_typeof(r."metadataRaw" -> ${keyParameter}) = 'string' THEN NULLIF(btrim(r."metadataRaw" ->> ${keyParameter}), '') END
|
|
17742
|
+
)`;
|
|
17743
|
+
values.push(plan.path.slice(9));
|
|
17744
|
+
} else field = fieldSql(discoveryRegistry(plan.predicateScope), plan.path);
|
|
17745
|
+
const searchParameter = values.length + 1;
|
|
17746
|
+
const search = plan.search ? `AND strpos(lower(value), lower($${searchParameter})) > 0` : "";
|
|
17747
|
+
if (plan.search) values.push(plan.search);
|
|
17748
|
+
values.push(plan.limit + 1);
|
|
17749
|
+
return {
|
|
17750
|
+
text: `WITH ${ctes.join(",\n")}, extracted AS (
|
|
17751
|
+
SELECT ${field}::text AS value FROM ${discoverySource(plan.predicateScope)}
|
|
17752
|
+
)
|
|
17753
|
+
SELECT value, count(*)::bigint AS count
|
|
17754
|
+
FROM extracted
|
|
17755
|
+
WHERE value IS NOT NULL
|
|
17756
|
+
AND octet_length(value) <= ${coreStorage.TRACE_QUERY_MAX_STRING_BYTES}
|
|
17757
|
+
${search}
|
|
17758
|
+
GROUP BY value
|
|
17759
|
+
ORDER BY count DESC, value COLLATE "C" ASC
|
|
17760
|
+
LIMIT $${values.length}`,
|
|
17761
|
+
values
|
|
17762
|
+
};
|
|
17763
|
+
}
|
|
17610
17764
|
function asIsoTimestamp$1(value) {
|
|
17611
17765
|
if (value === null || value === void 0) throw new Error("Trace query returned a null timestamp");
|
|
17612
17766
|
return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
|
|
@@ -17628,6 +17782,29 @@ async function runWithPostgresTraceQueryTimeout(client, timeoutMs, execute) {
|
|
|
17628
17782
|
throw error;
|
|
17629
17783
|
}
|
|
17630
17784
|
}
|
|
17785
|
+
async function getTraceQueryObservedFields(client, schema, plan, timeoutMs) {
|
|
17786
|
+
if (plan.predicateScope !== "trace") return {
|
|
17787
|
+
observedFields: [],
|
|
17788
|
+
observedFieldsTruncated: false
|
|
17789
|
+
};
|
|
17790
|
+
const query = compilePostgresTraceQueryObservedFields(schema, plan);
|
|
17791
|
+
const rows = await runWithPostgresTraceQueryTimeout(client, timeoutMs, (transaction) => transaction.any(query.text, query.values));
|
|
17792
|
+
return {
|
|
17793
|
+
observedFields: rows.slice(0, plan.limit).map((row) => coreStorage.createTraceQueryObservedFieldDescriptor(String(row.path), Number(row.occurrences))),
|
|
17794
|
+
observedFieldsTruncated: rows.length > plan.limit
|
|
17795
|
+
};
|
|
17796
|
+
}
|
|
17797
|
+
async function getTraceQueryValues(client, schema, plan, timeoutMs) {
|
|
17798
|
+
const query = compilePostgresTraceQueryValues(schema, plan);
|
|
17799
|
+
const rows = await runWithPostgresTraceQueryTimeout(client, timeoutMs, (transaction) => transaction.any(query.text, query.values));
|
|
17800
|
+
return coreStorage.getTraceQueryValuesResponseSchema.parse({
|
|
17801
|
+
values: rows.slice(0, plan.limit).map((row) => ({
|
|
17802
|
+
value: String(row.value),
|
|
17803
|
+
count: Number(row.count)
|
|
17804
|
+
})),
|
|
17805
|
+
valuesTruncated: rows.length > plan.limit
|
|
17806
|
+
});
|
|
17807
|
+
}
|
|
17631
17808
|
async function queryTraces(client, schema, plan, timeoutMs) {
|
|
17632
17809
|
const query = compilePostgresTraceQuery(schema, plan);
|
|
17633
17810
|
const rows = await runWithPostgresTraceQueryTimeout(client, timeoutMs, (transaction) => transaction.any(query.text, query.values));
|
|
@@ -18574,6 +18751,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
18574
18751
|
"metrics",
|
|
18575
18752
|
"logs",
|
|
18576
18753
|
"trace-query",
|
|
18754
|
+
"trace-query-discovery",
|
|
18577
18755
|
"thread-query"
|
|
18578
18756
|
];
|
|
18579
18757
|
return [
|
|
@@ -18581,6 +18759,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
18581
18759
|
"logs",
|
|
18582
18760
|
"delta-polling",
|
|
18583
18761
|
"trace-query",
|
|
18762
|
+
"trace-query-discovery",
|
|
18584
18763
|
"thread-query"
|
|
18585
18764
|
];
|
|
18586
18765
|
}
|
|
@@ -18627,6 +18806,12 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
18627
18806
|
async queryTraces(plan) {
|
|
18628
18807
|
return this.#run("QUERY_TRACES", () => queryTraces(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
18629
18808
|
}
|
|
18809
|
+
async getTraceQueryObservedFields(plan) {
|
|
18810
|
+
return this.#run("GET_TRACE_QUERY_OBSERVED_FIELDS", () => getTraceQueryObservedFields(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
18811
|
+
}
|
|
18812
|
+
async getTraceQueryValues(plan) {
|
|
18813
|
+
return this.#run("GET_TRACE_QUERY_VALUES", () => getTraceQueryValues(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
18814
|
+
}
|
|
18630
18815
|
async queryThreads(plan) {
|
|
18631
18816
|
return this.#run("QUERY_THREADS", () => queryThreads(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
18632
18817
|
}
|
|
@@ -23406,7 +23591,12 @@ var PgFactoryStorageOps = class {
|
|
|
23406
23591
|
const assignments = columns.map((column, i) => `"${column}" = $${i + 1}`).join(", ");
|
|
23407
23592
|
const filter = this.#buildWhere(schema, where, columns.length + 1);
|
|
23408
23593
|
const args = [...columns.map((column) => this.#serialize(this.#column(schema, column), set[column])), ...filter.args];
|
|
23409
|
-
|
|
23594
|
+
try {
|
|
23595
|
+
return (await queryable.query(`UPDATE "${schema.name}" SET ${assignments} WHERE ${filter.sql}`, args)).rowCount ?? 0;
|
|
23596
|
+
} catch (error) {
|
|
23597
|
+
if (isUniqueViolation(error)) throw new UniqueViolationError(collection, { cause: error });
|
|
23598
|
+
throw error;
|
|
23599
|
+
}
|
|
23410
23600
|
}
|
|
23411
23601
|
async deleteMany(collection, where) {
|
|
23412
23602
|
const schema = this.#schema(collection);
|