added array filter option

This commit is contained in:
2025-05-03 18:13:31 +05:30
parent 5800069e6b
commit dbc82f53a3
9 changed files with 202 additions and 174 deletions

View File

@@ -1,13 +1,13 @@
import { orgModel } from '../organization/organization.schema'; import { orgModel } from "../organization/organization.schema";
import { getFilterObject, getSortObject, PageQueryParams } from '../pagination'; import { getFilterObject, getSortObject, PageQueryParams } from "../pagination";
import { userModel } from '../user/user.schema'; import { userModel } from "../user/user.schema";
import { generateId } from '../utils/id'; import { generateId } from "../utils/id";
import { import {
CreateNotificationInput, CreateNotificationInput,
notificationFields, notificationFields,
notificationModel, notificationModel,
UpdateNotificationInput, UpdateNotificationInput,
} from './notification.schema'; } from "./notification.schema";
export async function createNotification( export async function createNotification(
input: CreateNotificationInput, input: CreateNotificationInput,
@@ -47,12 +47,12 @@ export async function listNotifications(
const pipeline: any = [ const pipeline: any = [
{ {
$match: { $and: [{ tenantId: tenantId }, { ...filterObj }] }, $match: { $and: [{ tenantId: tenantId }, ...filterObj] },
}, },
]; ];
if (params.searchToken && params.searchToken != '') { if (params.searchToken && params.searchToken != "") {
const regex = new RegExp(params.searchToken, 'i'); const regex = new RegExp(params.searchToken, "i");
pipeline.push({ pipeline.push({
$match: { $match: {
$or: [{ permitNumber: { $regex: regex } }, { link: { $regex: regex } }], $or: [{ permitNumber: { $regex: regex } }, { link: { $regex: regex } }],
@@ -82,7 +82,7 @@ export async function listNotifications(
}, },
{ {
$facet: { $facet: {
metadata: [{ $count: 'count' }], metadata: [{ $count: "count" }],
data: [ data: [
{ $sort: sortObj }, { $sort: sortObj },
{ $skip: (page - 1) * pageSize }, { $skip: (page - 1) * pageSize },
@@ -121,12 +121,12 @@ export async function getUniqueValuesNotification(
let values = await notificationModel.distinct(field, { tenantId: tenenatId }); let values = await notificationModel.distinct(field, { tenantId: tenenatId });
let matchedValues = []; let matchedValues = [];
if (field === 'county.name') { if (field === "county.name") {
matchedValues = await orgModel.find().where('name').in(values).exec(); matchedValues = await orgModel.find().where("name").in(values).exec();
} else if (field === 'client') { } else if (field === "client") {
matchedValues = await orgModel.find().where('_id').in(values).exec(); matchedValues = await orgModel.find().where("_id").in(values).exec();
} else if (field === 'assignedTo') { } else if (field === "assignedTo") {
matchedValues = await userModel.find().where('name').in(values).exec(); matchedValues = await userModel.find().where("name").in(values).exec();
} }
if (matchedValues.length > 0) { if (matchedValues.length > 0) {

View File

@@ -42,7 +42,7 @@ export async function listOrgs(params: PageQueryParams, tenantId: string) {
const filterObj = getFilterObject(params); const filterObj = getFilterObject(params);
const orgs = await orgModel.aggregate([ const orgs = await orgModel.aggregate([
{ $match: { $and: [{ tenantId: tenantId }, { ...filterObj }] } }, { $match: { $and: [{ tenantId: tenantId }, ...filterObj] } },
{ {
$facet: { $facet: {
metadata: [{ $count: "count" }], metadata: [{ $count: "count" }],
@@ -130,7 +130,7 @@ export async function searchOrgs(params: PageQueryParams, tenantId: string) {
const regex = new RegExp(params.searchToken, "i"); const regex = new RegExp(params.searchToken, "i");
const orgs = await orgModel.aggregate([ const orgs = await orgModel.aggregate([
{ $match: { $and: [{ tenantId: tenantId }, { ...filterObj }] } }, { $match: { $and: [{ tenantId: tenantId }, ...filterObj] } },
{ {
$match: { $match: {
$or: [{ name: { $regex: regex } }, { domain: { $regex: regex } }], $or: [{ name: { $regex: regex } }, { domain: { $regex: regex } }],

View File

@@ -1,5 +1,5 @@
import { z } from 'zod'; import { z } from "zod";
import { parse } from './utils/queryParser'; import { parse } from "./utils/queryParser";
export const pageMetadata = z.object({ export const pageMetadata = z.object({
count: z.number(), count: z.number(),
@@ -23,23 +23,26 @@ export function getSortObject(
) { ) {
const sortObj: Record<string, 1 | -1> = {}; const sortObj: Record<string, 1 | -1> = {};
if (params.sort && params.sort != '') { if (params.sort && params.sort != "") {
const sortOptions = params.sort.split(','); const sortOptions = params.sort.split(",");
sortOptions.forEach((item) => { sortOptions.forEach((item) => {
const order = item.startsWith('-') ? -1 : 1; const order = item.startsWith("-") ? -1 : 1;
const field = item.replace('-', '').trim(); const field = item.replace("-", "").trim();
if (validFields.includes(field)) sortObj[field] = order; if (validFields.includes(field)) sortObj[field] = order;
}); });
} }
if (Object.keys(sortObj).length == 0) sortObj['createdAt'] = -1; if (Object.keys(sortObj).length == 0) sortObj["createdAt"] = -1;
return sortObj; return sortObj;
} }
export function getFilterObject(params: PageQueryParams) { export function getFilterObject(params: PageQueryParams) {
if (params.filter && params.filter != '') { if (params.filter && params.filter != "") {
return parse(params.filter.split(',')); const parsedQuery = parse(params.filter.split("|")).filter(
(query) => Object.keys(query).length > 0
);
return parsedQuery;
} }
} }

View File

@@ -63,15 +63,15 @@ export async function listPermits(
const page = params.page || 1; const page = params.page || 1;
const pageSize = params.pageSize || 10; const pageSize = params.pageSize || 10;
const sortObj = getSortObject(params, permitFields); const sortObj = getSortObject(params, permitFields);
const filterObj = getFilterObject(params) || {}; const filterObj = getFilterObject(params) || [];
if (user.role == "client") { if (user.role == "client") {
filterObj["client"] = new mongoose.Types.ObjectId(user.orgId); filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) });
} }
const permitsList = await permitModel.aggregate([ const permitsList = await permitModel.aggregate([
{ {
$match: { $and: [{ tenantId: user.tenantId }, { ...filterObj }] }, $match: { $and: [{ tenantId: user.tenantId }, ...filterObj] },
}, },
{ {
$lookup: { $lookup: {
@@ -216,10 +216,10 @@ export async function searchPermit(
const page = params.page || 1; const page = params.page || 1;
const pageSize = params.pageSize || 10; const pageSize = params.pageSize || 10;
const sortObj = getSortObject(params, permitFields); const sortObj = getSortObject(params, permitFields);
const filterObj = getFilterObject(params) || {}; const filterObj = getFilterObject(params) || [];
if (user.role == "client") { if (user.role == "client") {
filterObj["client"] = new mongoose.Types.ObjectId(user.orgId); filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) });
} }
if (!params.searchToken) if (!params.searchToken)
@@ -229,7 +229,7 @@ export async function searchPermit(
const permitsList = await permitModel.aggregate([ const permitsList = await permitModel.aggregate([
{ {
$match: { $and: [{ tenantId: user.tenantId }, { ...filterObj }] }, $match: { $and: [{ tenantId: user.tenantId }, ...filterObj] },
}, },
{ {
$match: { $match: {

View File

@@ -41,15 +41,15 @@ export async function listProcessedPermits(
const page = params.page || 1; const page = params.page || 1;
const pageSize = params.pageSize || 10; const pageSize = params.pageSize || 10;
const sortObj = getSortObject(params, processedFields); const sortObj = getSortObject(params, processedFields);
const filterObj = getFilterObject(params) || {}; const filterObj = getFilterObject(params) || [];
if (user.role == "client") { if (user.role == "client") {
filterObj["client"] = new mongoose.Types.ObjectId(user.orgId); filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) });
} }
const pipeline: any = [ const pipeline: any = [
{ {
$match: { $and: [{ tenantId: user.tenantId }, { ...filterObj }] }, $match: { $and: [{ tenantId: user.tenantId }, ...filterObj] },
}, },
]; ];

View File

@@ -4,13 +4,13 @@ import {
rtsModel, rtsModel,
UpdateRtsInput, UpdateRtsInput,
UploadRtsInput, UploadRtsInput,
} from './rts.schema'; } from "./rts.schema";
import { AuthenticatedUser } from '../auth'; import { AuthenticatedUser } from "../auth";
import { generateId } from '../utils/id'; import { generateId } from "../utils/id";
import { getFilterObject, getSortObject, PageQueryParams } from '../pagination'; import { getFilterObject, getSortObject, PageQueryParams } from "../pagination";
import { getUser } from '../user/user.service'; import { getUser } from "../user/user.service";
import { orgModel } from '../organization/organization.schema'; import { orgModel } from "../organization/organization.schema";
import { userModel } from '../user/user.schema'; import { userModel } from "../user/user.schema";
export async function createRts( export async function createRts(
input: CreateRtsInput, input: CreateRtsInput,
@@ -53,9 +53,9 @@ export async function createRts(
export async function getRts(id: string, tenantId: string) { export async function getRts(id: string, tenantId: string) {
return await rtsModel return await rtsModel
.findOne({ pid: id, tenantId: tenantId }) .findOne({ pid: id, tenantId: tenantId })
.populate({ path: 'county', select: 'pid name avatar' }) .populate({ path: "county", select: "pid name avatar" })
.populate({ path: 'client', select: 'pid name avatar' }) .populate({ path: "client", select: "pid name avatar" })
.populate({ path: 'createdBy', select: 'pid name avatar' }); .populate({ path: "createdBy", select: "pid name avatar" });
} }
export async function listRts(params: PageQueryParams, tenantId: string) { export async function listRts(params: PageQueryParams, tenantId: string) {
@@ -66,30 +66,30 @@ export async function listRts(params: PageQueryParams, tenantId: string) {
const rtsList = await rtsModel.aggregate([ const rtsList = await rtsModel.aggregate([
{ {
$match: { $and: [{ tenantId: tenantId }, { ...filterObj }] }, $match: { $and: [{ tenantId: tenantId }, ...filterObj] },
}, },
{ {
$lookup: { $lookup: {
from: 'organizations', from: "organizations",
localField: 'county', localField: "county",
foreignField: '_id', foreignField: "_id",
as: 'countyRec', as: "countyRec",
}, },
}, },
{ {
$lookup: { $lookup: {
from: 'organizations', from: "organizations",
localField: 'client', localField: "client",
foreignField: '_id', foreignField: "_id",
as: 'clientRec', as: "clientRec",
}, },
}, },
{ {
$lookup: { $lookup: {
from: 'users', from: "users",
localField: 'createdBy', localField: "createdBy",
foreignField: '_id', foreignField: "_id",
as: 'createdRec', as: "createdRec",
}, },
}, },
{ {
@@ -101,36 +101,36 @@ export async function listRts(params: PageQueryParams, tenantId: string) {
createdAt: 1, createdAt: 1,
county: { county: {
$let: { $let: {
vars: { county: { $arrayElemAt: ['$countyRec', 0] } }, vars: { county: { $arrayElemAt: ["$countyRec", 0] } },
in: { in: {
_id: '$$county._id', _id: "$$county._id",
pid: '$$county.pid', pid: "$$county.pid",
name: '$$county.name', name: "$$county.name",
type: '$$county.type', type: "$$county.type",
avatar: '$$county.avatar', avatar: "$$county.avatar",
}, },
}, },
}, },
client: { client: {
$let: { $let: {
vars: { client: { $arrayElemAt: ['$clientRec', 0] } }, vars: { client: { $arrayElemAt: ["$clientRec", 0] } },
in: { in: {
_id: '$$client._id', _id: "$$client._id",
pid: '$$client.pid', pid: "$$client.pid",
name: '$$client.name', name: "$$client.name",
type: '$$client.type', type: "$$client.type",
avatar: '$$client.avatar', avatar: "$$client.avatar",
}, },
}, },
}, },
createdBy: { createdBy: {
$let: { $let: {
vars: { created: { $arrayElemAt: ['$createdRec', 0] } }, vars: { created: { $arrayElemAt: ["$createdRec", 0] } },
in: { in: {
_id: '$$created._id', _id: "$$created._id",
pid: '$$created.pid', pid: "$$created.pid",
name: '$$created.name', name: "$$created.name",
avatar: '$$created.avatar', avatar: "$$created.avatar",
}, },
}, },
}, },
@@ -138,7 +138,7 @@ export async function listRts(params: PageQueryParams, tenantId: string) {
}, },
{ {
$facet: { $facet: {
metadata: [{ $count: 'count' }], metadata: [{ $count: "count" }],
data: [ data: [
{ $sort: sortObj }, { $sort: sortObj },
{ $skip: (page - 1) * pageSize }, { $skip: (page - 1) * pageSize },
@@ -168,9 +168,9 @@ export async function updateRts(
) { ) {
const updatedRts = await rtsModel const updatedRts = await rtsModel
.findOneAndUpdate({ pid: id, tenantId: tenantId }, input, { new: true }) .findOneAndUpdate({ pid: id, tenantId: tenantId }, input, { new: true })
.populate({ path: 'createdBy', select: 'pid name avatar' }) .populate({ path: "createdBy", select: "pid name avatar" })
.populate({ path: 'county', select: 'pid name avatar' }) .populate({ path: "county", select: "pid name avatar" })
.populate({ path: 'client', select: 'pid name avatar' }); .populate({ path: "client", select: "pid name avatar" });
return updatedRts; return updatedRts;
} }
@@ -202,12 +202,12 @@ export async function getUniqueValuesRTS(field: string, tenenatId: string) {
let values = await rtsModel.distinct(field, { tenantId: tenenatId }); let values = await rtsModel.distinct(field, { tenantId: tenenatId });
let matchedValues = []; let matchedValues = [];
if (field === 'county') { if (field === "county") {
matchedValues = await orgModel.find().where('_id').in(values).exec(); matchedValues = await orgModel.find().where("_id").in(values).exec();
} else if (field === 'client') { } else if (field === "client") {
matchedValues = await orgModel.find().where('_id').in(values).exec(); matchedValues = await orgModel.find().where("_id").in(values).exec();
} else if (field === 'createdBy') { } else if (field === "createdBy") {
matchedValues = await userModel.find().where('_id').in(values).exec(); matchedValues = await userModel.find().where("_id").in(values).exec();
} }
if (matchedValues.length > 0) { if (matchedValues.length > 0) {

View File

@@ -1,14 +1,14 @@
import { AuthenticatedUser } from '../auth'; import { AuthenticatedUser } from "../auth";
import { getFilterObject, getSortObject, PageQueryParams } from '../pagination'; import { getFilterObject, getSortObject, PageQueryParams } from "../pagination";
import { generateId } from '../utils/id'; import { generateId } from "../utils/id";
import { taskPipeline } from '../utils/pipeline'; import { taskPipeline } from "../utils/pipeline";
import { import {
CreateTaskInput, CreateTaskInput,
taskFields, taskFields,
taskModel, taskModel,
UpdateTaskInput, UpdateTaskInput,
UploadTaskInput, UploadTaskInput,
} from './task.schema'; } from "./task.schema";
export async function createTask( export async function createTask(
input: CreateTaskInput, input: CreateTaskInput,
@@ -31,8 +31,8 @@ export async function createTask(
return await taskModel return await taskModel
.findOne({ pid: task.pid }) .findOne({ pid: task.pid })
.populate({ path: 'createdBy', select: 'pid name avatar' }) .populate({ path: "createdBy", select: "pid name avatar" })
.populate({ path: 'assignedTo', select: 'pid name avatar' }); .populate({ path: "assignedTo", select: "pid name avatar" });
} }
export async function updateTask( export async function updateTask(
@@ -42,8 +42,8 @@ export async function updateTask(
) { ) {
const updatedTask = await taskModel const updatedTask = await taskModel
.findOneAndUpdate({ tenantId: tenantId, pid: taskId }, input, { new: true }) .findOneAndUpdate({ tenantId: tenantId, pid: taskId }, input, { new: true })
.populate({ path: 'createdBy', select: 'pid name avatar' }) .populate({ path: "createdBy", select: "pid name avatar" })
.populate({ path: 'assignedTo', select: 'pid name avatar' }); .populate({ path: "assignedTo", select: "pid name avatar" });
return updatedTask; return updatedTask;
} }
@@ -51,8 +51,8 @@ export async function updateTask(
export async function getTask(taskId: string, tenantId: string) { export async function getTask(taskId: string, tenantId: string) {
return await taskModel return await taskModel
.findOne({ tenantId: tenantId, pid: taskId }) .findOne({ tenantId: tenantId, pid: taskId })
.populate({ path: 'createdBy', select: 'pid name avatar' }) .populate({ path: "createdBy", select: "pid name avatar" })
.populate({ path: 'assignedTo', select: 'pid name avatar' }); .populate({ path: "assignedTo", select: "pid name avatar" });
} }
export async function listTasks(params: PageQueryParams, tenantId: string) { export async function listTasks(params: PageQueryParams, tenantId: string) {
@@ -63,22 +63,22 @@ export async function listTasks(params: PageQueryParams, tenantId: string) {
const taskList = await taskModel.aggregate([ const taskList = await taskModel.aggregate([
{ {
$match: { $and: [{ tenantId: tenantId }, { ...filterObj }] }, $match: { $and: [{ tenantId: tenantId }, ...filterObj] },
}, },
{ {
$lookup: { $lookup: {
from: 'users', from: "users",
localField: 'createdBy', localField: "createdBy",
foreignField: '_id', foreignField: "_id",
as: 'createdBy', as: "createdBy",
}, },
}, },
{ {
$lookup: { $lookup: {
from: 'users', from: "users",
localField: 'assignedTo', localField: "assignedTo",
foreignField: '_id', foreignField: "_id",
as: 'assignedTo', as: "assignedTo",
}, },
}, },
{ {
@@ -92,21 +92,21 @@ export async function listTasks(params: PageQueryParams, tenantId: string) {
createdAt: 1, createdAt: 1,
createdBy: { createdBy: {
$let: { $let: {
vars: { createdBy: { $arrayElemAt: ['$createdBy', 0] } }, vars: { createdBy: { $arrayElemAt: ["$createdBy", 0] } },
in: { in: {
_id: '$$createdBy._id', _id: "$$createdBy._id",
pid: '$$createdBy.pid', pid: "$$createdBy.pid",
name: '$$createdBy.name', name: "$$createdBy.name",
}, },
}, },
}, },
assignedTo: { assignedTo: {
$let: { $let: {
vars: { assignedTo: { $arrayElemAt: ['$assignedTo', 0] } }, vars: { assignedTo: { $arrayElemAt: ["$assignedTo", 0] } },
in: { in: {
_id: '$$assignedTo._id', _id: "$$assignedTo._id",
pid: '$$assignedTo.pid', pid: "$$assignedTo.pid",
name: '$$assignedTo.name', name: "$$assignedTo.name",
}, },
}, },
}, },
@@ -114,7 +114,7 @@ export async function listTasks(params: PageQueryParams, tenantId: string) {
}, },
{ {
$facet: { $facet: {
metadata: [{ $count: 'count' }], metadata: [{ $count: "count" }],
data: [ data: [
{ $sort: sortObj }, { $sort: sortObj },
{ $skip: (page - 1) * pageSize }, { $skip: (page - 1) * pageSize },
@@ -147,11 +147,11 @@ export async function searchTasks(params: PageQueryParams, tenantId: string) {
const sortObj = getSortObject(params, taskFields); const sortObj = getSortObject(params, taskFields);
const filterObj = getFilterObject(params); const filterObj = getFilterObject(params);
const regex = new RegExp(params.searchToken, 'i'); const regex = new RegExp(params.searchToken, "i");
const taskList = await taskModel.aggregate([ const taskList = await taskModel.aggregate([
{ {
$match: { $and: [{ tenantId: tenantId }, { ...filterObj }] }, $match: { $and: [{ tenantId: tenantId }, ...filterObj] },
}, },
{ {
$match: { $match: {
@@ -160,18 +160,18 @@ export async function searchTasks(params: PageQueryParams, tenantId: string) {
}, },
{ {
$lookup: { $lookup: {
from: 'users', from: "users",
localField: 'createdBy', localField: "createdBy",
foreignField: '_id', foreignField: "_id",
as: 'createdBy', as: "createdBy",
}, },
}, },
{ {
$lookup: { $lookup: {
from: 'users', from: "users",
localField: 'assignedTo', localField: "assignedTo",
foreignField: '_id', foreignField: "_id",
as: 'assignedTo', as: "assignedTo",
}, },
}, },
{ {
@@ -185,21 +185,21 @@ export async function searchTasks(params: PageQueryParams, tenantId: string) {
createdAt: 1, createdAt: 1,
createdBy: { createdBy: {
$let: { $let: {
vars: { createdBy: { $arrayElemAt: ['$createdBy', 0] } }, vars: { createdBy: { $arrayElemAt: ["$createdBy", 0] } },
in: { in: {
_id: '$$createdBy._id', _id: "$$createdBy._id",
pid: '$$createdBy.pid', pid: "$$createdBy.pid",
name: '$$createdBy.name', name: "$$createdBy.name",
}, },
}, },
}, },
assignedTo: { assignedTo: {
$let: { $let: {
vars: { assignedTo: { $arrayElemAt: ['$assignedTo', 0] } }, vars: { assignedTo: { $arrayElemAt: ["$assignedTo", 0] } },
in: { in: {
_id: '$$assignedTo._id', _id: "$$assignedTo._id",
pid: '$$assignedTo.pid', pid: "$$assignedTo.pid",
name: '$$assignedTo.name', name: "$$assignedTo.name",
}, },
}, },
}, },
@@ -207,7 +207,7 @@ export async function searchTasks(params: PageQueryParams, tenantId: string) {
}, },
{ {
$facet: { $facet: {
metadata: [{ $count: 'count' }], metadata: [{ $count: "count" }],
data: [ data: [
{ $sort: sortObj }, { $sort: sortObj },
{ $skip: (page - 1) * pageSize }, { $skip: (page - 1) * pageSize },

View File

@@ -1,9 +1,55 @@
import mongoose from 'mongoose'; import mongoose from "mongoose";
type MongoFilter = Record<string, any>; type MongoFilter = Record<string, any>;
function convertValue(value: string) {
if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
return new Date(value);
} else if (!isNaN(Number(value))) {
return Number(value);
} else if (mongoose.Types.ObjectId.isValid(value)) {
return new mongoose.Types.ObjectId(value);
} else if (value === "true") {
return true;
} else if (value === "false") {
return false;
} else if (value === "null") {
return null;
}
return value;
}
function formulaToMongoFilter(formula: string): MongoFilter { function formulaToMongoFilter(formula: string): MongoFilter {
// Split the formula into parts // Check for array syntax first (values in parentheses)
const arrayMatch = formula.match(/([^!<>=]+)([!<>=]*)=\(([^)]+)\)/);
if (arrayMatch) {
const [, field, operator, values] = arrayMatch;
const trimmedField = field.trim();
if (trimmedField === "tenantId") return {};
// Split values by comma and trim each value
const valueArray = values
.split(",")
.map((v) => v.trim().replace(/^['"]|['"]$/g, ""));
// Convert each value to appropriate type
const parsedValues = valueArray.map((value) => convertValue(value));
// If no operator or equals operator, use $in
if (!operator || operator === "=") {
return { [trimmedField]: { $in: parsedValues } };
}
// If not equals operator, use $nin
else if (operator === "!=") {
return { [trimmedField]: { $nin: parsedValues } };
}
// Other operators don't make sense with arrays
throw new Error(`Unsupported operator with array values: ${operator}`);
}
// Original single value processing
const operatorMatch = formula.match(/([^!<>=]+)([!<>=]+)(.+)/); const operatorMatch = formula.match(/([^!<>=]+)([!<>=]+)(.+)/);
if (!operatorMatch) { if (!operatorMatch) {
@@ -12,56 +58,35 @@ function formulaToMongoFilter(formula: string): MongoFilter {
const [, field, operator, value] = operatorMatch; const [, field, operator, value] = operatorMatch;
const trimmedField = field.trim(); const trimmedField = field.trim();
const trimmedValue = value.trim(); const trimmedValue = value.trim().replace(/^['"]|['"]$/g, "");
if (trimmedField === 'tenantId') return {}; if (trimmedField === "tenantId") return {};
// Convert value to appropriate type (date or number if possible) // Convert value to appropriate type (date or number if possible)
let parsedValue: any = trimmedValue; let parsedValue: any = convertValue(trimmedValue);
if (/^\d{4}-\d{2}-\d{2}$/.test(trimmedValue)) {
// Check if it's a date (ISO format)
parsedValue = new Date(trimmedValue);
} else if (!isNaN(Number(trimmedValue))) {
// Check if it's a number
parsedValue = Number(trimmedValue);
} else if (
typeof parsedValue === 'string' &&
mongoose.Types.ObjectId.isValid(parsedValue)
) {
parsedValue = new mongoose.Types.ObjectId(parsedValue);
} else if (parsedValue === 'true') {
parsedValue = true;
} else if (parsedValue === 'false') {
parsedValue = false;
} else if (parsedValue === 'null') {
parsedValue = null;
}
// Convert operator to MongoDB operator // Convert operator to MongoDB operator
switch (operator) { switch (operator) {
case '=': case "=":
return { [trimmedField]: { $eq: parsedValue } }; return { [trimmedField]: { $eq: parsedValue } };
case '!=': case "!=":
return { [trimmedField]: { $ne: parsedValue } }; return { [trimmedField]: { $ne: parsedValue } };
case '>': case ">":
return { [trimmedField]: { $gt: parsedValue } }; return { [trimmedField]: { $gt: parsedValue } };
case '<': case "<":
return { [trimmedField]: { $lt: parsedValue } }; return { [trimmedField]: { $lt: parsedValue } };
case '>=': case ">=":
return { [trimmedField]: { $gte: parsedValue } }; return { [trimmedField]: { $gte: parsedValue } };
case '<=': case "<=":
return { [trimmedField]: { $lte: parsedValue } }; return { [trimmedField]: { $lte: parsedValue } };
default: default:
throw new Error(`Unsupported operator: ${operator}`); throw new Error(`Unsupported operator: ${operator}`);
} }
} }
export function parse(formulas: string[]): MongoFilter { export function parse(formulas: string[]): Array<MongoFilter> {
const parsedQuery: MongoFilter = formulas.reduce((filter, formula) => { const parsedQuery: Array<MongoFilter> = formulas.map((formula) =>
const newFilter = formulaToMongoFilter(formula); formulaToMongoFilter(formula)
return { ...filter, ...newFilter }; );
}, {});
return parsedQuery; return parsedQuery;
} }

View File

@@ -1,12 +1,12 @@
import { AuthenticatedUser } from '../auth'; import { AuthenticatedUser } from "../auth";
import { getFilterObject, getSortObject, PageQueryParams } from '../pagination'; import { getFilterObject, getSortObject, PageQueryParams } from "../pagination";
import { generateId } from '../utils/id'; import { generateId } from "../utils/id";
import { import {
CreateViewInput, CreateViewInput,
UpdateViewInput, UpdateViewInput,
viewFields, viewFields,
viewModel, viewModel,
} from './view.schema'; } from "./view.schema";
export async function createView( export async function createView(
input: CreateViewInput, input: CreateViewInput,
@@ -39,7 +39,7 @@ export async function listViews(
$and: [ $and: [
{ tenantId: user.tenantId }, { tenantId: user.tenantId },
{ createdBy: user.userId }, { createdBy: user.userId },
{ ...filterObj }, ...filterObj,
], ],
}); });
} }