@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rsktash/beads-ui",
3
- "version": "0.1.40",
3
+ "version": "0.1.41",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/rsktash/beads-ui.git"
@@ -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
  *