diff --git a/CHANGELOG.md b/CHANGELOG.md index 68b528b6a..1008024c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [0.11.15] - 2026-08-24 + +### Fixed + +- **Composant Filter : accepte les items tableau** (ex. lignes d'un xlsx/csv via + upload → valueFromPath). LokiJS n'acceptant que des objets, les items tableau sont + désormais enveloppés dans `{ _wrapped }` à l'insertion puis dé-enveloppés avant + l'évaluation `$where` et dans le résultat. Plus d'erreurs « Object cannot be null » / + « Document needs to be an object » sur les flux de fichiers. + ## [0.11.14] - 2026-08-24 ### Security diff --git a/package.json b/package.json index 8604f2769..59eaa0518 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "semantic-bus-monorepo", - "version": "0.11.14", + "version": "0.11.15", "description": "ETL style data middleware transformation embedded in an ESB for all kind of data", "private": true, "workspaces": [ diff --git a/packages/core/package.json b/packages/core/package.json index 0563a9a67..5c8737d3d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@semantic-bus/core", - "version": "0.11.14", + "version": "0.11.15", "description": "Core module for Semantic Bus", "private": true, "main": "index.js", diff --git a/packages/engine/__tests__/workspaceComponentExecutor/filter.test.js b/packages/engine/__tests__/workspaceComponentExecutor/filter.test.js index 78dd9539d..fb090aca2 100644 --- a/packages/engine/__tests__/workspaceComponentExecutor/filter.test.js +++ b/packages/engine/__tests__/workspaceComponentExecutor/filter.test.js @@ -65,4 +65,38 @@ describe('filter $where - eval validé (validateExpression)', () => { error: '$where have to be the only property when it is used' }); }); +}); + +describe('filter - accepte les items tableau (lignes xlsx/csv)', () => { + function makeWrappedCollection(items) { + const db = new Loki('test-arrays'); + const col = db.addCollection('items', { disableMeta: true }); + // reproduit filterRawItems : les tableaux sont enveloppés dans { _wrapped } + for (const item of items) { + col.insert(Array.isArray(item) ? { _wrapped: item } : item); + } + return col; + } + + test('filter dé-enveloppe les items tableau (cas find simple)', async () => { + const col = makeWrappedCollection([{ name: 'obj' }, ['a', 'b'], []]); + const result = await Filter.filter(col, { name: { $exists: true } }, {}); + // le filtre non-$where matche l objet ; vérifions aussi le dé-enveloppement global + expect(result).toHaveLength(1); + expect(result[0].name).toBe('obj'); + }); + + test('filterRawItems accepte un tableau de tableaux sans erreur (lignes xlsx)', async () => { + const items = [ + [null, null, 'SOLIS', null], + [], + ['Nom', 'Age'], + [null, 'Alice', 30] + ]; + const filter = { $where: 'this.length > 0' }; + const data = { _id: 'comp-filter' }; + const result = await Filter.filterRawItems(items, filter, data); + // aucun erreur d insertion (Loki ne rejette plus les tableaux) + expect(result.errors).toBeUndefined(); + }); }); \ No newline at end of file diff --git a/packages/engine/package.json b/packages/engine/package.json index 5a7d83d38..a26cf72c3 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@semantic-bus/engine", - "version": "0.11.14", + "version": "0.11.15", "description": "Processing engine module for Semantic Bus", "private": true, "main": "app.js", diff --git a/packages/engine/workspaceComponentExecutor/filter.js b/packages/engine/workspaceComponentExecutor/filter.js index ab247892d..1561968a0 100644 --- a/packages/engine/workspaceComponentExecutor/filter.js +++ b/packages/engine/workspaceComponentExecutor/filter.js @@ -68,7 +68,14 @@ class Filter { if (item !== undefined && item !== null) { if (typeof item === 'object') { try { - collection.insert(item); + // Loki n'accepte que des objets : un item TABLEAU (ex. une ligne d'un + // xlsx/csv : [c1,c2,...]) est enveloppé dans { _wrapped: item } pour être + // insérable, puis dé-enveloppé avant l'évaluation et dans le résultat. + if (Array.isArray(item)) { + collection.insert({ _wrapped: item }); + } else { + collection.insert(item); + } } catch (insertError) { insertionErrors.push({ error: insertError.message, @@ -140,19 +147,26 @@ class Filter { const whereCondition = filter['$where'].replace(/this/g, 'obj'); validateExpression(whereCondition); const whereItems = collection.find({}); + // Dé-enveloppe les items tableaux (insérés via { _wrapped: item }) : + // l'évaluation porte sur l'item d'origine (le tableau). + const unwrappedItems = whereItems.map(doc => + doc && doc._wrapped !== undefined ? doc._wrapped : doc + ); const whereMatches = []; - for (let i = 0; i < whereItems.length; i++) { - const res = await runEvalInRemote(whereCondition, { obj: whereItems[i] }); + for (let i = 0; i < unwrappedItems.length; i++) { + const res = await runEvalInRemote(whereCondition, { obj: unwrappedItems[i] }); if (res == true) whereMatches.push(i); } - resultData = whereMatches.map(i => whereItems[i]); + resultData = whereMatches.map(i => unwrappedItems[i]); } else { reject({ error: '$where have to be the only property when it is used' }); } } else { - resultData = collection.find(filter); + resultData = collection.find(filter).map(doc => + doc && doc._wrapped !== undefined ? doc._wrapped : doc + ); } - resultData = resultData.map(r => { delete r['$loki']; return r; }); + resultData = resultData.map(r => { if (r && typeof r === 'object' && !Array.isArray(r)) delete r['$loki']; return r; }); resolve(resultData); } catch (e) { reject(e); @@ -188,14 +202,15 @@ class Filter { pathTable: pathTable, callBackOnPath: async (item) => { // console.log('___item', item); - if (item!==undefined && item!==null) { + if (item!==undefined && item!==null && !Array.isArray(item)) { delete item['$loki']; } if (item!==undefined) { // Check if item is an object before inserting (LokiJS requires objects) if (typeof item === 'object' && item !== null) { try { - collection.insert(item); + // Les tableaux sont enveloppés dans { _wrapped: item } (voir filterRawItems) + collection.insert(Array.isArray(item) ? { _wrapped: item } : item); } catch (insertError) { insertionErrors.push({ error: insertError.message, diff --git a/packages/eval-service/package.json b/packages/eval-service/package.json index ceb770954..baddcc518 100644 --- a/packages/eval-service/package.json +++ b/packages/eval-service/package.json @@ -1,6 +1,6 @@ { "name": "@semantic-bus/eval-service", - "version": "0.11.14", + "version": "0.11.15", "description": "Service d'évaluation JavaScript isolé en container (dédié aux eval des transformations / $where).", "private": true, "main": "app.js", diff --git a/packages/main/package.json b/packages/main/package.json index c5cd003a6..0babffdff 100644 --- a/packages/main/package.json +++ b/packages/main/package.json @@ -1,6 +1,6 @@ { "name": "@semantic-bus/main", - "version": "0.11.14", + "version": "0.11.15", "description": "Main application module for Semantic Bus", "private": true, "main": "app.js", diff --git a/packages/timer/package.json b/packages/timer/package.json index 8954d1b2e..608b5e133 100644 --- a/packages/timer/package.json +++ b/packages/timer/package.json @@ -1,6 +1,6 @@ { "name": "@semantic-bus/timer", - "version": "0.11.14", + "version": "0.11.15", "description": "Timer scheduler module for Semantic Bus", "private": true, "main": "app.js",