Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
db2c871
Commit local controller changes
Mansi0905 May 27, 2026
c05dbc9
fix: update controller logic
Mansi0905 May 27, 2026
ba15f4e
Export getAllData function to fix failing tests
Mansi0905 May 27, 2026
a72186e
Fix: Correct getAllData function to properly initialize getCompiledMo…
Mansi0905 May 27, 2026
f8209ce
Fix test mocks to properly support getAllData function calls
Mansi0905 May 27, 2026
ee6b198
Refactor getAllData to properly handle QueryEngine and fix test compa…
Mansi0905 May 27, 2026
983d42f
fix(dashboard-api): add limitFields, populate, cursor pagination, cou…
Mansi0905 May 29, 2026
988dc4f
chore: remove local test script test-getData.js
Mansi0905 May 29, 2026
dcaf5c6
fix: add limitFields() to QueryEngine mock and controller chain
Mansi0905 May 29, 2026
2034bb7
fix: normalize getData errors and fix per-project log aggregation
Mansi0905 May 30, 2026
29b61b6
fix: address coderabbit and reviewer comments - restore jsdocs, fix p…
Mansi0905 May 30, 2026
c8bbe8f
fix: normalize getData error responses to standard contract
Mansi0905 May 30, 2026
25c26c6
fix: normalize getData error responses to standard contract
Mansi0905 May 30, 2026
27aeb38
fix: reorder populate before limitFields, use topN for log aggregatio…
Mansi0905 May 30, 2026
9298d90
chore: resolve package-lock.json merge conflict
Mansi0905 May 31, 2026
f7c95bb
fix: fix syntax error in log aggregation pipeline
Mansi0905 Jun 1, 2026
01f2f69
fix: remove stray brace causing syntax error in log aggregation
Mansi0905 Jun 1, 2026
5e49d2d
Merge branch 'main' into fix/dashboard-getData-query-engine
Mansi0905 Jun 1, 2026
966f68c
ci: trigger rerun
Mansi0905 Jun 1, 2026
478426e
fix: fix unclosed template literal and missing closing brace in getData
Mansi0905 Jun 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 31 additions & 21 deletions apps/dashboard-api/src/controllers/project.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,16 +332,29 @@ module.exports.getAllProject = async (req, res) => {

const projectIds = projects.map(p => p._id);
const recentLogs = await Log.aggregate([
{ $match: { projectId: { $in: projectIds } } },
{ $sort: { timestamp: -1 } },
{ $limit: 100 },
{ $group: {
_id: "$projectId",
errorCount: { $sum: { $cond: [{ $gte: ["$status", 400] }, 1, 0] } },
successCount: { $sum: { $cond: [{ $lt: ["$status", 400] }, 1, 0] } }
{ $match: { projectId: { $in: projectIds } } },
{ $sort: { timestamp: -1 } },
{
$group: {
_id: "$projectId",
logs: { $topN: { n: 100, sortBy: { timestamp: -1 }, output: { status: "$status" } } }
}
},
{
$project: {
errorCount: {
$size: {
$filter: { input: "$logs", as: "l", cond: { $gte: ["$$l.status", 400] } }
}
},
successCount: {
$size: {
$filter: { input: "$logs", as: "l", cond: { $lt: ["$$l.status", 400] } }
}
}
]);
}
}
]);

const logsMap = recentLogs.reduce((acc, log) => {
acc[log._id.toString()] = log;
Expand Down Expand Up @@ -395,8 +408,7 @@ module.exports.getSingleProject = async (req, res) => {
"+resendApiKey.iv " +
"+resendApiKey.tag",
);
if (!project)
return res.status(404).json({ error: "Project not found." });
if (!project) return res.status(404).json({ success: false, data: {}, message: "Project not found." });
projectObj = project.toObject();
await setProjectById(req.params.projectId, projectObj);
}
Expand Down Expand Up @@ -763,14 +775,13 @@ module.exports.getData = async (req, res) => {
try {
const { projectId, collectionName } = req.params;
const project = await Project.findOne({ _id: projectId, owner: req.user._id });
if (!project) return res.status(404).json({ error: "Project not found." });
if (!project) return res.status(404).json({ success: false, data: {}, message: "Project not found." });



const collectionConfig = project.collections.find(c => c.name === collectionName);
if (!collectionConfig) {
return res.status(404).json({
error: "Collection not found",
collection: collectionName
});
return res.status(404).json({ success: false, data: {}, message: `Collection ${collectionName} not found.` });
}

const connection = await getConnection(projectId);
Expand Down Expand Up @@ -850,10 +861,11 @@ module.exports.getData = async (req, res) => {
message: "Data fetched successfully.",
});
} catch (err) {
res.status(500).json({ error: err.message });
if (err?.statusCode === 400 || err?.name === 'QueryFilterError') {
return res.status(400).json({ success: false, data: {}, message: err.message || "Invalid query filter." });
}
};

};
module.exports.deleteCollection = async (req, res) => {
try {
const { projectId, collectionName } = req.params;
Expand Down Expand Up @@ -925,10 +937,8 @@ module.exports.insertData = async (req, res) => {
(c) => c.name === collectionName,
);
if (!collectionConfig) {
return res
.status(404)
.json({ error: "Collection configuration not found." });
}
return res.status(404).json({ success: false, data: {}, message: `Collection ${collectionName} not found.` });
}

// Prevent manual injection of soft-delete fields
delete incomingData.isDeleted;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jest.mock('@urbackend/common', () => ({
sanitize: (v) => v,
Project: {},
getConnection: jest.fn().mockResolvedValue({}),
getCompiledModel: jest.fn(() => ({
getCompiledModel: jest.fn((connection, collectionConfig, projectId, isExternal) => ({
find: (...args) => {
mockFind(...args);
return {
Expand Down
15 changes: 9 additions & 6 deletions apps/public-api/src/controllers/data.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,14 @@ module.exports.getAllData = async (req, res) => {
const collectionConfig = project.collections.find(
(c) => c.name === collectionName,
);
if (!collectionConfig)
return res.status(404).json({ error: "Collection not found" });

if (!collectionConfig) {
return res.status(404).json({
success: false,
data: {},
message: "Collection not found",
});
}

const connection = await getConnection(project._id);
const Model = getCompiledModel(
Expand Down Expand Up @@ -264,7 +270,6 @@ module.exports.getAllData = async (req, res) => {
const parsedLimit = parseInt(req.query.limit, 10);
const limit = Math.max(1, Math.min(Number.isNaN(parsedLimit) ? 100 : parsedLimit, 100));

// Use cursor-based pagination if cursor parameter is provided, otherwise use offset-based
const useCursor = !!req.query.cursor;
if (useCursor) {
features.cursorPaginate();
Expand All @@ -274,7 +279,6 @@ module.exports.getAllData = async (req, res) => {

const data = await features.query.lean();

// Handle cursor pagination: slice to actual limit and generate next cursor
let items = data;
let nextCursor = null;
if (useCursor) {
Expand Down Expand Up @@ -327,7 +331,6 @@ module.exports.getAllData = async (req, res) => {
});
}
};

// GET SINGLE DOC
module.exports.getSingleDoc = async (req, res) => {
try {
Expand Down Expand Up @@ -737,4 +740,4 @@ module.exports.recoverSingleDoc = async (req, res, next) => {
}
return next(new AppError(500, "Failed to recover document."));
}
};
};
Loading