Skip to content
This repository was archived by the owner on Sep 4, 2025. It is now read-only.

Commit a05844f

Browse files
committed
feat(packages): Add new package structure - data-core, data-host-node, data-templates, data-cli
- Created modular ESM package architecture - data-core: Pure JavaScript logic, no I/O - data-host-node: Node.js adapter implementations - data-templates: Deno Edge Function templates - data-cli: Command-line interface shell (to be populated) Note: Migration of src/ to packages/ incomplete - need to recreate conversions
1 parent 508a243 commit a05844f

File tree

7 files changed

+299
-3
lines changed

7 files changed

+299
-3
lines changed

packages/data-cli/bin/data.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* D.A.T.A. CLI Entry Point
5+
*
6+
* Simple executable that imports and runs the CLI
7+
*/
8+
9+
import { cli } from '../index.js';
10+
11+
// Run CLI with process arguments
12+
cli(process.argv).catch(error => {
13+
console.error('Fatal error:', error.message);
14+
process.exit(1);
15+
});

packages/data-cli/index.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* D.A.T.A. CLI Main Module
3+
*
4+
* Provides the command-line interface for database automation,
5+
* testing, and alignment operations.
6+
*/
7+
8+
import { Command } from 'commander';
9+
import { DataCore } from '@data/core';
10+
import { createNodeAdapters } from '@data/host-node';
11+
import { readFileSync } from 'fs';
12+
import { fileURLToPath } from 'url';
13+
import { dirname, join } from 'path';
14+
15+
const __filename = fileURLToPath(import.meta.url);
16+
const __dirname = dirname(__filename);
17+
const { version } = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf8'));
18+
19+
/**
20+
* Main CLI function
21+
* @param {string[]} argv - Command line arguments
22+
*/
23+
export async function cli(argv) {
24+
const program = new Command();
25+
26+
program
27+
.name('data')
28+
.description('⛰️ D.A.T.A. - Database Automation, Testing & Alignment')
29+
.version(version)
30+
.option('--prod', 'Target production environment')
31+
.option('--json', 'Output results as JSON')
32+
.option('--no-color', 'Disable colored output');
33+
34+
// Initialize command
35+
program
36+
.command('init')
37+
.description('Initialize a new D.A.T.A. project')
38+
.option('--path <path>', 'Project path (default: current directory)')
39+
.action(async (options) => {
40+
console.log('Initializing D.A.T.A. project...');
41+
// TODO: Implement init command using DataCore
42+
});
43+
44+
// Database commands
45+
const db = program
46+
.command('db')
47+
.description('Database operations');
48+
49+
db.command('compile')
50+
.description('Compile SQL sources into migration')
51+
.option('--sql-dir <path>', 'SQL source directory', './sql')
52+
.option('--migrations-dir <path>', 'Migrations output directory', './migrations')
53+
.action(async (options) => {
54+
const adapters = createNodeAdapters();
55+
const dataCore = new DataCore(adapters);
56+
57+
try {
58+
console.log('Compiling SQL sources...');
59+
// TODO: Implement compile using DataCore
60+
} catch (error) {
61+
console.error('Compilation failed:', error.message);
62+
process.exit(1);
63+
}
64+
});
65+
66+
// Test commands
67+
const test = program
68+
.command('test')
69+
.description('Testing operations');
70+
71+
test.command('run')
72+
.description('Run database tests')
73+
.option('--pattern <pattern>', 'Test pattern to match')
74+
.action(async (options) => {
75+
console.log('Running tests...');
76+
// TODO: Implement test runner using DataCore
77+
});
78+
79+
// Parse arguments
80+
await program.parseAsync(argv);
81+
82+
// Show help if no command provided
83+
if (argv.length === 2) {
84+
program.help();
85+
}
86+
}
87+
88+
export default cli;

packages/data-cli/package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "@data/cli",
3+
"version": "1.0.0",
4+
"description": "D.A.T.A. CLI - Database Automation, Testing & Alignment",
5+
"type": "module",
6+
"main": "index.js",
7+
"bin": {
8+
"data": "./bin/data.js"
9+
},
10+
"dependencies": {
11+
"@data/core": "file:../data-core",
12+
"@data/host-node": "file:../data-host-node",
13+
"@data/templates": "file:../data-templates",
14+
"commander": "^12.1.0"
15+
},
16+
"engines": {
17+
"node": ">=20.0.0"
18+
}
19+
}

