Add edge model, service, and routes; integrate edge creation and deletion APIs

This commit is contained in:
2025-08-27 15:30:25 +05:30
parent f24ed93679
commit 46956974a1
7 changed files with 554 additions and 14 deletions

2
.env
View File

@@ -1,4 +1,4 @@
MONGO_URI=mongodb://192.168.0.110/
MONGO_URI=mongodb://192.168.0.111/
MONGO_USER=mydata
MONGO_PASSWORD=mongodb@hexr2002
MONGO_AUTH_DB=admin

View File

@@ -3,6 +3,7 @@ import cors from "cors";
import dotenv from "dotenv";
import projectRoutes from "./routes/projectRoutes";
import collectionNodeRoutes from "./routes/collectionRoutes";
import edgeRoutes from "./routes/edgeRoutes";
dotenv.config({ quiet: true });
const app = express();
@@ -14,5 +15,6 @@ app.use(
app.use("/api/v1", projectRoutes);
app.use("/api/v1", collectionNodeRoutes);
app.use("/api/v1", edgeRoutes);
export default app;

View File

@@ -0,0 +1,158 @@
import { Request, Response } from "express";
import { Alledges, deleteEdge, edgecreation } from "../../shared/services/edgeService";
export const edgeCreationController = async (
req: Request,
res: Response
): Promise<void> => {
try {
const { organization, projectId, from,to,cardinality } = req.body;
if (!organization || !projectId || !from || !to) {
res.status(400).json({
message: "All fields are required",
});
return;
}
const data = {
organization,
projectId,
from,
to,
cardinality
};
const result = await edgecreation(data);
console.log('result: ', result);
switch (result.status) {
case "project not found":
res.status(200).json({
message: "project not found",
});
break;
case "From collection not found":
res.status(200).json({
message: "From collection not found",
});
break;
case "To collection not found":
res.status(200).json({
message: "To collection not found",
});
break;
case "Field already exists":
res.status(200).json({
message: "Field already exists",
});
break;
case "Success":
res.status(200).json({
message:"Edge created successfully",
collectionNodeId: result.data,
});
break;
default:
res.status(500).json({
message: "Internal server error",
});
break;
}
} catch (error) {
res.status(500).json({
message: "Unknown error",
});
}
};
export const allEdgesController = async (
req: Request,
res: Response
): Promise<void> => {
try {
const { organization, projectId, } = req.body;
if (!organization || !projectId ) {
res.status(400).json({
message: "All fields are required",
});
return;
}
const data = {
organization,
projectId,
};
const result = await Alledges(data);
switch (result.status) {
case "project not found":
res.status(200).json({
message: "project not found",
});
break;
case "edge not found":
res.status(200).json({
message: "edge not found",
});
break;
case "Success":
res.status(200).json({
message:"fetch all Edge datas successfully",
collectionNodeId: result.data,
});
break;
default:
res.status(500).json({
message: "Internal server error",
});
break;
}
} catch (error) {
res.status(500).json({
message: "Unknown error",
});
}
};
export const deleteEdgesController = async (
req: Request,
res: Response
): Promise<void> => {
try {
const { organization, projectId, edgeId} = req.body;
if (!organization || !projectId ||!edgeId) {
res.status(400).json({
message: "All fields are required",
});
return;
}
const data = {
organization,
projectId,
edgeId
};
const result = await deleteEdge(data);
switch (result.status) {
case "project not found":
res.status(200).json({
message: "project not found",
});
break;
case "edge not found":
res.status(200).json({
message: "edge not found",
});
break;
case "Success":
res.status(200).json({
message:"Edge deleted successfully",
collectionNodeId: result.data,
});
break;
default:
res.status(500).json({
message: "Internal server error",
});
break;
}
} catch (error) {
res.status(500).json({
message: "Unknown error",
});
}
};

View File

@@ -0,0 +1,8 @@
import express from "express";
import { allEdgesController, deleteEdgesController, edgeCreationController } from "../controller/edgeController";
const edgeRoutes = express.Router();
edgeRoutes.post("/edgeCreate", edgeCreationController);
edgeRoutes.patch("/edgeDelete", deleteEdgesController);
edgeRoutes.get("/allEdges", allEdgesController);
export default edgeRoutes;

View File

@@ -1,30 +1,66 @@
import { Schema, Document } from "mongoose";
import MainModel from "../connection/connection";
import { IProject } from "./projectmodel";
type IattributeTypes =
| "string"
| "any"
| "Array"
| "Date"
| "Enum"
| "undefined"
| "object"
| "ObjectId"
| "number"
| "boolean";
interface IAttributes {
isArchive: boolean;
key: string;
type: IattributeTypes;
refKey?: object;
required?: boolean;
default?: any;
unique?: boolean;
index?: boolean;
}
interface ICollectionNode extends Document {
projectId: IProject["_id"];
collectionNodeName: string;
attributes: [
{
key: string;
type: any;
}
];
attributes: IAttributes[];
isArchive: boolean;
position: [number, number, number];
}
const attributeSchema = new Schema<IAttributes>({
key: { type: String, required: true },
type: {
type: String,
required: true,
enum: [
"string",
"number",
"boolean",
"Date",
"ObjectId",
"Array",
"Enum",
"object",
"any",
],
},
required: { type: Boolean },
refKey: { type: Object },
default: { type: Schema.Types.Mixed },
unique: { type: Boolean },
index: { type: Boolean },
isArchive: { type: Boolean, default: false },
});
const collectionSchema: Schema<ICollectionNode> = new Schema(
{
projectId: { type: Schema.Types.ObjectId, ref: "Project" },
collectionNodeName: { type: String },
position: { type: [Number], required: true },
isArchive: { type: Boolean, default: false },
attributes: [
{
key: { type: String },
type: { type: Schema.Types.Mixed },
},
],
attributes: [attributeSchema],
},
{
timestamps: true,

View File

@@ -0,0 +1,29 @@
import { Schema, Document } from "mongoose";
import MainModel from "../connection/connection";
import { IProject } from "./projectmodel";
interface IEdgeModel extends Document {
projectId: IProject["_id"];
from: { collection_id: string; field: string };
to: { collection_id: string };
cardinality: "one-to-one" | "one-to-many"|"many-to-many"
isArchive: boolean;
createdAt: number;
}
const EdgeSchema = new Schema<IEdgeModel>({
projectId: { type: Schema.Types.ObjectId, ref: "Project", required: true },
from: {
collection_id: { type: String, required: true },
field: { type: String, required: true },
},
to: {
collection_id: { type: String, required: true },
},
cardinality: { type: String, enum: ["one-to-one", "one-to-many", "many-to-many"], required: true },
isArchive: { type: Boolean, default: false },
createdAt: { type: Number, default: Date.now },
});
const edgeModel = (db: any) => {
return MainModel(db, "edge", EdgeSchema, "edge");
};
export default edgeModel;

View File

@@ -0,0 +1,307 @@
import ProjectType from "../../shared/model/projectmodel";
import collectionsModel from "../model/collectionModel";
import edgeModel from "../model/edgeModel";
interface Iresponse {
status: string;
data?: any;
}
interface IEdge {
organization: string;
projectId: string;
from: { collection_id: string, field: string };
to: { collection_id: string };
cardinality: string
}
interface IAllEdge {
organization: string;
projectId: string;
}
interface IEdgeDelete {
organization: string;
projectId: string;
edgeId: string;
}
interface Attribute {
key: string;
type: string;
isArchive: boolean;
refKey?: {
collection_id: any;
fieldId: any;
};
}
export const edgecreation = async (
data: IEdge
): Promise<Iresponse> => {
const { organization, projectId, from, to, cardinality } = data;
console.log('data: ', data);
try {
const existingProject = await ProjectType(organization).findOne({
_id: projectId,
// createdBy: userName,
isArchive: false,
});
if (!existingProject) {
return { status: "project not found" };
}
const existingFromCollection = await collectionsModel(organization).findOne({
_id: from.collection_id
})
if (!existingFromCollection) {
return { status: "From collection not found" };
}
const existingToCollection = await collectionsModel(organization).findOne({
_id: to.collection_id
})
if (!existingToCollection) {
return { status: "To collection not found" };
}
// ✅ Generate new field name for TO collection
const capitalizeFirst = (str: string) => {
if (!str) return str;
return str.charAt(0).toUpperCase() + str.slice(1);
};
// Example variables (replace with your actual data)
const collectionName = existingFromCollection.collectionNodeName;
const fieldName = from.field;
// ✅ Generate new field key
const newFieldKey = `${collectionName}${capitalizeFirst(fieldName)}`;
console.log('newFieldKey: ', newFieldKey);
// Find matching field in FROM collection
const fromField = existingFromCollection.attributes.find(
(attr: any) => attr.key === from.field
);
const fromFieldId = [fromField].map((attr: any) => attr?._id)[0];
const fieldType = normalizeType(fromField?.type);
// ✅ Check if field already exists in TO collection
// Check if already exists in TO collection
const fieldExists = existingToCollection.attributes.some(
(attr: any) => attr.key === newFieldKey
);
if (!fieldExists) {
// ✅ Add field if not exists
const newAttribute: any = {
key: newFieldKey,
type: fieldType,
refKey: {
collection_id: existingFromCollection._id,
fieldId: fromFieldId
}
};
// ✅ Push the object directly
console.log('newAttribute: ', newAttribute);
existingToCollection.attributes.push(newAttribute);
existingToCollection.attributes = existingToCollection.attributes.map((attr: any) => ({
...attr,
type: normalizeType(attr.type),
}));
await existingToCollection.save();
console.log(
`Field ${newFieldKey} (type: ${fieldType}) added to TO collection with reference to ${existingFromCollection._id}`
);
const newEdge = {
projectId,
from: { collection_id: existingFromCollection._id, field: from.field },
to: { collection_id: existingToCollection._id },
cardinality,
createdAt: new Date(),
};
// Here you should save into EdgeModel (need Edge Schema)
// Example:
const savedEdge = await edgeModel(organization).create(newEdge);
//
return {
status: "Success",
data: savedEdge, // replace with savedEdge after model integration
};
}
else {
console.log("Field already exists 🚫");
return {
status: "Field already exists"
}
}
}
catch (error: unknown) {
console.log('error: ', error);
if (error instanceof Error) {
return {
status: error.message,
};
} else {
return {
status: "An unexpected error occurred",
};
}
}
};
export const Alledges = async (
data: IAllEdge
): Promise<Iresponse> => {
const { organization, projectId, } = data;
console.log('data: ', data);
try {
const existingProject = await ProjectType(organization).findOne({
_id: projectId,
// createdBy: userName,
isArchive: false,
});
if (!existingProject) {
return { status: "project not found" };
}
const edgeDatas = await edgeModel(organization).find()
console.log('edgeDatas: ', edgeDatas);
if (!edgeDatas || edgeDatas.length === 0) {
return { status: "edge not found" };
}
return {
status: "Success",
data: edgeDatas, // replace with savedEdge after model integration
};
} catch (error: unknown) {
console.log('error: ', error);
if (error instanceof Error) {
return {
status: error.message,
};
} else {
return {
status: "An unexpected error occurred",
};
}
}
};
export const deleteEdge = async (
data: IEdgeDelete
): Promise<Iresponse> => {
const { organization, projectId, edgeId } = data;
console.log('data: ', data);
try {
const existingProject = await ProjectType(organization).findOne({
_id: projectId,
// createdBy: userName,
isArchive: false,
});
if (!existingProject) {
return { status: "project not found" };
}
const deleteEdge = await edgeModel(organization).findOneAndUpdate
({ _id: edgeId, isArchive: false }, {
isArchive: true
}, { new: true })
if (!deleteEdge) return { status: "Edge not found" }
const collectionDoc = await collectionsModel(organization).findOne({
_id: deleteEdge?.to?.collection_id, isArchive: false
});
if (!collectionDoc ) {
return { status: "collection not found" };
}
else {
const attributes = collectionDoc.attributes || [];
const matchedAttr = attributes.find((attr, index) => {
const refKey: any = (attr as any).refKey;
if (refKey) {
return String(refKey.collection_id) === String(deleteEdge?.from?.collection_id);
}
return false;
});
if (matchedAttr) {
console.log('Matched Attribute:', matchedAttr);
const index = attributes.indexOf(matchedAttr);
if (index > -1) {
attributes.splice(index, 1);
await collectionDoc.save();
console.log(`Attribute at index ${index} deleted successfully.`)
}
else {
console.log('Matched attribute not found in array');
}
} else {
// console.log('No attribute matches the given collection_id');
return { status: "No deleted in matched Document" }
}
}
return {status:"Success"}
} catch (error: unknown) {
console.log('error: ', error);
if (error instanceof Error) {
return {
status: error.message,
};
} else {
return {
status: "An unexpected error occurred",
};
}
}
};
const normalizeType = (type: any): string => {
if (!type) return "string"; // default
if (typeof type === "string") {
switch (type.toLowerCase()) {
case "boolean":
return "boolean";
case "number":
return "number";
case "string":
return "string";
case "object":
return "object";
case "array":
return "array";
case "date":
return "date";
default:
return "string";
}
}
// Handle cases like [Number], Boolean, Object
if (Array.isArray(type)) return "array";
if (type === Boolean) return "boolean";
if (type === Number) return "number";
if (type === String) return "string";
if (type === Object) return "object";
return "string"; // fallback
};