@rsktash/beads-ui 0.1.40 → 0.1.41
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/package.json +1 -1
- package/server/dolt-queries.js +92 -0
package/package.json
CHANGED
package/server/dolt-queries.js
CHANGED
|
@@ -80,6 +80,98 @@ function buildPagination(pagination) {
|
|
|
80
80
|
return { limitClause };
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Enrich list items with parent_title, children counts, and blocked_by.
|
|
85
|
+
* Runs batch queries to avoid N+1.
|
|
86
|
+
*
|
|
87
|
+
* @param {Array<Record<string, unknown>>} items
|
|
88
|
+
* @returns {Promise<Array<Record<string, unknown>>>}
|
|
89
|
+
*/
|
|
90
|
+
export async function enrichListItems(items) {
|
|
91
|
+
const pool = getPool();
|
|
92
|
+
if (!pool || items.length === 0) return items;
|
|
93
|
+
|
|
94
|
+
const ids = items.map(i => i.id);
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
// Batch: resolve parent IDs from dependencies table
|
|
98
|
+
/** @type {Map<string, string>} */
|
|
99
|
+
const parentIdMap = new Map();
|
|
100
|
+
const [parentDepRows] = await pool.query(
|
|
101
|
+
`SELECT issue_id, depends_on_id FROM dependencies
|
|
102
|
+
WHERE type = 'parent-child' AND issue_id IN (${ids.map(() => '?').join(',')})`,
|
|
103
|
+
ids
|
|
104
|
+
);
|
|
105
|
+
for (const r of /** @type {any[]} */ (parentDepRows)) {
|
|
106
|
+
parentIdMap.set(r.issue_id, r.depends_on_id);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Batch: parent titles
|
|
110
|
+
const parentIds = [...new Set(parentIdMap.values())];
|
|
111
|
+
/** @type {Map<string, string>} */
|
|
112
|
+
const parentTitles = new Map();
|
|
113
|
+
if (parentIds.length > 0) {
|
|
114
|
+
const [rows] = await pool.query(
|
|
115
|
+
`SELECT id, title FROM issues WHERE id IN (${parentIds.map(() => '?').join(',')})`,
|
|
116
|
+
parentIds
|
|
117
|
+
);
|
|
118
|
+
for (const r of /** @type {any[]} */ (rows)) parentTitles.set(r.id, r.title);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Batch: children counts
|
|
122
|
+
const [childRows] = await pool.query(
|
|
123
|
+
`SELECT depends_on_id AS pid, COUNT(*) AS total,
|
|
124
|
+
SUM(CASE WHEN i.status = 'closed' THEN 1 ELSE 0 END) AS closed
|
|
125
|
+
FROM dependencies d JOIN issues i ON i.id = d.issue_id
|
|
126
|
+
WHERE d.type = 'parent-child' AND d.depends_on_id IN (${ids.map(() => '?').join(',')})
|
|
127
|
+
GROUP BY d.depends_on_id`,
|
|
128
|
+
ids
|
|
129
|
+
);
|
|
130
|
+
/** @type {Map<string, { total: number, closed: number }>} */
|
|
131
|
+
const childCounts = new Map();
|
|
132
|
+
for (const r of /** @type {any[]} */ (childRows)) {
|
|
133
|
+
childCounts.set(r.pid, { total: Number(r.total), closed: Number(r.closed) });
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Batch: blocked by (issues that block each item)
|
|
137
|
+
const [blockRows] = await pool.query(
|
|
138
|
+
`SELECT d.issue_id, d.depends_on_id, i.title AS blocker_title
|
|
139
|
+
FROM dependencies d JOIN issues i ON i.id = d.depends_on_id
|
|
140
|
+
WHERE d.type = 'blocks' AND d.issue_id IN (${ids.map(() => '?').join(',')})
|
|
141
|
+
AND i.status != 'closed'`,
|
|
142
|
+
ids
|
|
143
|
+
);
|
|
144
|
+
/** @type {Map<string, Array<{ id: string, title: string }>>} */
|
|
145
|
+
const blockedBy = new Map();
|
|
146
|
+
for (const r of /** @type {any[]} */ (blockRows)) {
|
|
147
|
+
if (!blockedBy.has(r.issue_id)) blockedBy.set(r.issue_id, []);
|
|
148
|
+
blockedBy.get(r.issue_id).push({ id: r.depends_on_id, title: r.blocker_title });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return items.map(item => {
|
|
152
|
+
const enriched = { ...item };
|
|
153
|
+
const pid = parentIdMap.get(/** @type {string} */ (enriched.id));
|
|
154
|
+
if (pid) {
|
|
155
|
+
enriched.parent_id = pid;
|
|
156
|
+
if (parentTitles.has(pid)) enriched.parent_title = parentTitles.get(pid);
|
|
157
|
+
}
|
|
158
|
+
const cc = childCounts.get(/** @type {string} */ (enriched.id));
|
|
159
|
+
if (cc) {
|
|
160
|
+
enriched.total_children = cc.total;
|
|
161
|
+
enriched.closed_children = cc.closed;
|
|
162
|
+
}
|
|
163
|
+
const bb = blockedBy.get(/** @type {string} */ (enriched.id));
|
|
164
|
+
if (bb && bb.length > 0) {
|
|
165
|
+
enriched.blocked_by = bb;
|
|
166
|
+
}
|
|
167
|
+
return enriched;
|
|
168
|
+
});
|
|
169
|
+
} catch (err) {
|
|
170
|
+
log('enrichListItems error: %o', err);
|
|
171
|
+
return items;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
83
175
|
/**
|
|
84
176
|
* Fetch total count for a WHERE clause.
|
|
85
177
|
*
|