{"id":16632,"library":"join-js","title":"JoinJS","description":"JoinJS is a JavaScript library designed to transform flat result sets from database queries, typically involving complex joins, into deeply nested JavaScript objects. It functions as a lightweight alternative to full-blown Object-Relational Mappers (ORMs), giving developers precise control over their SQL queries while simplifying the object mapping layer. The current stable version is 1.1.2, last updated in 2019, suggesting an irregular or halted release cadence. Key differentiators include its \"no-nonsense\" approach to database interaction, inspired by the Java MyBatis framework, which encourages writing raw SQL or using existing query builders like Knex.js, and then leveraging JoinJS solely for the post-query data structuring. It ships with TypeScript definitions, enhancing developer experience for type-safe applications.","status":"abandoned","version":"1.1.2","language":"javascript","source_language":"en","source_url":"https://github.com/archfirst/joinjs","tags":["javascript","typescript"],"install":[{"cmd":"npm install join-js","lang":"bash","label":"npm"},{"cmd":"yarn add join-js","lang":"bash","label":"yarn"},{"cmd":"pnpm add join-js","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The library primarily exposes its functionalities via a default export object in ESM. For CommonJS, use `const joinjs = require('join-js');`","wrong":"import { joinjs } from 'join-js';","symbol":"joinjs (main object)","correct":"import joinjs from 'join-js';"},{"note":"The 'map' function is a method of the default exported 'joinjs' object, not a named export itself.","wrong":"import { map } from 'join-js';","symbol":"map","correct":"import joinjs from 'join-js';\njoinjs.map(resultSet, resultMaps, 'teamMap', 'team_');"},{"note":"The 'mapOne' function is a method of the default exported 'joinjs' object, not a named export itself. It retrieves a single mapped object or throws NotFoundError (since v0.2.0).","wrong":"import { mapOne } from 'join-js';","symbol":"mapOne","correct":"import joinjs from 'join-js';\njoinjs.mapOne(resultSet, resultMaps, 'teamMap', 'team_');"}],"quickstart":{"code":"import joinjs from 'join-js';\n\nconst resultSet = [\n    { team_id: 1, team_name: 'New England Patriots', player_id: 1, player_name: 'Tom Brady'      },\n    { team_id: 1, team_name: 'New England Patriots', player_id: 2, player_name: 'Rob Gronkowski' },\n    { team_id: 2, team_name: 'New York Jets',        player_id: 3, player_name: 'Geno Smith'     },\n    { team_id: 2, team_name: 'New York Jets',        player_id: 4, player_name: 'Darrelle Revis' }\n];\n\nconst resultMaps = [\n    {\n        mapId: 'teamMap',\n        idProperty: 'id',\n        properties: ['name'],\n        collections: [\n            {name: 'players', mapId: 'playerMap', columnPrefix: 'player_'}\n        ]\n    },\n    {\n        mapId: 'playerMap',\n        idProperty: 'id',\n        properties: ['name']\n    }\n];\n\ntry {\n    const mappedResult = joinjs.map(resultSet, resultMaps, 'teamMap', 'team_');\n    console.log('Mapped Result:', JSON.stringify(mappedResult, null, 2));\n\n    const mappedOneTeam = joinjs.mapOne(resultSet, resultMaps, 'teamMap', 'team_');\n    console.log('\\nMapped One Team:', JSON.stringify(mappedOneTeam, null, 2));\n\n    // Demonstrate NotFoundError for mapOne with an empty set\n    const emptyResultSet = [];\n    try {\n        joinjs.mapOne(emptyResultSet, resultMaps, 'teamMap', 'team_');\n    } catch (e) {\n        if (e.name === 'NotFoundError') {\n            console.log('\\nCaught expected NotFoundError for mapOne with empty result set.');\n        } else {\n            throw e;\n        }\n    }\n} catch (error) {\n    console.error('An error occurred:', error);\n}","lang":"typescript","description":"Demonstrates mapping a flat database result set into nested 'Team' and 'Player' objects using `joinjs.map` and `joinjs.mapOne`, including error handling for `NotFoundError`."},"warnings":[{"fix":"Wrap calls to `joinjs.mapOne()` in a `try-catch` block and handle the `NotFoundError` explicitly.","message":"The `mapOne()` method now throws a `NotFoundError` if no matching object is found in the result set, instead of returning `null` or `undefined`. Applications relying on the previous behavior must implement `try-catch` blocks.","severity":"breaking","affected_versions":">=0.2.0"},{"fix":"Evaluate the project's long-term needs for maintenance and consider alternatives if active development and support are critical. Forking the repository for internal maintenance may be an option.","message":"The library has not been actively maintained since its last release in 2019. While functional, it may not receive updates for new JavaScript features, bug fixes, or security patches, which could pose long-term maintenance risks.","severity":"gotcha","affected_versions":">=1.1.2"},{"fix":"Integrate JoinJS with a suitable database driver or query builder. Understand that JoinJS is purely a mapping utility and manage other ORM-like concerns externally.","message":"While JoinJS simplifies mapping, it does not provide features for query building, migrations, or schema management. Developers must use separate tools (e.g., Knex.js, raw SQL) for database interactions.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure `joinjs` is correctly imported as the default export (`import joinjs from 'join-js';` for ESM, `const joinjs = require('join-js');` for CommonJS) before calling `joinjs.map()` or `joinjs.mapOne()`.","cause":"Attempting to call `map` on an undefined or incorrectly imported `joinjs` object, often due to incorrect CommonJS `require` or ESM `import` syntax (e.g., trying to destructure `map` directly if it's not a named export).","error":"TypeError: Cannot read properties of undefined (reading 'map') OR TypeError: joinjs.map is not a function"},{"fix":"Verify that your SQL query returns at least one row corresponding to the expected primary entity. If it's an expected scenario for no data to be found, wrap the call to `mapOne` in a `try-catch` block to handle the `NotFoundError` gracefully.","cause":"The `mapOne` method was called, but the provided `resultSet` did not contain data that could be mapped to a single object based on the given `resultMaps` and `mapId`.","error":"NotFoundError: Mapped object not found"},{"fix":"Carefully review `resultMaps` to ensure `mapId`, `idProperty`, `properties`, and `collections` (including `name`, `mapId`, and `columnPrefix`) accurately reflect the structure of your desired objects and the column names from your database query.","cause":"Misconfiguration in `resultMaps`, particularly incorrect `idProperty`, `properties`, `collections` definitions, or `columnPrefix` values that do not align with the actual column names in the `resultSet`.","error":"Mapped result is empty or incorrect data structure."}],"ecosystem":"npm"}