mirror of
https://github.com/dadosfera/maestro.git
synced 2026-09-20 10:24:48 +00:00
239 lines
5.9 KiB
TypeScript
239 lines
5.9 KiB
TypeScript
import { Injectable, Inject } from '@nestjs/common';
|
|
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
import {
|
|
DynamoDBDocumentClient,
|
|
GetCommand,
|
|
PutCommand,
|
|
DeleteCommand,
|
|
TranslateConfig,
|
|
} from '@aws-sdk/lib-dynamodb';
|
|
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
|
import { v4 as uuid } from 'uuid';
|
|
import { DYNAMODB_CONFIG } from './dynamodb.config';
|
|
|
|
export interface ReferenceColumn {
|
|
name: string;
|
|
type: string;
|
|
}
|
|
|
|
export interface InputDocument {
|
|
id: string;
|
|
client_id: string;
|
|
user_id: string;
|
|
created_at: string;
|
|
name: string;
|
|
description?: string;
|
|
plugin: string;
|
|
type: string;
|
|
tables?: Array<{
|
|
name: string;
|
|
type: string;
|
|
columns?: string[];
|
|
reference_column?: ReferenceColumn;
|
|
}>;
|
|
credentials?: Record<string, any>;
|
|
}
|
|
|
|
@Injectable()
|
|
export class DynamoDBService {
|
|
private documentClient: DynamoDBDocumentClient;
|
|
private logger: any;
|
|
|
|
constructor(
|
|
@Inject(DadosferaLogger) dadosferaLogger: DadosferaLogger,
|
|
) {
|
|
this.logger = dadosferaLogger.logger;
|
|
|
|
const dynamoConfig = { region: DYNAMODB_CONFIG.region() };
|
|
const marshallOptions: TranslateConfig = {
|
|
marshallOptions: {
|
|
removeUndefinedValues: true,
|
|
},
|
|
};
|
|
|
|
const dynamoDb = new DynamoDBClient(dynamoConfig);
|
|
this.documentClient = DynamoDBDocumentClient.from(dynamoDb, marshallOptions);
|
|
}
|
|
|
|
async createInput(
|
|
clientId: string,
|
|
userId: string,
|
|
data: {
|
|
name: string;
|
|
description?: string;
|
|
plugin: string;
|
|
type: string;
|
|
tables?: Array<{
|
|
name: string;
|
|
type: string;
|
|
columns?: string[];
|
|
reference_column?: ReferenceColumn;
|
|
}>;
|
|
},
|
|
): Promise<InputDocument> {
|
|
const tableName = DYNAMODB_CONFIG.inputsTable();
|
|
const id = uuid();
|
|
const created_at = new Date().toISOString();
|
|
|
|
const item: InputDocument = {
|
|
id,
|
|
client_id: clientId,
|
|
user_id: userId,
|
|
created_at,
|
|
name: data.name,
|
|
description: data.description,
|
|
plugin: data.plugin,
|
|
type: data.type,
|
|
tables: data.tables,
|
|
};
|
|
|
|
this.logger.info('DynamoDB: Creating input', {
|
|
tableName,
|
|
inputId: id,
|
|
plugin: data.plugin,
|
|
});
|
|
|
|
const putCommand = new PutCommand({
|
|
TableName: tableName,
|
|
Item: item,
|
|
});
|
|
|
|
try {
|
|
await this.documentClient.send(putCommand);
|
|
this.logger.info('DynamoDB: Input created successfully', { inputId: id });
|
|
return item;
|
|
} catch (error) {
|
|
this.logger.error('DynamoDB: Failed to create input', {
|
|
tableName,
|
|
inputId: id,
|
|
region: DYNAMODB_CONFIG.region(),
|
|
error: error.message,
|
|
errorName: error.name,
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async findInput(clientId: string, inputId: string): Promise<InputDocument | null> {
|
|
const tableName = DYNAMODB_CONFIG.inputsTable();
|
|
|
|
const getCommand = new GetCommand({
|
|
TableName: tableName,
|
|
Key: {
|
|
id: inputId,
|
|
client_id: clientId,
|
|
},
|
|
});
|
|
|
|
try {
|
|
const { Item } = await this.documentClient.send(getCommand);
|
|
return Item as InputDocument | null;
|
|
} catch (error) {
|
|
this.logger.error('DynamoDB: findInput failed', { inputId, clientId, error: error.message });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async deleteInput(clientId: string, inputId: string): Promise<void> {
|
|
const tableName = DYNAMODB_CONFIG.inputsTable();
|
|
|
|
this.logger.info('DynamoDB: Deleting input', {
|
|
tableName,
|
|
inputId,
|
|
});
|
|
|
|
const deleteCommand = new DeleteCommand({
|
|
TableName: tableName,
|
|
Key: {
|
|
id: inputId,
|
|
client_id: clientId,
|
|
},
|
|
});
|
|
|
|
await this.documentClient.send(deleteCommand);
|
|
|
|
this.logger.info('DynamoDB: Input deleted successfully', { inputId });
|
|
}
|
|
|
|
/**
|
|
* Update a specific table entry in the input document.
|
|
* Fetches the current document, updates the matching table, and saves.
|
|
*/
|
|
async updateInputTable(
|
|
clientId: string,
|
|
inputId: string,
|
|
tableName: string,
|
|
changes: {
|
|
type?: string;
|
|
columns?: string[];
|
|
reference_column?: ReferenceColumn | null;
|
|
},
|
|
): Promise<void> {
|
|
const dynamoTableName = DYNAMODB_CONFIG.inputsTable();
|
|
|
|
this.logger.info('DynamoDB: Updating input table', {
|
|
inputId,
|
|
tableName,
|
|
changes: Object.keys(changes),
|
|
});
|
|
|
|
// Get current document
|
|
const current = await this.findInput(clientId, inputId);
|
|
if (!current) {
|
|
this.logger.warn('DynamoDB: Input not found for update', { inputId });
|
|
return;
|
|
}
|
|
|
|
// Find and update the matching table
|
|
const tables = current.tables || [];
|
|
const tableIndex = tables.findIndex((t) => t.name === tableName);
|
|
|
|
if (tableIndex === -1) {
|
|
this.logger.warn('DynamoDB: Table not found in input', {
|
|
inputId,
|
|
tableName,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Merge changes into the table entry
|
|
const updatedTable = { ...tables[tableIndex] };
|
|
if ('type' in changes) updatedTable.type = changes.type;
|
|
if ('columns' in changes) updatedTable.columns = changes.columns;
|
|
if ('reference_column' in changes) {
|
|
if (changes.reference_column === null) {
|
|
delete updatedTable.reference_column;
|
|
} else {
|
|
updatedTable.reference_column = changes.reference_column;
|
|
}
|
|
}
|
|
tables[tableIndex] = updatedTable;
|
|
|
|
// Save updated document
|
|
const putCommand = new PutCommand({
|
|
TableName: dynamoTableName,
|
|
Item: {
|
|
...current,
|
|
tables,
|
|
updated_at: new Date().toISOString(),
|
|
},
|
|
});
|
|
|
|
try {
|
|
await this.documentClient.send(putCommand);
|
|
this.logger.info('DynamoDB: Input table updated successfully', {
|
|
inputId,
|
|
tableName,
|
|
});
|
|
} catch (error) {
|
|
this.logger.error('DynamoDB: Failed to update input table', {
|
|
inputId,
|
|
tableName,
|
|
error: error.message,
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
}
|