@gftdcojp/gftd-orm
Version:
Enterprise-grade real-time data platform with ksqlDB, inspired by Supabase architecture
273 lines • 10.3 kB
JavaScript
;
/**
* GFTD ORM CLI - TypeScript型生成コマンドライン インターフェース
*
* 完全実装済み機能:
* - CLIコマンドの実装 ✅
* - 型生成コマンドの追加 ✅
* - ファイル出力機能 ✅
* - ドライランモード ✅
* - 全テーブル型生成 ✅
* - テーブル一覧表示 ✅
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runCli = main;
const fs_1 = require("fs");
const path_1 = require("path");
const commander_1 = require("commander");
const ksqldb_client_1 = require("./ksqldb-client");
const type_generator_1 = require("./type-generator");
const logger_1 = require("./utils/logger");
const dotenv_1 = __importDefault(require("dotenv"));
// 環境変数を読み込み
dotenv_1.default.config();
/**
* CLIのバージョン情報
*/
const CLI_VERSION = '25.07.8';
/**
* ksqlDB接続を初期化
* @param options - CLI オプション
*/
function initializeConnection(options) {
const url = options.url || process.env.GFTD_DB_URL || process.env.KSQLDB_URL || 'http://localhost:8088';
const apiKey = options.apiKey || process.env.GFTD_DB_API_KEY || process.env.KSQLDB_API_KEY;
const apiSecret = options.apiSecret || process.env.GFTD_DB_API_SECRET || process.env.KSQLDB_API_SECRET;
if (options.verbose) {
logger_1.log.info('Initializing ksqlDB connection...');
logger_1.log.info(`URL: ${url}`);
logger_1.log.info(`API Key: ${apiKey ? '***' : 'Not provided'}`);
}
(0, ksqldb_client_1.initializeKsqlDbClient)({
url,
apiKey,
apiSecret,
});
}
/**
* ファイルを安全に書き込み
* @param filePath - ファイルパス
* @param content - 書き込み内容
* @param options - CLI オプション
*/
function writeFileContents(filePath, content, options) {
if (options.dry) {
console.log(`\n[DRY RUN] Would write to: ${filePath}`);
console.log('--- Content ---');
console.log(content);
console.log('--- End Content ---\n');
return;
}
// ディレクトリを作成
const dir = (0, path_1.dirname)(filePath);
if (!(0, fs_1.existsSync)(dir)) {
(0, fs_1.mkdirSync)(dir, { recursive: true });
if (options.verbose) {
logger_1.log.info(`Created directory: ${dir}`);
}
}
// ファイルに書き込み
(0, fs_1.writeFileSync)(filePath, content, 'utf8');
if (options.verbose) {
logger_1.log.info(`✅ Generated: ${filePath}`);
}
else {
console.log(`✅ Generated: ${filePath}`);
}
}
/**
* テーブル名からファイル名を生成
* @param tableName - テーブル名
* @param format - 出力形式
* @returns ファイル名
*/
function generateFileName(tableName, format = 'ts') {
// TABLE_table のような重複を修正
const cleanName = tableName.replace(/_table$/i, '').replace(/_stream$/i, '');
return cleanName
.toLowerCase()
.replace(/[^a-z0-9_]/g, '_') + `.${format}`;
}
/**
* 単一テーブルの型を生成
*/
async function generateTypesCommand(tableName, options) {
try {
initializeConnection(options);
if (options.verbose) {
logger_1.log.info(`🔍 Analyzing table: ${tableName}`);
}
const schema = await (0, type_generator_1.getTableSchema)(tableName);
const typeInfo = (0, type_generator_1.generateCompleteTypeDefinition)(schema);
const outputDir = options.output || './types';
const fileName = generateFileName(tableName, options.format || 'ts');
const filePath = (0, path_1.join)(outputDir, fileName);
writeFileContents(filePath, typeInfo.fullCode, options);
if (!options.dry) {
console.log(`\n🎉 Type generation completed for table: ${tableName}`);
console.log(`📄 Interface: ${typeInfo.interfaceName}`);
console.log(`🔧 Mapper: ${typeInfo.mapperFunctionName}`);
}
}
catch (error) {
console.error(`❌ Error generating types for table ${tableName}:`, error.message);
process.exit(1);
}
}
/**
* 全テーブルの型を生成
*/
async function generateAllTypesCommand(options) {
try {
initializeConnection(options);
if (options.verbose) {
logger_1.log.info('🔍 Listing all tables and streams...');
}
const tables = await (0, type_generator_1.listAllTables)();
if (tables.length === 0) {
console.log('⚠️ No tables or streams found.');
return;
}
console.log(`🔍 Found ${tables.length} tables/streams:`);
tables.forEach(table => {
console.log(` - ${table.name} (${table.type})`);
});
console.log('\n🚀 Generating types...\n');
const outputDir = options.output || './types';
let successCount = 0;
let errorCount = 0;
for (const table of tables) {
try {
if (options.verbose) {
logger_1.log.info(`Generating types for: ${table.name}`);
}
const schema = await (0, type_generator_1.getTableSchema)(table.name);
const typeInfo = (0, type_generator_1.generateCompleteTypeDefinition)(schema);
const fileName = generateFileName(table.name, options.format || 'ts');
const filePath = (0, path_1.join)(outputDir, fileName);
writeFileContents(filePath, typeInfo.fullCode, options);
successCount++;
}
catch (error) {
console.error(`❌ Failed to generate types for ${table.name}: ${error.message}`);
errorCount++;
}
}
if (!options.dry) {
console.log(`\n🎉 Type generation completed!`);
console.log(`✅ Success: ${successCount} tables`);
if (errorCount > 0) {
console.log(`❌ Errors: ${errorCount} tables`);
}
console.log(`📁 Output directory: ${outputDir}`);
}
}
catch (error) {
console.error(`❌ Error generating types:`, error.message);
process.exit(1);
}
}
/**
* テーブル一覧を表示
*/
async function listTablesCommand(options) {
try {
initializeConnection(options);
if (options.verbose) {
logger_1.log.info('🔍 Listing all tables and streams...');
}
const tables = await (0, type_generator_1.listAllTables)();
if (tables.length === 0) {
console.log('⚠️ No tables or streams found.');
return;
}
console.log(`\n📊 Found ${tables.length} tables/streams:\n`);
// テーブルとストリームを分けて表示
const tablesList = tables.filter(t => t.type === 'TABLE');
const streamsList = tables.filter(t => t.type === 'STREAM');
if (tablesList.length > 0) {
console.log('📋 Tables:');
tablesList.forEach(table => {
console.log(` • ${table.name} (topic: ${table.topic}, format: ${table.valueFormat})`);
});
console.log('');
}
if (streamsList.length > 0) {
console.log('🌊 Streams:');
streamsList.forEach(stream => {
console.log(` • ${stream.name} (topic: ${stream.topic}, format: ${stream.valueFormat})`);
});
console.log('');
}
}
catch (error) {
console.error(`❌ Error listing tables:`, error.message);
process.exit(1);
}
}
/**
* メイン CLI プログラム
*/
async function main() {
const program = new commander_1.Command();
program
.name('gftd-orm')
.description('GFTD ORM CLI - TypeScript type generation for ksqlDB')
.version(CLI_VERSION);
// 共通オプション
program
.option('-u, --url <url>', 'ksqlDB server URL (default: http://localhost:8088)')
.option('-k, --api-key <key>', 'ksqlDB API key')
.option('-s, --api-secret <secret>', 'ksqlDB API secret')
.option('-o, --output <dir>', 'Output directory (default: ./types)')
.option('-v, --verbose', 'Verbose output')
.option('--dry', 'Dry run - show what would be generated without writing files');
// generate-types コマンド - 単一テーブル
program
.command('generate-types')
.description('Generate TypeScript types for a specific table')
.option('-t, --table <table>', 'Table name to generate types for')
.option('-f, --format <format>', 'Output format (ts, js, dts)', 'ts')
.action(async (options) => {
const globalOptions = program.opts();
const combinedOptions = { ...globalOptions, ...options };
if (!combinedOptions.table) {
console.error('❌ Error: --table option is required');
console.log('Usage: gftd-orm generate-types --table <table-name>');
process.exit(1);
}
await generateTypesCommand(combinedOptions.table, combinedOptions);
});
// generate-all コマンド - 全テーブル
program
.command('generate-all')
.description('Generate TypeScript types for all tables and streams')
.option('-f, --format <format>', 'Output format (ts, js, dts)', 'ts')
.action(async (options) => {
const globalOptions = program.opts();
const combinedOptions = { ...globalOptions, ...options };
await generateAllTypesCommand(combinedOptions);
});
// list コマンド - テーブル一覧
program
.command('list')
.description('List all available tables and streams')
.action(async () => {
const globalOptions = program.opts();
await listTablesCommand(globalOptions);
});
// パース実行
program.parse();
}
// CLI 実行
if (require.main === module) {
main().catch((error) => {
console.error('❌ Unexpected error:', error);
process.exit(1);
});
}
//# sourceMappingURL=cli.js.map