Appearance
RuoYi DynamoDB - Node.js Implementation
Below is a Node.js implementation for the DynamoDB data models and operations previously defined in Go.
Models and Repositories
javascript
const AWS = require('aws-sdk');
const { v4: uuidv4 } = require('uuid');
// Configure AWS SDK
const dynamoDB = new AWS.DynamoDB.DocumentClient({
region: 'your-region',
// Add other configurations as needed
});
const TABLE_NAME = 'AccountManagement';
// ===================== Models =====================
/**
* Client (Tenant) Entity
*/
class Client {
constructor(data = {}) {
this.PK = data.PK || `CLIENT#${data.id || ''}`;
this.SK = 'METADATA';
this.id = data.id || uuidv4();
this.name = data.name || '';
this.description = data.description || '';
this.status = data.status || 'active';
this.created_at = data.created_at || new Date().toISOString();
this.created_by = data.created_by || '';
this.updated_at = data.updated_at || new Date().toISOString();
this.Type = 'CLIENT';
this.GSI1PK = this.PK;
this.GSI1SK = this.PK;
this.GSI4PK = this.PK;
this.GSI4SK = `CLIENT#${this.created_at}`;
}
static fromItem(item) {
return item ? new Client(item) : null;
}
toItem() {
return {
...this,
PK: `CLIENT#${this.id}`,
GSI1PK: `CLIENT#${this.id}`,
GSI1SK: `CLIENT#${this.id}`,
GSI4PK: `CLIENT#${this.id}`,
GSI4SK: `CLIENT#${this.created_at}`,
};
}
}
/**
* Project Entity
*/
class Project {
constructor(data = {}) {
this.PK = data.PK || `CLIENT#${data.client_id || ''}`;
this.SK = data.SK || `PROJECT#${data.id || ''}`;
this.id = data.id || uuidv4();
this.name = data.name || '';
this.client_id = data.client_id || '';
this.description = data.description || '';
this.status = data.status || 'active';
this.created_at = data.created_at || new Date().toISOString();
this.created_by = data.created_by || '';
this.updated_at = data.updated_at || new Date().toISOString();
this.Type = 'PROJECT';
this.GSI1PK = data.GSI1PK || this.PK;
this.GSI1SK = data.GSI1SK || this.SK;
this.GSI4PK = data.GSI4PK || this.PK;
this.GSI4SK = data.GSI4SK || `PROJECT#${this.created_at}`;
}
static fromItem(item) {
return item ? new Project(item) : null;
}
toItem() {
return {
...this,
PK: `CLIENT#${this.client_id}`,
SK: `PROJECT#${this.id}`,
GSI1PK: `CLIENT#${this.client_id}`,
GSI1SK: `PROJECT#${this.id}`,
GSI4PK: `CLIENT#${this.client_id}`,
GSI4SK: `PROJECT#${this.created_at}`,
};
}
}
/**
* Building Entity
*/
class Building {
constructor(data = {}) {
this.PK = data.PK || `PROJECT#${data.project_id || ''}`;
this.SK = data.SK || `BUILDING#${data.id || ''}`;
this.id = data.id || uuidv4();
this.name = data.name || '';
this.project_id = data.project_id || '';
this.client_id = data.client_id || '';
this.address = data.address || '';
this.description = data.description || '';
this.created_at = data.created_at || new Date().toISOString();
this.created_by = data.created_by || '';
this.updated_at = data.updated_at || new Date().toISOString();
this.Type = 'BUILDING';
this.GSI1PK = data.GSI1PK || `CLIENT#${this.client_id}`;
this.GSI1SK = data.GSI1SK || this.SK;
this.GSI4PK = data.GSI4PK || `CLIENT#${this.client_id}`;
this.GSI4SK = data.GSI4SK || `BUILDING#${this.created_at}`;
}
static fromItem(item) {
return item ? new Building(item) : null;
}
toItem() {
return {
...this,
PK: `PROJECT#${this.project_id}`,
SK: `BUILDING#${this.id}`,
GSI1PK: `CLIENT#${this.client_id}`,
GSI1SK: `BUILDING#${this.id}`,
GSI4PK: `CLIENT#${this.client_id}`,
GSI4SK: `BUILDING#${this.created_at}`,
};
}
}
/**
* Role Entity
*/
class Role {
constructor(data = {}) {
this.PK = data.PK || `CLIENT#${data.client_id || ''}`;
this.SK = data.SK || `ROLE#${data.id || ''}`;
this.id = data.id || uuidv4();
this.name = data.name || '';
this.is_system = data.is_system || 'false';
this.description = data.description || '';
this.permissions = data.permissions || '[]';
this.created_at = data.created_at || new Date().toISOString();
this.created_by = data.created_by || '';
this.updated_at = data.updated_at || new Date().toISOString();
this.Type = 'ROLE';
this.GSI1PK = data.GSI1PK || this.PK;
this.GSI1SK = data.GSI1SK || this.SK;
this.GSI4PK = data.GSI4PK || this.PK;
this.GSI4SK = data.GSI4SK || `ROLE#${this.created_at}`;
}
static fromItem(item) {
return item ? new Role(item) : null;
}
toItem() {
return {
...this,
PK: `CLIENT#${this.client_id}`,
SK: `ROLE#${this.id}`,
GSI1PK: `CLIENT#${this.client_id}`,
GSI1SK: `ROLE#${this.id}`,
GSI4PK: `CLIENT#${this.client_id}`,
GSI4SK: `ROLE#${this.created_at}`,
};
}
// Parse stored JSON permissions string to array
getPermissionsArray() {
try {
return JSON.parse(this.permissions || '[]');
} catch (error) {
console.error('Failed to parse permissions:', error);
return [];
}
}
}
/**
* Menu Entity
*/
class Menu {
constructor(data = {}) {
this.PK = data.PK || `CLIENT#${data.client_id || ''}`;
this.SK = data.SK || `MENU#${data.menu_id || ''}`;
this.Type = 'MENU';
this.menu_id = data.menu_id || uuidv4();
this.menu_name = data.menu_name || '';
this.parent_id = data.parent_id || '0';
this.order_num = data.order_num || 0;
this.path = data.path || '';
this.component = data.component || '';
this.query_param = data.query_param || '';
this.is_frame = data.is_frame || 0;
this.is_cache = data.is_cache || 0;
this.menu_type = data.menu_type || 'M';
this.visible = data.visible || '0';
this.status = data.status || '0';
this.permissions = data.permissions || '';
this.perms = data.perms || '';
this.icon = data.icon || '';
this.create_dept = data.create_dept || '';
this.create_by = data.create_by || '';
this.create_time = data.create_time || new Date().toISOString();
this.update_by = data.update_by || '';
this.update_time = data.update_time || new Date().toISOString();
this.remark = data.remark || '';
this.GSI1PK = data.GSI1PK || this.PK;
this.GSI1SK = data.GSI1SK || this.SK;
this.GSI2PK = data.GSI2PK || `MENU#${this.parent_id}`;
this.GSI2SK = data.GSI2SK || `MENU#${this.menu_id}`;
}
static fromItem(item) {
return item ? new Menu(item) : null;
}
toItem() {
return {
...this,
PK: `CLIENT#${this.client_id}`,
SK: `MENU#${this.menu_id}`,
GSI1PK: `CLIENT#${this.client_id}`,
GSI1SK: `MENU#${this.menu_id}`,
GSI2PK: `MENU#${this.parent_id}`,
GSI2SK: `MENU#${this.menu_id}`,
};
}
}
// ===================== Repositories =====================
/**
* Client Repository
*/
class ClientRepository {
/**
* Get client by ID
* @param {string} clientId - The client ID
* @returns {Promise<Client|null>} The client or null
*/
async getById(clientId) {
const params = {
TableName: TABLE_NAME,
Key: {
PK: `CLIENT#${clientId}`,
SK: 'METADATA'
}
};
try {
const result = await dynamoDB.get(params).promise();
return Client.fromItem(result.Item);
} catch (error) {
console.error('Error getting client by ID:', error);
throw error;
}
}
/**
* Get all clients
* @returns {Promise<Client[]>} Array of clients
*/
async getAll() {
const params = {
TableName: TABLE_NAME,
FilterExpression: 'begins_with(PK, :pk) AND SK = :sk',
ExpressionAttributeValues: {
':pk': 'CLIENT#',
':sk': 'METADATA'
}
};
try {
const result = await dynamoDB.scan(params).promise();
return result.Items.map(item => Client.fromItem(item));
} catch (error) {
console.error('Error getting all clients:', error);
throw error;
}
}
/**
* Get clients by status
* @param {string} status - The status to filter by
* @returns {Promise<Client[]>} Array of clients with the given status
*/
async getByStatus(status) {
const params = {
TableName: TABLE_NAME,
FilterExpression: 'begins_with(PK, :pk) AND SK = :sk AND #status = :status',
ExpressionAttributeNames: {
'#status': 'status'
},
ExpressionAttributeValues: {
':pk': 'CLIENT#',
':sk': 'METADATA',
':status': status
}
};
try {
const result = await dynamoDB.scan(params).promise();
return result.Items.map(item => Client.fromItem(item));
} catch (error) {
console.error(`Error getting clients with status ${status}:`, error);
throw error;
}
}
/**
* Save client
* @param {Client} client - The client to save
* @returns {Promise<Client>} The saved client
*/
async save(client) {
if (!client.id) {
client.id = uuidv4();
}
const now = new Date().toISOString();
if (!client.created_at) {
client.created_at = now;
}
client.updated_at = now;
const item = client.toItem();
const params = {
TableName: TABLE_NAME,
Item: item
};
try {
await dynamoDB.put(params).promise();
return client;
} catch (error) {
console.error('Error saving client:', error);
throw error;
}
}
/**
* Delete client (soft delete)
* @param {string} clientId - The client ID to delete
* @returns {Promise<void>}
*/
async delete(clientId) {
const params = {
TableName: TABLE_NAME,
Key: {
PK: `CLIENT#${clientId}`,
SK: 'METADATA'
},
UpdateExpression: 'SET #status = :status, updated_at = :updatedAt',
ExpressionAttributeNames: {
'#status': 'status'
},
ExpressionAttributeValues: {
':status': 'deleted',
':updatedAt': new Date().toISOString()
}
};
try {
await dynamoDB.update(params).promise();
} catch (error) {
console.error('Error deleting client:', error);
throw error;
}
}
}
/**
* Project Repository
*/
class ProjectRepository {
/**
* Get project by ID
* @param {string} clientId - The client ID
* @param {string} projectId - The project ID
* @returns {Promise<Project|null>} The project or null
*/
async getById(clientId, projectId) {
const params = {
TableName: TABLE_NAME,
Key: {
PK: `CLIENT#${clientId}`,
SK: `PROJECT#${projectId}`
}
};
try {
const result = await dynamoDB.get(params).promise();
return Project.fromItem(result.Item);
} catch (error) {
console.error('Error getting project by ID:', error);
throw error;
}
}
/**
* Get all projects for a client
* @param {string} clientId - The client ID
* @returns {Promise<Project[]>} Array of projects
*/
async getByClientId(clientId) {
const params = {
TableName: TABLE_NAME,
KeyConditionExpression: 'PK = :pk AND begins_with(SK, :sk)',
ExpressionAttributeValues: {
':pk': `CLIENT#${clientId}`,
':sk': 'PROJECT#'
}
};
try {
const result = await dynamoDB.query(params).promise();
return result.Items.map(item => Project.fromItem(item));
} catch (error) {
console.error(`Error getting projects for client ${clientId}:`, error);
throw error;
}
}
/**
* Save project
* @param {Project} project - The project to save
* @returns {Promise<Project>} The saved project
*/
async save(project) {
if (!project.id) {
project.id = uuidv4();
}
const now = new Date().toISOString();
if (!project.created_at) {
project.created_at = now;
}
project.updated_at = now;
const item = project.toItem();
const params = {
TableName: TABLE_NAME,
Item: item
};
try {
await dynamoDB.put(params).promise();
return project;
} catch (error) {
console.error('Error saving project:', error);
throw error;
}
}
/**
* Delete project (soft delete)
* @param {string} clientId - The client ID
* @param {string} projectId - The project ID to delete
* @returns {Promise<void>}
*/
async delete(clientId, projectId) {
const params = {
TableName: TABLE_NAME,
Key: {
PK: `CLIENT#${clientId}`,
SK: `PROJECT#${projectId}`
},
UpdateExpression: 'SET #status = :status, updated_at = :updatedAt',
ExpressionAttributeNames: {
'#status': 'status'
},
ExpressionAttributeValues: {
':status': 'deleted',
':updatedAt': new Date().toISOString()
}
};
try {
await dynamoDB.update(params).promise();
} catch (error) {
console.error('Error deleting project:', error);
throw error;
}
}
}
/**
* Role Repository
*/
class RoleRepository {
/**
* Get role by ID
* @param {string} clientId - The client ID
* @param {string} roleId - The role ID
* @returns {Promise<Role|null>} The role or null
*/
async getById(clientId, roleId) {
const params = {
TableName: TABLE_NAME,
Key: {
PK: `CLIENT#${clientId}`,
SK: `ROLE#${roleId}`
}
};
try {
const result = await dynamoDB.get(params).promise();
return Role.fromItem(result.Item);
} catch (error) {
console.error('Error getting role by ID:', error);
throw error;
}
}
/**
* Get all roles for a client
* @param {string} clientId - The client ID
* @returns {Promise<Role[]>} Array of roles
*/
async getByClientId(clientId) {
const params = {
TableName: TABLE_NAME,
KeyConditionExpression: 'PK = :pk AND begins_with(SK, :sk)',
ExpressionAttributeValues: {
':pk': `CLIENT#${clientId}`,
':sk': 'ROLE#'
}
};
try {
const result = await dynamoDB.query(params).promise();
return result.Items.map(item => Role.fromItem(item));
} catch (error) {
console.error(`Error getting roles for client ${clientId}:`, error);
throw error;
}
}
/**
* Get system roles
* @param {string} clientId - The client ID
* @returns {Promise<Role[]>} Array of system roles
*/
async getSystemRoles(clientId) {
const params = {
TableName: TABLE_NAME,
KeyConditionExpression: 'PK = :pk AND begins_with(SK, :sk)',
FilterExpression: 'is_system = :isSystem',
ExpressionAttributeValues: {
':pk': `CLIENT#${clientId}`,
':sk': 'ROLE#',
':isSystem': 'true'
}
};
try {
const result = await dynamoDB.query(params).promise();
return result.Items.map(item => Role.fromItem(item));
} catch (error) {
console.error(`Error getting system roles for client ${clientId}:`, error);
throw error;
}
}
/**
* Save role
* @param {Role} role - The role to save
* @returns {Promise<Role>} The saved role
*/
async save(role) {
if (!role.id) {
role.id = uuidv4();
}
const now = new Date().toISOString();
if (!role.created_at) {
role.created_at = now;
}
role.updated_at = now;
// Ensure permissions is a string (JSON)
if (typeof role.permissions === 'object') {
role.permissions = JSON.stringify(role.permissions);
}
const item = role.toItem();
const params = {
TableName: TABLE_NAME,
Item: item
};
try {
await dynamoDB.put(params).promise();
return role;
} catch (error) {
console.error('Error saving role:', error);
throw error;
}
}
/**
* Delete role (soft delete)
* @param {string} clientId - The client ID
* @param {string} roleId - The role ID to delete
* @returns {Promise<void>}
*/
async delete(clientId, roleId) {
const params = {
TableName: TABLE_NAME,
Key: {
PK: `CLIENT#${clientId}`,
SK: `ROLE#${roleId}`
},
UpdateExpression: 'SET #status = :status, updated_at = :updatedAt',
ExpressionAttributeNames: {
'#status': 'status'
},
ExpressionAttributeValues: {
':status': 'deleted',
':updatedAt': new Date().toISOString()
}
};
try {
await dynamoDB.update(params).promise();
} catch (error) {
console.error('Error deleting role:', error);
throw error;
}
}
}
/**
* Menu Repository
*/
class MenuRepository {
/**
* Get menu by ID
* @param {string} clientId - The client ID
* @param {string} menuId - The menu ID
* @returns {Promise<Menu|null>} The menu or null
*/
async getById(clientId, menuId) {
const params = {
TableName: TABLE_NAME,
Key: {
PK: `CLIENT#${clientId}`,
SK: `MENU#${menuId}`
}
};
try {
const result = await dynamoDB.get(params).promise();
return Menu.fromItem(result.Item);
} catch (error) {
console.error('Error getting menu by ID:', error);
throw error;
}
}
/**
* Get all menus for a client
* @param {string} clientId - The client ID
* @returns {Promise<Menu[]>} Array of menus
*/
async getByClientId(clientId) {
const params = {
TableName: TABLE_NAME,
KeyConditionExpression: 'PK = :pk AND begins_with(SK, :sk)',
ExpressionAttributeValues: {
':pk': `CLIENT#${clientId}`,
':sk': 'MENU#'
}
};
try {
const result = await dynamoDB.query(params).promise();
return result.Items.map(item => Menu.fromItem(item));
} catch (error) {
console.error(`Error getting menus for client ${clientId}:`, error);
throw error;
}
}
/**
* Get menus by parent ID using GSI2
* @param {string} clientId - The client ID
* @param {string} parentId - The parent menu ID
* @returns {Promise<Menu[]>} Array of child menus
*/
async getByParentId(parentId) {
const params = {
TableName: TABLE_NAME,
IndexName: 'GSI2',
KeyConditionExpression: 'GSI2PK = :pk',
ExpressionAttributeValues: {
':pk': `MENU#${parentId}`
}
};
try {
const result = await dynamoDB.query(params).promise();
return result.Items.map(item => Menu.fromItem(item));
} catch (error) {
console.error(`Error getting menus with parent ID ${parentId}:`, error);
throw error;
}
}
/**
* Get menus by type
* @param {string} clientId - The client ID
* @param {string} menuType - The menu type (M, C, F)
* @returns {Promise<Menu[]>} Array of menus of the specified type
*/
async getByType(clientId, menuType) {
const params = {
TableName: TABLE_NAME,
KeyConditionExpression: 'PK = :pk AND begins_with(SK, :sk)',
FilterExpression: 'menu_type = :menuType',
ExpressionAttributeValues: {
':pk': `CLIENT#${clientId}`,
':sk': 'MENU#',
':menuType': menuType
}
};
try {
const result = await dynamoDB.query(params).promise();
return result.Items.map(item => Menu.fromItem(item));
} catch (error) {
console.error(`Error getting menus of type ${menuType}:`, error);
throw error;
}
}
/**
* Save menu
* @param {Menu} menu - The menu to save
* @returns {Promise<Menu>} The saved menu
*/
async save(menu) {
if (!menu.menu_id) {
menu.menu_id = uuidv4();
}
const now = new Date().toISOString();
if (!menu.create_time) {
menu.create_time = now;
}
menu.update_time = now;
const item = menu.toItem();
const params = {
TableName: TABLE_NAME,
Item: item
};
try {
await dynamoDB.put(params).promise();
return menu;
} catch (error) {
console.error('Error saving menu:', error);
throw error;
}
}
/**
* Delete menu (soft delete)
* @param {string} clientId - The client ID
* @param {string} menuId - The menu ID to delete
* @returns {Promise<void>}
*/
async delete(clientId, menuId) {
const params = {
TableName: TABLE_NAME,
Key: {
PK: `CLIENT#${clientId}`,
SK: `MENU#${menuId}`
},
UpdateExpression: 'SET #status = :status, update_time = :updateTime',
ExpressionAttributeNames: {
'#status': 'status'
},
ExpressionAttributeValues: {
':status': '1', // 1 = disabled in RuoYi
':updateTime': new Date().toISOString()
}
};
try {
await dynamoDB.update(params).promise();
} catch (error) {
console.error('Error deleting menu:', error);
throw error;
}
}
}
// ===================== Utility Functions =====================
/**
* Build menu tree from flat menu array
* @param {Menu[]} menus - Array of menus
* @param {string} parentId - Parent ID to start from (usually '0')
* @returns {Object[]} Tree of menu nodes
*/
function buildMenuTree(menus, parentId = '0') {
const nodes = [];
for (const menu of menus) {
if (menu.parent_id === parentId) {
const node = {
menu,
children: buildMenuTree(menus, menu.menu_id)
};
nodes.push(node);
}
}
// Sort by order_num
return nodes.sort((a, b) => a.menu.order_num - b.menu.order_num);
}
/**
* Get user roles and permissions
* @param {string} userId - The user ID
* @param {string} clientId - The client ID
* @returns {Promise<Object>} Object containing roles and permissions
*/
async function getUserRolesAndPermissions(userId, clientId) {
// This function assumes you have a UserRoleRepository and RoleRepository
const userRoleRepo = new UserRoleRepository();
const roleRepo = new RoleRepository();
try {
// Get user roles
const userRoles = await userRoleRepo.getByUserId(userId);
// Get role details and extract permissions
const roles = [];
const allPermissions = new Set();
for (const userRole of userRoles) {
const role = await roleRepo.getById(clientId, userRole.role_id);
if (role) {
roles.push(role);
// Extract permissions from role
const permissions = role.getPermissionsArray();
for (const perm of permissions) {
if (perm.action && perm.resource) {
allPermissions.add(`${perm.action}:${perm.resource}`);
}
}
}
}
return {
roles,
permissions: Array.from(allPermissions)
};
} catch (error) {
console.error('Error getting user roles and permissions:', error);
throw error;
}
}
/**
* Check if user has a specific permission
* @param {string[]} permissions - User's permission array
* @param {string} requiredPermission - Permission to check
* @returns {boolean} True if user has permission
*/
function hasPermission(permissions, requiredPermission) {
// Check for exact match or wildcard permissions
if (permissions.includes(requiredPermission) || permissions.includes('*:*')) {
return true;
}
// Check for wildcard permissions (e.g., "system:*")
for (const perm of permissions) {
if (perm.includes('*')) {
const pattern = perm.replace(/\*/g, '.*');
const regex = new RegExp(`^${pattern}$`);
if (regex.test(requiredPermission)) {
return true;
}
}
}
return false;
}
// ===================== Example Usage =====================
/**
* Example: Create a new client
*/
async function createClient() {
const clientRepo = new ClientRepository();
const client = new Client({
name: 'Test Client',
description: 'This is a test client',
created_by: 'admin'
});
try {
const savedClient = await clientRepo.save(client);
console.log('Client created:', savedClient);
return savedClient;
} catch (error) {
console.error('Failed to create client:', error);
throw error;
}
}
/**
* Example: Create a project for a client
*/
async function createProject(clientId) {
const projectRepo = new ProjectRepository();
const project = new Project({
name: 'Test Project',
client_id: clientId,
description: 'This is a test project',
created_by: 'admin'
});
try {
const savedProject = await projectRepo.save(project);
console.log('Project created:', savedProject);
return savedProject;
} catch (error) {
console.error('Failed to create project:', error);
throw error;
}
}
/**
* Example: Get client menu tree
*/
async function getClientMenuTree(clientId) {
const menuRepo = new MenuRepository();
try {
const menus = await menuRepo.getByClientId(clientId);
const menuTree = buildMenuTree(menus);
console.log('Menu tree:', JSON.stringify(menuTree, null, 2));
return menuTree;
} catch (error) {
console.error('Failed to get menu tree:', error);
throw error;
}
}
module.exports = {
// Models
Client,
Project,
Building,
Role,
Menu,
// Repositories
ClientRepository,
ProjectRepository,
RoleRepository,
MenuRepository,
// Utility functions
buildMenuTree,
getUserRolesAndPermissions,
hasPermission,
// Example functions
createClient,
createProject,
getClientMenuTree
};Key Differences from Go Implementation
Dynamic Types: JavaScript's dynamic typing eliminates the need for explicit type declarations and conversions.
Object Manipulation: JavaScript's object spread syntax (
...obj) and JSON handling make object manipulation simpler.Promise-based Async: Uses JavaScript's Promise-based async/await pattern instead of Go's context-based approach.
Class-based Models: Models are implemented as classes with methods like
toItem()and staticfromItem().Built-in JSON Handling: No need for explicit JSON marshaling/unmarshaling since DynamoDB DocumentClient handles this.
Regular Expressions: JavaScript's built-in regex handling is more concise for permission checking.
Benefits of Node.js Implementation
Less Boilerplate: Significantly less code compared to Go implementation.
Natural JSON Handling: DynamoDB stores items as JSON, which aligns perfectly with JavaScript objects.
Async Operations: JavaScript's async/await makes handling asynchronous DynamoDB operations more intuitive.
AWS SDK Integration: AWS SDK for JavaScript has excellent DynamoDB support with DocumentClient.
Server-side & Lambda Compatibility: Code works in both Node.js server environments and AWS Lambda functions.
Usage in AWS Lambda
This code can be directly used in AWS Lambda functions with minimal modifications:
javascript
// Lambda handler example
exports.handler = async (event) => {
const clientId = event.pathParameters.clientId;
const clientRepo = new ClientRepository();
try {
const client = await clientRepo.getById(clientId);
if (!client) {
return {
statusCode: 404,
body: JSON.stringify({ message: 'Client not found' })
};
}
return {
statusCode: 200,
body: JSON.stringify(client)
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
body: JSON.stringify({ message: 'Internal server error' })
};
}
};This Node.js implementation provides a complete solution for working with RuoYi data models in DynamoDB, with significant improvements in code readability and maintainability compared to the Go version.