{"id":16630,"library":"futoin-database","title":"FutoIn Database Interface","description":"futoin-database is a neutral database interface designed for microservices, providing advanced Query and a unique 'revolutionary' Transaction builder. As a reference implementation for FTN17: FutoIn Interface - Database, it focuses on enforcing specific patterns by design, notably lacking direct support for large result sets, cursors, and explicit client-side transaction control to prevent common database anti-patterns. The library leverages a 'single call' transaction pattern, executing multiple statements on the DB side within a single transaction, with back references for sequential query data. It supports auto-configuration through environment variables for connection pooling and works with MySQL, PostgreSQL, and SQLite out of the box. The current stable version is 1.9.12, and it appears to be actively maintained, often with minor version updates. Its core differentiators include its opinionated approach to database interaction and its tight integration with the FutoIn ecosystem, requiring `futoin-asyncsteps`, `futoin-executor`, and `futoin-invoker` as peer dependencies.","status":"active","version":"1.9.12","language":"javascript","source_language":"en","source_url":"https://github.com/futoin/core-js-ri-database","tags":["javascript","futoin","async","db","database","querybuilder","transaction","postgresql","mysql"],"install":[{"cmd":"npm install futoin-database","lang":"bash","label":"npm"},{"cmd":"yarn add futoin-database","lang":"bash","label":"yarn"},{"cmd":"pnpm add futoin-database","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core library for asynchronous control flow, fundamental to FutoIn ecosystem operation.","package":"futoin-asyncsteps","optional":false},{"reason":"Provides the ContainerConnectionManager (CCM) for managing services and connections.","package":"futoin-executor","optional":false},{"reason":"Part of the FutoIn invocation mechanism, often used with Executor and CCM.","package":"futoin-invoker","optional":false}],"imports":[{"note":"While CommonJS `require` is supported by Node.js `>=6`, modern TypeScript/ESM projects should use named `import`.","wrong":"const AutoConfig = require('futoin-database').AutoConfig;","symbol":"AutoConfig","correct":"import { AutoConfig } from 'futoin-database';"},{"note":"QueryBuilder is a named export, not a default export. Ensure curly braces for named import syntax.","wrong":"import QueryBuilder from 'futoin-database';","symbol":"QueryBuilder","correct":"import { QueryBuilder } from 'futoin-database';"},{"note":"This symbol represents the database interface definition, primarily useful for TypeScript type checking. Runtime interaction is typically through an instance obtained from a Container Connection Manager (CCM).","wrong":"const IDataBaseService = require('futoin-database');","symbol":"IDataBaseService","correct":"import { IDataBaseService } from 'futoin-database';"}],"quickstart":{"code":"/*\n  Installation:\n  npm install futoin-asyncsteps futoin-executor futoin-invoker futoin-database sqlite3\n  (sqlite3 is an optional peer dependency for SQLite support that must be explicitly installed if you use it.)\n*/\n\n// Set environment variables for a test in-memory SQLite database.\n// In a real application, these would be set externally (e.g., .env file, Docker config).\nprocess.env.DB_TYPE = 'sqlite';\nprocess.env.DB_PATH = ':memory:'; // Use an in-memory SQLite DB for quick demonstration\nprocess.env.DB_MAXCONN = '1';\nprocess.env.FUTOIN_DB_ALIAS = 'my_sqlite_db'; // Custom alias for clarity\n\nconst AsyncSteps = require('futoin-asyncsteps');\nconst Executor = require('futoin-executor'); // Required for ContainerConnectionManager\nconst { AutoConfig } = require('futoin-database');\n\n// Create a FutoIn Container Connection Manager (CCM)\nconst ccm = new Executor.ContainerConnectionManager();\n\n// Main execution block using AsyncSteps for flow control\nAsyncSteps((as) => {\n    // 1. Auto-configure the database connection using environment variables.\n    // The configuration object indicates supported types, and the last argument\n    // is the alias under which the DB service will be registered in CCM.\n    AutoConfig(as, ccm, {\n        [process.env.FUTOIN_DB_ALIAS]: { type: ['sqlite'] }\n    }, process.env.FUTOIN_DB_ALIAS);\n\n    as.add((as) => {\n        console.log(`Database service '${process.env.FUTOIN_DB_ALIAS}' configured.`);\n        // 2. Get the database service instance from the CCM\n        const db = ccm.get(process.env.FUTOIN_DB_ALIAS);\n\n        // 3. Execute a simple query (Level 1 interface)\n        console.log('\\n--- Executing simple query (Level 1) ---');\n        db.query(as, 'SELECT ? + ? AS result_value', [10, 20]);\n\n        as.add((as, rows) => {\n            console.log('Query result:', rows);\n            console.log('10 + 20 =', rows[0].result_value);\n\n            // 4. Execute a multi-statement transaction (Level 2 interface)\n            // This transaction creates a table, inserts data, and then selects it.\n            // If any step fails, the entire transaction is rolled back.\n            console.log('\\n--- Executing transaction (Level 2) ---');\n            const tx = [\n                // Statement 0: Create table if not exists\n                'CREATE TABLE IF NOT EXISTS sample_users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT)',\n                // Statement 1: Insert data for User A\n                { query: 'INSERT INTO sample_users (name, email) VALUES (?, ?)', params: ['Charlie', 'charlie@example.com'] },\n                // Statement 2: Insert data for User B\n                { query: 'INSERT INTO sample_users (name, email) VALUES (?, ?)', params: ['Diana', 'diana@example.com'] },\n                // Statement 3: Select data for User A by name\n                { query: 'SELECT id, name, email FROM sample_users WHERE name = ?', params: ['Charlie'], expect: 'rows' },\n                // Statement 4: Select data for User B by email\n                { query: 'SELECT id, name, email FROM sample_users WHERE email = ?', params: ['diana@example.com'], expect: 'rows' }\n            ];\n\n            db.transaction(as, tx);\n            as.add((as, results) => {\n                console.log('Transaction results:');\n                // 'results' is an array where each element corresponds to the outcome of a statement in 'tx'.\n                // For 'expect: rows', it will contain an array of row objects.\n                console.log('Charlie data:', results[3][0]); // Result of statement 3\n                console.log('Diana data:', results[4][0]);   // Result of statement 4\n\n                if (results[3][0].name === 'Charlie' && results[4][0].name === 'Diana') {\n                    console.log('Transaction successful: data inserted and retrieved correctly.');\n                }\n            });\n        });\n    });\n},(as, err) => {\n    console.error('An error occurred during execution:', err.message);\n    // Ensure connections are released on error\n    ccm.release();\n    process.exit(1);\n}).whenEnd(() => {\n    console.log('\\nQuickstart execution complete. Releasing resources.');\n    // Ensure connections are released upon successful completion\n    ccm.release();\n    process.exit(0);\n});","lang":"javascript","description":"Demonstrates auto-configuration of an in-memory SQLite database, executing a basic query (Level 1), and a multi-statement transaction with an implicit rollback on failure (Level 2). It showcases the FutoIn database interface's core usage patterns, including integration with `futoin-asyncsteps` and `futoin-executor`."},"warnings":[{"fix":"Adapt application logic to FutoIn's 'single call' transaction pattern and avoid operations requiring cursors or client-managed transactions. Leverage the library's back-reference mechanism for chaining operations within transactions.","message":"FutoIn database interface fundamentally differs from traditional database APIs by intentionally omitting support for large result sets, cursors, and explicit client-side transaction control. This design choice is to enforce specific operational patterns suitable for microservices and may require significant application refactoring for traditional SQL-based projects.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"When installing, use `npm install futoin-database --no-optional` or `yarn add futoin-database --ignore-optional` to only install the package's core dependencies and explicitly install specific database drivers if needed (e.g., `npm install sqlite3`).","message":"The `futoin-database` package includes optional dependencies for various database drivers (e.g., `sqlite3`, `pg`, `mysql`). If not all database types are used, these optional dependencies might be installed unnecessarily, increasing package size. The documentation recommends installing with `--ignore-optional` to mitigate this.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure all required peer dependencies (`futoin-asyncsteps`, `futoin-executor`, `futoin-invoker`) are explicitly installed in your project using `npm install <package-name>` or `yarn add <package-name>`.","message":"`futoin-database` relies heavily on its peer dependencies: `futoin-asyncsteps`, `futoin-executor`, and `futoin-invoker`. These libraries must be installed in the consuming project alongside `futoin-database` for the system to function correctly. Failure to install them will result in runtime errors.","severity":"breaking","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Install the missing peer dependencies: `npm install futoin-asyncsteps futoin-executor futoin-invoker`.","cause":"One of the required FutoIn peer dependencies is missing from your project's `node_modules`.","error":"Error: Cannot find module 'futoin-asyncsteps' (or futoin-executor, futoin-invoker)"},{"fix":"Verify that `AutoConfig(as, ccm, config, alias)` is called successfully before `ccm.get(alias)`. Double-check the alias string for consistency and ensure environment variables (like `DB_TYPE`, `DB_PATH`) are correctly set if using auto-configuration.","cause":"The `AutoConfig` function was either not called, failed to execute, or the alias provided to `ccm.get()` does not match the one used during configuration.","error":"Error: Service 'your_db_alias' is not registered in CCM"},{"fix":"Ensure `AutoConfig` successfully initializes the database connection and registers the service. Check the console for earlier errors during `AutoConfig` execution. Confirm that the required database driver (e.g., `sqlite3` for SQLite) is correctly installed and accessible by `futoin-database`.","cause":"The object retrieved from `ccm.get()` is not a valid FutoIn database service instance, or the underlying database driver failed to initialize, resulting in an incomplete service object.","error":"TypeError: db.query is not a function"}],"ecosystem":"npm"}