packages/data-core/example-di.js

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Example demonstrating the dependency injection system.
5+
* Shows how to wire data-core with data-host-node adapters using DI.
6+
*
7+
* Run with: node packages/data-core/example-di.js
8+
*/
9+
10+
import { DIContainer } from './ports/DIContainer.js';
11+
import { PortFactory, wireDataCore } from './ports/PortFactory.js';
12+
import { DataCore } from './index.js';
13+
14+
// Import Node.js adapters
15+
import {
16+
FileSystemAdapter,
17+
CryptoAdapter,
18+
ProcessAdapter,
19+
EnvironmentAdapter
20+
} from '../data-host-node/index.js';
21+
22+
console.log('🔗 Dependency Injection System Demo\n');
23+
24+
// === Method 1: Using DIContainer directly ===
25+
console.log('📦 Method 1: Using DIContainer directly');
26+
27+
const container = new DIContainer();
28+
29+
// Register all adapters as singletons
30+
container
31+
.registerSingleton('fileSystem', FileSystemAdapter, {
32+
config: { encoding: 'utf8' }
33+
})
34+
.registerSingleton('crypto', CryptoAdapter, {
35+
config: { defaultAlgorithm: 'sha256' }
36+
})
37+
.registerSingleton('process', ProcessAdapter, {
38+
config: { timeout: 30000, shell: '/bin/bash' }
39+
})
40+
.registerSingleton('environment', EnvironmentAdapter, {
41+
config: { prefix: 'DATA_' }
42+
});
43+
44+
// Register DataCore with automatic dependency injection
45+
container.register('dataCore', DataCore);
46+
47+
// Resolve DataCore - all dependencies automatically injected
48+
const dataCore1 = container.resolve('dataCore');
49+
console.log(`✅ DataCore resolved with ports: ${Object.keys(dataCore1).filter(k => k.endsWith('Port')).join(', ')}`);
50+
console.log(`📊 Container stats:`, container.getStats());
51+
52+
console.log('\n---\n');
53+
54+
// === Method 2: Using PortFactory ===
55+
console.log('🏭 Method 2: Using PortFactory');
56+
57+
const factory = new PortFactory();
58+
59+
// Register adapters with factory
60+
factory
61+
.registerPort('fileSystem', FileSystemAdapter, FileSystemAdapter, { encoding: 'utf8' })
62+
.registerPort('crypto', CryptoAdapter, CryptoAdapter, { defaultAlgorithm: 'sha256' })
63+
.registerPort('process', ProcessAdapter, ProcessAdapter, { timeout: 30000 })
64+
.registerPort('environment', EnvironmentAdapter, EnvironmentAdapter, { prefix: 'DATA_' });
65+
66+
// Create all data-core compatible ports
67+
const ports = factory.createDataCorePorts({
68+
fileSystem: { encoding: 'utf8', mode: 0o644 },
69+
crypto: { defaultAlgorithm: 'sha256' },
70+
process: { timeout: 30000, shell: '/bin/bash' },
71+
environment: { prefix: 'DATA_', caseSensitive: true }
72+
});
73+
74+
// Create DataCore with ports
75+
const dataCore2 = new DataCore(
76+
ports.fileSystem,
77+
ports.crypto,
78+
ports.process,
79+
ports.environment
80+
);
81+
82+
console.log(`✅ DataCore created with factory-generated ports`);
83+
console.log(`📊 Factory info:`, factory.getPortInfo());
84+
85+
console.log('\n---\n');
86+
87+
// === Method 3: Using convenience wireDataCore function ===
88+
console.log('⚡ Method 3: Using wireDataCore convenience function');
89+
90+
const { ports: wirePorts, dataCore: dataCore3, factory: wireFactory } = wireDataCore(
91+
DataCore,
92+
{
93+
fileSystem: FileSystemAdapter,
94+
crypto: CryptoAdapter,
95+
process: ProcessAdapter,
96+
environment: EnvironmentAdapter
97+
},
98+
{
99+
fileSystem: { encoding: 'utf8' },
100+
crypto: { defaultAlgorithm: 'sha256' },
101+
process: { timeout: 30000 },
102+
environment: { prefix: 'DATA_' }
103+
}
104+
);
105+
106+
console.log(`✅ DataCore wired using convenience function`);
107+
console.log(`🔌 Wired ports:`, Object.keys(wirePorts));
108+
109+
console.log('\n---\n');
110+
111+
// === Method 4: Factory + Container integration ===
112+
console.log('🔄 Method 4: Factory + Container integration');
113+
114+
const integratedContainer = new DIContainer();
115+
const integratedFactory = new PortFactory();
116+
117+
// Register adapters with factory
118+
integratedFactory
119+
.registerPort('fileSystem', FileSystemAdapter, FileSystemAdapter)
120+
.registerPort('crypto', CryptoAdapter, CryptoAdapter)
121+
.registerPort('process', ProcessAdapter, ProcessAdapter)
122+
.registerPort('environment', EnvironmentAdapter, EnvironmentAdapter);
123+
124+
// Register factory-created ports with container
125+
integratedFactory.registerWithContainer(integratedContainer, {
126+
fileSystem: { encoding: 'utf8' },
127+
crypto: { defaultAlgorithm: 'sha256' },
128+
process: { timeout: 30000 },
129+
environment: { prefix: 'DATA_' }
130+
});
131+
132+
// Register DataCore
133+
integratedContainer.registerSingleton('dataCore', DataCore);
134+
135+
// Resolve everything
136+
const integratedDataCore = integratedContainer.resolve('dataCore');
137+
console.log(`✅ DataCore resolved from integrated Factory + Container`);
138+
139+
console.log('\n---\n');
140+
141+
// === Demonstrate DataCore functionality ===
142+
console.log('🚀 Testing DataCore functionality');
143+
144+
try {
145+
// Test package info
146+
const packageInfo = dataCore1.getPackageInfo();
147+
console.log(`📋 Package: ${packageInfo.name} v${packageInfo.version}`);
148+
console.log(`🔌 Port interfaces: ${packageInfo.portInterfaces.join(', ')}`);
149+
console.log(`⚙️ Core engines: ${packageInfo.coreEngines.join(', ')}`);
150+
151+
// Test sample schema creation
152+
const sampleSchema = dataCore1.createSampleSchema('demo');
153+
console.log(`📊 Sample schema created with checksum capability`);
154+
155+
console.log('\n✅ All dependency injection methods working correctly!');
156+
console.log('\n🎯 Key Benefits:');
157+
console.log(' • Automatic dependency resolution');
158+
console.log(' • Circular dependency detection');
159+
console.log(' • Singleton lifecycle management');
160+
console.log(' • Configuration injection');
161+
console.log(' • Factory pattern for reusability');
162+
console.log(' • Multiple integration approaches');
163+
164+
} catch (error) {
165+
console.error('❌ Error testing DataCore:', error.message);
166+
process.exit(1);
167+
}

