Skip to content

Commit 29a9f5f

Browse files
committed
feat: Enhance pagination and query support across database adapters
- Refactored pagination methods in multiple database adapters to support advanced querying - Added support for complex where conditions (ne, eq, gt, gte, lt, lte) - Improved order clause generation with flexible sorting - Updated account creation to include new fields: pid and source - Standardized pagination result structure across adapters - Enhanced query parameter handling in client-direct manage API
1 parent ffb3980 commit 29a9f5f

File tree

14 files changed

+418
-233
lines changed

14 files changed

+418
-233
lines changed

packages/adapter-mongodb/src/index.ts

+56-23
Original file line numberDiff line numberDiff line change
@@ -1454,54 +1454,87 @@ export class MongoDBDatabaseAdapter
14541454
page = 1,
14551455
pageSize = 10,
14561456
where = {},
1457-
order = { createdAt: -1 } // MongoDB uses 1 for ASC, -1 for DESC
1457+
order = { createdAt: 'DESC' }
14581458
} = params;
14591459

14601460
const skip = (page - 1) * pageSize;
1461-
1462-
// Convert where conditions for MongoDB
1463-
const whereQuery: any = {};
1464-
// biome-ignore lint/complexity/noForEach: <explanation>
1465-
Object.entries(where).forEach(([key, value]) => {
1466-
if (value === null || value === undefined) return;
1467-
1468-
if (typeof value === 'object') {
1469-
if (key === 'createdAt') {
1470-
whereQuery[key] = {};
1471-
if (value.gte) whereQuery[key].$gte = new Date(value.gte);
1472-
if (value.lte) whereQuery[key].$lte = new Date(value.lte);
1473-
} else {
1474-
whereQuery[key] = value;
1475-
}
1476-
} else {
1477-
whereQuery[key] = value;
1478-
}
1479-
});
1480-
1461+
14811462
try {
1463+
// Build MongoDB query conditions
1464+
const whereQuery = this.buildWhereQuery(where);
1465+
1466+
// Build sort options
1467+
const sortOptions = this.buildSortOptions(order);
1468+
14821469
// Get total count
14831470
const total = await this.database.collection(collectionName)
14841471
.countDocuments(whereQuery);
14851472

14861473
// Get paginated data
14871474
const list = await this.database.collection(collectionName)
14881475
.find(whereQuery)
1489-
.sort(order)
1476+
.sort(sortOptions)
14901477
.skip(skip)
14911478
.limit(pageSize)
14921479
.toArray();
14931480

14941481
return {
1495-
list,
14961482
total,
14971483
page,
14981484
pageSize,
14991485
totalPages: Math.ceil(total / pageSize),
1486+
list,
15001487
};
15011488
} catch (error) {
15021489
elizaLogger.error(`Error in paginate for collection ${collectionName}:`, error);
15031490
throw error;
15041491
}
15051492
}
1493+
1494+
private buildWhereQuery(where: Record<string, any>): Record<string, any> {
1495+
const query: Record<string, any> = {};
1496+
1497+
// biome-ignore lint/complexity/noForEach: <explanation>
1498+
Object.entries(where).forEach(([key, value]) => {
1499+
if (value === undefined) return;
1500+
1501+
if (typeof value === 'object') {
1502+
query[key] = {};
1503+
1504+
// Handle comparison operators
1505+
if ('ne' in value) query[key].$ne = value.ne;
1506+
if ('eq' in value) query[key].$eq = value.eq;
1507+
if ('gt' in value) query[key].$gt = value.gt;
1508+
if ('gte' in value) query[key].$gte = value.gte;
1509+
if ('lt' in value) query[key].$lt = value.lt;
1510+
if ('lte' in value) query[key].$lte = value.lte;
1511+
1512+
// Handle date fields
1513+
if (key === 'createdAt') {
1514+
if (query[key].$gte) query[key].$gte = new Date(query[key].$gte);
1515+
if (query[key].$lte) query[key].$lte = new Date(query[key].$lte);
1516+
}
1517+
1518+
// Remove empty query object
1519+
if (Object.keys(query[key]).length === 0) {
1520+
delete query[key];
1521+
}
1522+
} else {
1523+
query[key] = value;
1524+
}
1525+
});
1526+
1527+
return query;
1528+
}
1529+
1530+
private buildSortOptions(order: Record<string, string>): Record<string, 1 | -1> {
1531+
const sortOptions: Record<string, 1 | -1> = {};
1532+
1533+
// biome-ignore lint/complexity/noForEach: <explanation>
1534+
Object.entries(order).forEach(([key, direction]) => {
1535+
sortOptions[key] = direction.toUpperCase() === 'DESC' ? -1 : 1;
1536+
});
1537+
return sortOptions;
1538+
}
15061539
}
15071540

