streamby-core
Version:
StreamBy middleware framework for media storage management
320 lines (319 loc) • 16.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Model = void 0;
const connectionManager_1 = require("../adapters/database/connectionManager");
const mongodb_1 = require("mongodb");
const sql_1 = require("../adapters/database/sql");
const nosql_1 = require("../adapters/database/nosql");
class Model {
constructor(connectionIds, tableName, schema) {
this.connectionIds = connectionIds;
this.tableName = tableName;
this.schema = schema;
}
// Add these getter methods
getConnectionIds() {
return this.connectionIds;
}
getTableName() {
return this.tableName;
}
useDbType(dbType) {
const filteredConnectionIds = this.connectionIds.filter(id => {
const connection = (0, connectionManager_1.getConnection)(id);
return connection.type === dbType;
});
return new Model(filteredConnectionIds, this.tableName);
}
async find(filter) {
const allResults = [];
const activeConnectionIds = this.connectionIds.filter(id => (0, connectionManager_1.getConnectedIds)().includes(id));
for (const connectionId of activeConnectionIds) {
const clientEntry = (0, connectionManager_1.getConnection)(connectionId);
const connection = clientEntry.client;
const dbType = clientEntry.type;
let processedFilter = { ...filter };
if (dbType === 'sql') {
if (processedFilter._id) {
processedFilter.id = processedFilter._id;
delete processedFilter._id;
}
let sqlResults = [];
if (this.tableName === 'projects' && processedFilter.members && processedFilter.members.$elemMatch) {
// Handle members filter for SQL projects
const userId = processedFilter.members.$elemMatch.userId;
const schema = this.schema || 'streamby'; // Default to 'streamby' if schema not provided
const query = `
SELECT p.*, pm."userId" as memberUserId, pm.archived as memberArchived
FROM "${schema}"."projects" p
JOIN "${schema}"."project_members" pm ON p.id = pm."projectId"
WHERE pm."userId" = $1
`;
const result = await connection.query(query, [userId]);
sqlResults = result.rows.map(row => ({
...row,
members: [{
userId: row.memberUserId,
archived: row.memberArchived,
// Add other member fields if necessary
}]
}));
}
else {
// General SQL find
sqlResults = await sql_1.sqlAdapter.find(connection, this.tableName, processedFilter, this.schema);
}
for (const item of sqlResults) {
const transformedItem = this.transformResult(item);
if (this.tableName === 'projects' && !transformedItem.members) {
// For projects, if members not already populated by join, fetch from project_members table
const projectMembers = await sql_1.sqlAdapter.find(connection, 'project_members', { projectId: transformedItem.id }, this.schema);
transformedItem.members = projectMembers.map((member) => ({
userId: member.userId,
role: member.role, // Assuming role is also stored in project_members
archived: member.archived,
}));
}
allResults.push(transformedItem);
}
}
else if (dbType === 'nosql') {
const nosqlResults = await nosql_1.nosqlAdapter.find(connection, this.tableName, processedFilter);
for (const item of nosqlResults) {
allResults.push(this.transformResult(item));
}
}
}
return allResults;
}
transformResult(item) {
const transformedItem = { ...item };
if (transformedItem._id && !transformedItem.id) {
transformedItem.id = transformedItem._id.toString();
}
return transformedItem;
}
async findOne(filter) {
const activeConnectionIds = this.connectionIds.filter(id => (0, connectionManager_1.getConnectedIds)().includes(id));
for (const connectionId of activeConnectionIds) {
const clientEntry = (0, connectionManager_1.getConnection)(connectionId);
const connection = clientEntry.client;
const dbType = clientEntry.type;
let processedFilter = { ...filter };
if (dbType === 'sql') {
if (processedFilter._id) {
processedFilter.id = processedFilter._id;
delete processedFilter._id;
}
// Special handling for 'users' table with raw query
if (this.tableName === 'users' && processedFilter.id) {
const schema = this.schema || 'streamby'; // Default to 'streamby' if schema not provided
const query = `SELECT * FROM "${schema}"."${this.tableName}" WHERE "id" = $1::uuid LIMIT 1`;
const result = await connection.query(query, [processedFilter.id]);
return result.rows[0] || null;
}
const result = await sql_1.sqlAdapter.findOne(connection, this.tableName, processedFilter, this.schema); // Pass this.schema
if (result) {
const transformedResult = this.transformResult(result);
if (this.tableName === 'projects') {
// For projects, fetch members from project_members table
const projectMembers = await sql_1.sqlAdapter.find(connection, 'project_members', { projectId: transformedResult.id }, this.schema);
transformedResult.members = projectMembers.map((member) => ({
userId: member.userId,
role: member.role, // Assuming role is also stored in project_members
archived: member.archived,
}));
}
return transformedResult;
}
}
else if (dbType === 'nosql') {
if (processedFilter._id && typeof processedFilter._id === 'string') {
try {
processedFilter._id = new mongodb_1.ObjectId(processedFilter._id);
}
catch (e) {
// If it's not a valid ObjectId string, it might be a UUID from a SQL project.
// In this case, this NoSQL connection won't find it, so we can just continue.
continue;
}
}
const result = await nosql_1.nosqlAdapter.findOne(connection, this.tableName, processedFilter);
if (result)
return result;
}
}
return null;
}
async create(data) {
const activeConnectionIds = this.connectionIds.filter(id => (0, connectionManager_1.getConnectedIds)().includes(id));
// Determine the target database type from the data payload
const targetDbType = data.dbType || 'nosql'; // Default to nosql if not specified
const allClientEntries = activeConnectionIds.map(id => (0, connectionManager_1.getConnection)(id));
// Find the connection that matches the targetDbType
const clientEntry = allClientEntries.find(entry => entry.type === targetDbType);
if (!clientEntry) {
throw new Error(`No active connection found for database type: ${targetDbType}`);
}
const connection = clientEntry.client;
const dbType = clientEntry.type;
if (dbType === 'sql') {
const dataToInsert = {};
let membersToInsert = [];
// Iterate over the keys of the incoming data
for (const key in data) {
if (this.tableName === 'projects' && key === 'members') {
membersToInsert = data[key];
}
else if (this.tableName === 'projects' && key.toLowerCase() === 'dbtype') {
dataToInsert["dbType"] = data[key];
}
else {
dataToInsert[key] = data[key];
}
}
const created = await sql_1.sqlAdapter.create(connection, this.tableName, dataToInsert, this.schema);
// Insert members into project_members table for SQL
if (this.tableName === 'projects' && membersToInsert.length > 0) {
for (const member of membersToInsert) {
await sql_1.sqlAdapter.create(connection, 'project_members', {
projectId: created.id,
userId: member.userId,
role: member.role,
archived: member.archived || false,
}, this.schema);
}
}
return created;
}
else if (dbType === 'nosql') {
const created = await nosql_1.nosqlAdapter.create(connection, this.tableName, data);
return created;
}
return data;
}
async update(filter, data) {
const existingProject = await this.findOne(filter); // Find the project first
if (!existingProject) {
return null; // Project not found
}
const targetDbType = existingProject.dbType; // Get the actual dbType of the project
// Find the connection that matches the targetDbType
const clientEntry = this.connectionIds
.map(id => (0, connectionManager_1.getConnection)(id))
.find(entry => entry.type === targetDbType);
if (!clientEntry) {
throw new Error(`No active connection found for database type: ${targetDbType}`);
}
const connection = clientEntry.client;
const dbType = clientEntry.type; // This will be the targetDbType
let updateFilter = {}; // Initialize updateFilter here
// Construct the updateFilter based on the actual dbType of the project
if (dbType === 'sql') {
updateFilter.id = existingProject.id; // Use the 'id' from the existingProject
}
else if (dbType === 'nosql') {
// Ensure _id is an ObjectId for NoSQL updates
if (existingProject._id && typeof existingProject._id === 'string') {
try {
updateFilter._id = new mongodb_1.ObjectId(existingProject._id);
}
catch (e) {
// If existingProject._id is not a valid ObjectId string, it's an error for NoSQL
return null; // Or throw a more specific error
}
}
else {
updateFilter._id = existingProject._id; // Already an ObjectId or other valid type
}
}
// Handle specific member archiving/unarchiving
if (data["members.$.archived"] !== undefined && filter["_id"] && filter["members.userId"]) { // Use original filter for projectId and userIdToUpdate
const originalProjectId = filter["_id"]; // Use the original projectId from the request filter
const userIdToUpdate = filter["members.userId"];
const newArchivedStatus = data["members.$.archived"];
const archivedBy = data["members.$.archivedBy"];
const archivedAt = data["members.$.archivedAt"];
if (dbType === 'sql') {
// For SQL, directly update the project_members table
const memberUpdateResult = await sql_1.sqlAdapter.update(connection, 'project_members', { projectId: originalProjectId, userId: userIdToUpdate }, // originalProjectId is fine for SQL
{ archived: newArchivedStatus, archivedBy: archivedBy, archivedAt: archivedAt }, this.schema);
// After updating the member, fetch the full project to return
if (memberUpdateResult) {
const updatedProject = await this.findOne({ _id: originalProjectId });
return updatedProject;
}
}
else if (dbType === 'nosql') {
const projectToUpdate = existingProject; // Already fetched
const updatedMembers = projectToUpdate.members.map((member) => {
if (member.userId === userIdToUpdate) {
return { ...member, archived: newArchivedStatus, archivedBy: archivedBy, archivedAt: archivedAt };
}
return member;
});
let objectIdOriginalProjectId;
try {
objectIdOriginalProjectId = new mongodb_1.ObjectId(originalProjectId); // Convert originalProjectId to ObjectId for NoSQL
}
catch (e) {
return null;
}
const result = await nosql_1.nosqlAdapter.update(connection, this.tableName, { _id: objectIdOriginalProjectId }, { members: updatedMembers });
if (result)
return result;
}
}
else {
// General update logic
// Use the correctly constructed updateFilter
if (dbType === 'sql') {
const result = await sql_1.sqlAdapter.update(connection, this.tableName, updateFilter, data, this.schema);
if (result)
return result;
}
else if (dbType === 'nosql') {
const result = await nosql_1.nosqlAdapter.update(connection, this.tableName, filter, data);
if (result)
return result;
}
}
return null;
}
async delete(filter) {
let deletedCount = 0;
const activeConnectionIds = this.connectionIds.filter(id => (0, connectionManager_1.getConnectedIds)().includes(id));
for (const connectionId of activeConnectionIds) {
const clientEntry = (0, connectionManager_1.getConnection)(connectionId);
const connection = clientEntry.client;
const dbType = clientEntry.type;
let processedFilter = { ...filter };
if (dbType === 'sql') {
if (processedFilter._id) {
processedFilter.id = processedFilter._id;
delete processedFilter._id;
}
console.log(`SQL: Deleting from ${this.tableName} with filter:`, processedFilter);
const count = await sql_1.sqlAdapter.delete(connection, this.tableName, processedFilter, this.schema);
console.log(`SQL: Deleted ${count} rows from ${this.tableName}`);
deletedCount += count;
}
else if (dbType === 'nosql') {
if (processedFilter._id && typeof processedFilter._id === 'string') {
try {
processedFilter._id = new mongodb_1.ObjectId(processedFilter._id);
}
catch (e) {
// If it's not a valid ObjectId string, it might be a UUID from a SQL project.
// In this case, this NoSQL connection won't find it, so we can just continue.
continue;
}
}
const count = await nosql_1.nosqlAdapter.delete(connection, this.tableName, processedFilter);
deletedCount += count;
}
}
return deletedCount;
}
}
exports.Model = Model;