Skip to main content
Glama
CloudflareD1Repository.test.jsβ€’25.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const vitest_1 = require("vitest"); const CloudflareD1Repository_1 = require("./CloudflareD1Repository"); const DatabaseConfig_1 = require("../config/DatabaseConfig"); const Environment_1 = require("../../domain/value-objects/Environment"); (0, vitest_1.describe)('CloudflareD1Repository', () => { let repository; let mockApiClient; let mockDatabaseConfig; (0, vitest_1.beforeEach)(() => { // Create mock API client mockApiClient = { query: vitest_1.vi.fn(), getDatabaseInfo: vitest_1.vi.fn(), }; // Create mock database config const databases = new Map(); databases.set(Environment_1.Environment.DEVELOPMENT, { name: 'dev_db', id: 'dev-123' }); databases.set(Environment_1.Environment.PRODUCTION, { name: 'prod_db', id: 'prod-456' }); mockDatabaseConfig = new DatabaseConfig_1.DatabaseConfig(databases); repository = new CloudflareD1Repository_1.CloudflareD1Repository(mockApiClient, mockDatabaseConfig, Environment_1.Environment.DEVELOPMENT); vitest_1.vi.clearAllMocks(); }); (0, vitest_1.describe)('constructor', () => { (0, vitest_1.it)('should create repository with dependencies', () => { (0, vitest_1.expect)(repository).toBeInstanceOf(CloudflareD1Repository_1.CloudflareD1Repository); }); (0, vitest_1.it)('should be frozen for immutability', () => { (0, vitest_1.expect)(Object.isFrozen(repository)).toBe(true); }); (0, vitest_1.it)('should default to DEVELOPMENT environment', () => { const repo = new CloudflareD1Repository_1.CloudflareD1Repository(mockApiClient, mockDatabaseConfig); (0, vitest_1.expect)(repo).toBeInstanceOf(CloudflareD1Repository_1.CloudflareD1Repository); }); }); (0, vitest_1.describe)('fetchDatabaseSchema()', () => { (0, vitest_1.it)('should fetch complete database schema', async () => { // Mock sqlite_master query mockApiClient.query.mockResolvedValueOnce({ success: true, results: [ { type: 'table', name: 'users', sql: 'CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)' }, { type: 'table', name: 'posts', sql: 'CREATE TABLE posts (id INTEGER PRIMARY KEY, user_id INTEGER)' }, ], }); // Mock PRAGMA table_info for users mockApiClient.query.mockResolvedValueOnce({ success: true, results: [ { cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null, pk: 1 }, { cid: 1, name: 'name', type: 'TEXT', notnull: 0, dflt_value: null, pk: 0 }, ], }); // Mock PRAGMA index_list for users mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list for users mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA table_info for posts mockApiClient.query.mockResolvedValueOnce({ success: true, results: [ { cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null, pk: 1 }, { cid: 1, name: 'user_id', type: 'INTEGER', notnull: 0, dflt_value: null, pk: 0 }, ], }); // Mock PRAGMA index_list for posts mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list for posts mockApiClient.query.mockResolvedValueOnce({ success: true, results: [ { id: 0, seq: 0, table: 'users', from: 'user_id', to: 'id', on_update: 'NO ACTION', on_delete: 'CASCADE', match: 'NONE', }, ], }); const schema = await repository.fetchDatabaseSchema(); (0, vitest_1.expect)(schema.name).toBe('dev_db'); (0, vitest_1.expect)(schema.environment).toBe(Environment_1.Environment.DEVELOPMENT); (0, vitest_1.expect)(schema.tables).toHaveLength(2); (0, vitest_1.expect)(schema.tables[0].name).toBe('users'); (0, vitest_1.expect)(schema.tables[1].name).toBe('posts'); (0, vitest_1.expect)(schema.fetchedAt).toBeInstanceOf(Date); }); (0, vitest_1.it)('should use provided database ID', async () => { // Mock sqlite_master query with at least one table mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ type: 'table', name: 'users', sql: 'CREATE TABLE users (id INTEGER)' }], }); // Mock PRAGMA table_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null, pk: 1 }], }); // Mock PRAGMA index_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); await repository.fetchDatabaseSchema('custom-db-id'); (0, vitest_1.expect)(mockApiClient.query).toHaveBeenCalledWith('custom-db-id', vitest_1.expect.stringContaining('SELECT type, name, sql FROM sqlite_master')); }); (0, vitest_1.it)('should use environment database ID when not provided', async () => { // Mock sqlite_master query with at least one table mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ type: 'table', name: 'users', sql: 'CREATE TABLE users (id INTEGER)' }], }); // Mock PRAGMA table_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null, pk: 1 }], }); // Mock PRAGMA index_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); await repository.fetchDatabaseSchema(); (0, vitest_1.expect)(mockApiClient.query).toHaveBeenCalledWith('dev-123', vitest_1.expect.stringContaining('SELECT type, name, sql FROM sqlite_master')); }); (0, vitest_1.it)('should return empty tables array when no tables exist', async () => { mockApiClient.query.mockResolvedValue({ success: true, results: [], }); const tables = await repository.fetchTableDetails(); (0, vitest_1.expect)(tables).toHaveLength(0); }); }); (0, vitest_1.describe)('fetchTableDetails()', () => { (0, vitest_1.it)('should fetch all tables when no table name specified', async () => { // Mock sqlite_master query mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ type: 'table', name: 'users', sql: 'CREATE TABLE users (id INTEGER)' }], }); // Mock PRAGMA table_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null, pk: 1 }], }); // Mock PRAGMA index_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); const tables = await repository.fetchTableDetails(); (0, vitest_1.expect)(mockApiClient.query).toHaveBeenCalledWith('dev-123', vitest_1.expect.stringContaining("WHERE type IN ('table', 'view') ORDER BY name")); (0, vitest_1.expect)(tables).toHaveLength(1); }); (0, vitest_1.it)('should fetch specific table when table name specified', async () => { // Mock sqlite_master query mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ type: 'table', name: 'users', sql: 'CREATE TABLE users (id INTEGER)' }], }); // Mock PRAGMA table_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null, pk: 1 }], }); // Mock PRAGMA index_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); const tables = await repository.fetchTableDetails(undefined, 'users'); (0, vitest_1.expect)(mockApiClient.query).toHaveBeenCalledWith('dev-123', vitest_1.expect.stringContaining("AND name = 'users'")); }); (0, vitest_1.it)('should include table columns', async () => { // Mock sqlite_master query mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ type: 'table', name: 'users', sql: 'CREATE TABLE users (id INTEGER, name TEXT)' }], }); // Mock PRAGMA table_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [ { cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null, pk: 1 }, { cid: 1, name: 'name', type: 'TEXT', notnull: 0, dflt_value: "'unknown'", pk: 0 }, ], }); // Mock PRAGMA index_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); const tables = await repository.fetchTableDetails(); (0, vitest_1.expect)(tables[0].columns).toHaveLength(2); (0, vitest_1.expect)(tables[0].columns[0].name).toBe('id'); (0, vitest_1.expect)(tables[0].columns[0].isPrimaryKey).toBe(true); (0, vitest_1.expect)(tables[0].columns[1].name).toBe('name'); (0, vitest_1.expect)(tables[0].columns[1].isNullable).toBe(true); (0, vitest_1.expect)(tables[0].columns[1].defaultValue).toBe("'unknown'"); }); (0, vitest_1.it)('should include table indexes', async () => { // Mock sqlite_master query mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ type: 'table', name: 'users', sql: 'CREATE TABLE users (id INTEGER, email TEXT)' }], }); // Mock PRAGMA table_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [ { cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null, pk: 1 }, { cid: 1, name: 'email', type: 'TEXT', notnull: 1, dflt_value: null, pk: 0 }, ], }); // Mock PRAGMA index_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ seq: 0, name: 'idx_users_email', unique: 1, origin: 'c', partial: 0 }], }); // Mock PRAGMA index_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ seqno: 0, cid: 1, name: 'email' }], }); // Mock PRAGMA foreign_key_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); const tables = await repository.fetchTableDetails(); (0, vitest_1.expect)(tables[0].indexes).toHaveLength(1); (0, vitest_1.expect)(tables[0].indexes[0].name).toBe('idx_users_email'); (0, vitest_1.expect)(tables[0].indexes[0].columns).toEqual(['email']); (0, vitest_1.expect)(tables[0].indexes[0].isUnique).toBe(true); }); (0, vitest_1.it)('should include table foreign keys', async () => { // Mock sqlite_master query mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ type: 'table', name: 'posts', sql: 'CREATE TABLE posts (id INTEGER, user_id INTEGER)' }], }); // Mock PRAGMA table_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [ { cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null, pk: 1 }, { cid: 1, name: 'user_id', type: 'INTEGER', notnull: 0, dflt_value: null, pk: 0 }, ], }); // Mock PRAGMA index_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [ { id: 0, seq: 0, table: 'users', from: 'user_id', to: 'id', on_update: 'NO ACTION', on_delete: 'CASCADE', match: 'NONE', }, ], }); const tables = await repository.fetchTableDetails(); (0, vitest_1.expect)(tables[0].foreignKeys).toHaveLength(1); (0, vitest_1.expect)(tables[0].foreignKeys[0].table).toBe('posts'); (0, vitest_1.expect)(tables[0].foreignKeys[0].column).toBe('user_id'); (0, vitest_1.expect)(tables[0].foreignKeys[0].referencesTable).toBe('users'); (0, vitest_1.expect)(tables[0].foreignKeys[0].referencesColumn).toBe('id'); (0, vitest_1.expect)(tables[0].foreignKeys[0].onDelete).toBe('CASCADE'); }); (0, vitest_1.it)('should handle views', async () => { // Mock sqlite_master query mockApiClient.query.mockResolvedValueOnce({ success: true, results: [ { type: 'view', name: 'active_users', sql: 'CREATE VIEW active_users AS SELECT * FROM users' }, ], }); // Mock PRAGMA table_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ cid: 0, name: 'id', type: 'INTEGER', notnull: 0, dflt_value: null, pk: 0 }], }); // Mock PRAGMA index_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); const tables = await repository.fetchTableDetails(); (0, vitest_1.expect)(tables[0].type).toBe('view'); (0, vitest_1.expect)(tables[0].isView()).toBe(true); }); (0, vitest_1.it)('should return empty array when no tables', async () => { mockApiClient.query.mockResolvedValue({ success: true, results: [], }); const tables = await repository.fetchTableDetails(); (0, vitest_1.expect)(tables).toHaveLength(0); }); }); (0, vitest_1.describe)('fetchIndexInformation()', () => { (0, vitest_1.it)('should fetch all indexes from sqlite_master', async () => { mockApiClient.query.mockResolvedValue({ success: true, results: [ { name: 'idx_users_email', tbl_name: 'users', sql: 'CREATE UNIQUE INDEX idx_users_email ON users(email)', }, { name: 'idx_posts_user_id', tbl_name: 'posts', sql: 'CREATE INDEX idx_posts_user_id ON posts(user_id)', }, ], }); const indexes = await repository.fetchIndexInformation(); (0, vitest_1.expect)(indexes).toHaveLength(2); (0, vitest_1.expect)(indexes[0].name).toBe('idx_users_email'); (0, vitest_1.expect)(indexes[0].tableName).toBe('users'); (0, vitest_1.expect)(indexes[0].columns).toEqual(['email']); (0, vitest_1.expect)(indexes[0].isUnique).toBe(true); (0, vitest_1.expect)(indexes[1].name).toBe('idx_posts_user_id'); (0, vitest_1.expect)(indexes[1].tableName).toBe('posts'); (0, vitest_1.expect)(indexes[1].columns).toEqual(['user_id']); (0, vitest_1.expect)(indexes[1].isUnique).toBe(false); }); (0, vitest_1.it)('should parse multi-column indexes', async () => { mockApiClient.query.mockResolvedValue({ success: true, results: [ { name: 'idx_users_name_email', tbl_name: 'users', sql: 'CREATE INDEX idx_users_name_email ON users(name, email)', }, ], }); const indexes = await repository.fetchIndexInformation(); (0, vitest_1.expect)(indexes[0].columns).toEqual(['name', 'email']); }); (0, vitest_1.it)('should use provided database ID', async () => { mockApiClient.query.mockResolvedValue({ success: true, results: [], }); await repository.fetchIndexInformation('custom-db-id'); (0, vitest_1.expect)(mockApiClient.query).toHaveBeenCalledWith('custom-db-id', vitest_1.expect.stringContaining("WHERE type = 'index'")); }); (0, vitest_1.it)('should return empty array when no indexes', async () => { mockApiClient.query.mockResolvedValue({ success: true, results: [], }); const indexes = await repository.fetchIndexInformation(); (0, vitest_1.expect)(indexes).toHaveLength(0); }); }); (0, vitest_1.describe)('executeSQLQuery()', () => { (0, vitest_1.it)('should execute SQL query and return results', async () => { mockApiClient.query.mockResolvedValue({ success: true, results: [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, ], meta: { duration: 15, rows_read: 2, }, }); const result = await repository.executeSQLQuery('db-123', 'SELECT * FROM users'); (0, vitest_1.expect)(result.success).toBe(true); (0, vitest_1.expect)(result.results).toHaveLength(2); (0, vitest_1.expect)(result.meta?.duration).toBe(15); (0, vitest_1.expect)(result.meta?.rows_read).toBe(2); }); (0, vitest_1.it)('should handle empty results', async () => { mockApiClient.query.mockResolvedValue({ success: true, results: [], }); const result = await repository.executeSQLQuery('db-123', 'DELETE FROM users WHERE id = 999'); (0, vitest_1.expect)(result.success).toBe(true); (0, vitest_1.expect)(result.results).toHaveLength(0); }); (0, vitest_1.it)('should handle failed queries', async () => { mockApiClient.query.mockResolvedValue({ success: false, results: [], }); const result = await repository.executeSQLQuery('db-123', 'INVALID SQL'); (0, vitest_1.expect)(result.success).toBe(false); }); }); (0, vitest_1.describe)('private methods behavior', () => { (0, vitest_1.it)('should handle columns with nullable=true (notnull=0)', async () => { // Mock sqlite_master query mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ type: 'table', name: 'users', sql: 'CREATE TABLE users (name TEXT)' }], }); // Mock PRAGMA table_info with notnull=0 (nullable) mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ cid: 0, name: 'name', type: 'TEXT', notnull: 0, dflt_value: null, pk: 0 }], }); // Mock PRAGMA index_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); const tables = await repository.fetchTableDetails(); (0, vitest_1.expect)(tables[0].columns[0].isNullable).toBe(true); }); (0, vitest_1.it)('should handle indexes with origin=pk (primary key)', async () => { // Mock sqlite_master query mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ type: 'table', name: 'users', sql: 'CREATE TABLE users (id INTEGER PRIMARY KEY)' }], }); // Mock PRAGMA table_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ cid: 0, name: 'id', type: 'INTEGER', notnull: 1, dflt_value: null, pk: 1 }], }); // Mock PRAGMA index_list with origin=pk mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ seq: 0, name: 'sqlite_autoindex_users_1', unique: 1, origin: 'pk', partial: 0 }], }); // Mock PRAGMA index_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ seqno: 0, cid: 0, name: 'id' }], }); // Mock PRAGMA foreign_key_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); const tables = await repository.fetchTableDetails(); (0, vitest_1.expect)(tables[0].indexes[0].isPrimaryKey).toBe(true); }); (0, vitest_1.it)('should handle foreign keys with null on_delete/on_update', async () => { // Mock sqlite_master query mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ type: 'table', name: 'posts', sql: 'CREATE TABLE posts (user_id INTEGER)' }], }); // Mock PRAGMA table_info mockApiClient.query.mockResolvedValueOnce({ success: true, results: [{ cid: 0, name: 'user_id', type: 'INTEGER', notnull: 0, dflt_value: null, pk: 0 }], }); // Mock PRAGMA index_list mockApiClient.query.mockResolvedValueOnce({ success: true, results: [], }); // Mock PRAGMA foreign_key_list with null on_delete/on_update mockApiClient.query.mockResolvedValueOnce({ success: true, results: [ { id: 0, seq: 0, table: 'users', from: 'user_id', to: 'id', on_update: null, on_delete: null, match: 'NONE', }, ], }); const tables = await repository.fetchTableDetails(); (0, vitest_1.expect)(tables[0].foreignKeys[0].onDelete).toBe('NO ACTION'); (0, vitest_1.expect)(tables[0].foreignKeys[0].onUpdate).toBe('NO ACTION'); }); }); }); //# sourceMappingURL=CloudflareD1Repository.test.js.map

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/semanticintent/semantic-d1-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server