packages/data-host-node/adapters/EnvironmentAdapter.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import { EnvironmentPort } from '../../data-core/ports/index.js';
2+
13
/**
24
* Node.js implementation of the Environment port.
35
* Wraps process.env and related APIs to provide standardized environment access.
46
*
57
* @class EnvironmentAdapter
68
*/
7-
export class EnvironmentAdapter {
9+
export class EnvironmentAdapter extends EnvironmentPort {
810
/**
911
* Create a new EnvironmentAdapter instance.
1012
*
@@ -14,6 +16,7 @@ export class EnvironmentAdapter {
1416
* @param {boolean} [options.caseSensitive=true] - Case sensitive variable names
1517
*/
1618
constructor(options = {}) {
19+
super();
1720
this.defaults = options.defaults || {};
1821
this.prefix = options.prefix || '';
1922
this.caseSensitive = options.caseSensitive !== false;

packages/data-host-node/adapters/FileSystemAdapter.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { promises as fs, constants } from 'fs';
22
import { dirname, resolve } from 'path';
3+
import { FileSystemPort } from '../../data-core/ports/index.js';
34

45
/**
56
* Node.js implementation of the FileSystem port.
67
* Wraps fs/promises APIs to provide standardized file system operations.
78
*
89
* @class FileSystemAdapter
910
*/
10-
export class FileSystemAdapter {
11+
export class FileSystemAdapter extends FileSystemPort {
1112
/**
1213
* Create a new FileSystemAdapter instance.
1314
*
@@ -16,6 +17,7 @@ export class FileSystemAdapter {
1617
* @param {number} [options.mode=0o644] - Default file creation mode
1718
*/
1819
constructor(options = {}) {
20+
super();
1921
this.encoding = options.encoding || 'utf8';
2022
this.defaultMode = options.mode || 0o644;
2123
}

packages/data-host-node/adapters/ProcessAdapter.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { spawn, exec } from 'child_process';
22
import { promisify } from 'util';
3+
import { ProcessPort } from '../../data-core/ports/index.js';
34

45
const execAsync = promisify(exec);
56

@@ -9,7 +10,7 @@ const execAsync = promisify(exec);
910
*
1011
* @class ProcessAdapter
1112
*/
12-
export class ProcessAdapter {
13+
export class ProcessAdapter extends ProcessPort {
1314
/**
1415
* Create a new ProcessAdapter instance.
1516
*
@@ -19,6 +20,7 @@ export class ProcessAdapter {
1920
* @param {string} [options.encoding='utf8'] - Default output encoding
2021
*/
2122
constructor(options = {}) {
23+
super();
2224
this.defaultShell = options.shell || '/bin/sh';
2325
this.defaultTimeout = options.timeout || 30000;
2426
this.encoding = options.encoding || 'utf8';

0 commit comments

Comments
 (0)