packages/adapter-pglite/src/index.ts

+86-52
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ export class PGLiteDatabaseAdapter
243243
try {
244244
const accountId = account.id ?? v4();
245245
await this.query(
246-
`INSERT INTO accounts (id, name, username, email, "avatarUrl", details, status)
247-
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
246+
`INSERT INTO accounts (id, name, username, email, "avatarUrl", details, status, pid, source)
247+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
248248
[
249249
accountId,
250250
account.name,
@@ -253,6 +253,8 @@ export class PGLiteDatabaseAdapter
253253
account.avatarUrl || "",
254254
JSON.stringify(account.details),
255255
account.status || "paused",
256+
account.pid || "",
257+
account.source || "",
256258
]
257259
);
258260
elizaLogger.debug("Account created successfully:", {
@@ -1599,42 +1601,11 @@ export class PGLiteDatabaseAdapter
15991601
} = params;
16001602

16011603
const offset = (page - 1) * pageSize;
1602-
const whereClause: string[] = [];
1603-
const values: any[] = [];
1604-
let paramCount = 0;
1605-
1606-
// Build where clause with proper parameter indexing
1607-
// biome-ignore lint/complexity/noForEach: <explanation>
1608-
Object.entries(where).forEach(([key, value]) => {
1609-
if (value === null || value === undefined) return;
1610-
1611-
if (typeof value === 'object') {
1612-
if (key === 'createdAt') {
1613-
if (value.gte) {
1614-
paramCount++;
1615-
whereClause.push(`"${key}" >= $${paramCount}`);
1616-
values.push(value.gte);
1617-
}
1618-
if (value.lte) {
1619-
paramCount++;
1620-
whereClause.push(`"${key}" <= $${paramCount}`);
1621-
values.push(value.lte);
1622-
}
1623-
}
1624-
} else {
1625-
paramCount++;
1626-
whereClause.push(`"${key}" = $${paramCount}`);
1627-
values.push(value);
1628-
}
1629-
});
1630-
1631-
const whereStr = whereClause.length > 0
1632-
? `WHERE ${whereClause.join(' AND ')}`
1604+
const { whereClause, whereParams } = this.buildWhereClause(where);
1605+
const whereStr = whereClause.length > 0
1606+
? `WHERE ${whereClause.join(' AND ')}`
16331607
: '';
1634-
1635-
const orderClause = Object.entries(order)
1636-
.map(([key, direction]) => `"${key}" ${direction}`)
1637-
.join(', ');
1608+
const orderClause = this.buildOrderClause(order);
16381609

16391610
// Count total records
16401611
const countQuery = `
@@ -1643,40 +1614,103 @@ export class PGLiteDatabaseAdapter
16431614
${whereStr}
16441615
`;
16451616

1646-
const { rows: countRows } = await this.query<{ total: number }>(
1647-
countQuery,
1648-
values
1649-
);
1650-
const total = Number(countRows[0]?.total || 0);
1651-
16521617
// Get paginated data
1653-
paramCount++;
1654-
const limitParam = `$${paramCount}`;
1655-
paramCount++;
1656-
const offsetParam = `$${paramCount}`;
1657-
16581618
const dataQuery = `
16591619
SELECT *
16601620
FROM "${table}"
16611621
${whereStr}
1662-
ORDER BY ${orderClause}
1663-
LIMIT ${limitParam} OFFSET ${offsetParam}
1622+
${orderClause}
1623+
LIMIT $${whereParams.length + 1}
1624+
OFFSET $${whereParams.length + 2}
16641625
`;
16651626

1627+
elizaLogger.debug("Pagination query:", {
1628+
countQuery,
1629+
dataQuery,
1630+
params: [...whereParams, pageSize, offset]
1631+
});
1632+
1633+
const { rows: countRows } = await this.query<{ total: number }>(
1634+
countQuery,
1635+
whereParams
1636+
);
1637+
const total = Number(countRows[0]?.total || 0);
1638+
16661639
const { rows: list } = await this.query(
16671640
dataQuery,
1668-
[...values, pageSize, offset]
1641+
[...whereParams, pageSize, offset]
16691642
);
16701643

16711644
return {
1672-
list,
16731645
total,
16741646
page,
16751647
pageSize,
16761648
totalPages: Math.ceil(total / pageSize),
1649+
list,
16771650
};
16781651
}, "paginate");
16791652
}
1653+
1654+
private buildWhereClause(where: Record<string, any>): { whereClause: string[], whereParams: any[] } {
1655+
const whereClause: string[] = [];
1656+
const whereParams: any[] = [];
1657+
let paramCount = 0;
1658+
1659+
// Handle where conditions
1660+
// biome-ignore lint/complexity/noForEach: <explanation>
1661+
Object.entries(where).forEach(([key, value]) => {
1662+
if (value === undefined) return;
1663+
1664+
if (typeof value === 'object') {
1665+
if (key === 'createdAt') {
1666+
if (value.gte) {
1667+
paramCount++;
1668+
whereClause.push(`"${key}" >= $${paramCount}`);
1669+
whereParams.push(value.gte);
1670+
}
1671+
if (value.lte) {
1672+
paramCount++;
1673+
whereClause.push(`"${key}" <= $${paramCount}`);
1674+
whereParams.push(value.lte);
1675+
}
1676+
}
1677+
// Add other comparison operators as needed
1678+
if ('ne' in value) {
1679+
paramCount++;
1680+
whereClause.push(`"${key}" != $${paramCount}`);
1681+
whereParams.push(value.ne);
1682+
}
1683+
if ('eq' in value) {
1684+
paramCount++;
1685+
whereClause.push(`"${key}" = $${paramCount}`);
1686+
whereParams.push(value.eq);
1687+
}
1688+
if ('gt' in value) {
1689+
paramCount++;
1690+
whereClause.push(`"${key}" > $${paramCount}`);
1691+
whereParams.push(value.gt);
1692+
}
1693+
if ('lt' in value) {
1694+
paramCount++;
1695+
whereClause.push(`"${key}" < $${paramCount}`);
1696+
whereParams.push(value.lt);
1697+
}
1698+
} else {
1699+
paramCount++;
1700+
whereClause.push(`"${key}" = $${paramCount}`);
1701+
whereParams.push(value);
1702+
}
1703+
});
1704+
1705+
return { whereClause, whereParams };
1706+
}
1707+
1708+
private buildOrderClause(order: Record<string, string>): string {
1709+
const orderClause = Object.entries(order)
1710+
.map(([key, direction]) => `"${key}" ${direction}`)
1711+
.join(', ');
1712+
return orderClause ? ` ORDER BY ${orderClause}` : '';
1713+
}
16801714
}
16811715

16821716
export default PGLiteDatabaseAdapter;

packages/adapter-postgres/schema.sql

+3-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ CREATE TABLE IF NOT EXISTS accounts (
4444
"email" TEXT NOT NULL,
4545
"avatarUrl" TEXT,
4646
"details" JSONB DEFAULT '{}'::jsonb,
47-
"status" TEXT
47+
"status" TEXT,
48+
"pid" TEXT,
49+
"source" TEXT
4850
);
4951

5052
CREATE TABLE IF NOT EXISTS rooms (

0 commit comments

Comments
 (0)