Compare commits
2 Commits
b0943f3fa0
...
8974d1e9da
| Author | SHA1 | Date | |
|---|---|---|---|
| 8974d1e9da | |||
| 0470f62e05 |
@ -657,21 +657,26 @@ export const listPropertyValues = async ({ model, property, filter = {}, search
|
|||||||
return await model.aggregate(aggregateCommand);
|
return await model.aggregate(aggregateCommand);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getEmbeddedSchemaType(path) {
|
||||||
|
if (!path) return null;
|
||||||
|
return path.embeddedSchemaType ?? path.$embeddedSchemaType ?? path.caster ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
function getObjectRefPathInfo(model, property) {
|
function getObjectRefPathInfo(model, property) {
|
||||||
if (!model?.schema || !property) return null;
|
if (!model?.schema || !property) return null;
|
||||||
|
|
||||||
const path = model.schema.path(property);
|
const path = model.schema.path(property);
|
||||||
if (!path) return null;
|
if (!path) return null;
|
||||||
|
|
||||||
const schemaType = path.instance === 'Array' ? path.caster : path;
|
const schemaType = path.instance === 'Array' ? getEmbeddedSchemaType(path) : path;
|
||||||
if (!schemaType) return null;
|
if (!schemaType) return null;
|
||||||
|
|
||||||
const instance = schemaType.instance;
|
const instance = schemaType.instance;
|
||||||
if (instance !== 'ObjectID' && instance !== 'ObjectId') return null;
|
if (instance !== 'ObjectID' && instance !== 'ObjectId') return null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ref: schemaType.options?.ref,
|
ref: schemaType.options?.ref ?? path.options?.ref,
|
||||||
refPath: schemaType.options?.refPath,
|
refPath: schemaType.options?.refPath ?? path.options?.refPath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,28 +695,52 @@ function inferTypeFieldFromRefFunction(refFn) {
|
|||||||
return matches.find((name) => name.endsWith('Type') || name === 'type') || matches[0] || null;
|
return matches.find((name) => name.endsWith('Type') || name === 'type') || matches[0] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getArrayParentPaths(model, property) {
|
function getArrayUnwindPaths(model, property) {
|
||||||
if (!model?.schema || !property?.includes('.')) return [];
|
if (!model?.schema || !property) return [];
|
||||||
|
|
||||||
const parents = [];
|
const paths = [];
|
||||||
const parts = property.split('.');
|
const parts = property.split('.');
|
||||||
for (let i = 1; i < parts.length; i++) {
|
for (let i = 1; i < parts.length; i++) {
|
||||||
const parentPath = parts.slice(0, i).join('.');
|
const parentPath = parts.slice(0, i).join('.');
|
||||||
const parentSchemaPath = model.schema.path(parentPath);
|
const parentSchemaPath = model.schema.path(parentPath);
|
||||||
if (parentSchemaPath?.instance === 'Array') {
|
if (parentSchemaPath?.instance === 'Array') {
|
||||||
parents.push(parentPath);
|
paths.push(parentPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parents;
|
|
||||||
|
const path = model.schema.path(property);
|
||||||
|
if (path?.instance === 'Array') {
|
||||||
|
paths.push(property);
|
||||||
|
}
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
function flattenRefIds(ids) {
|
||||||
|
const flattened = [];
|
||||||
|
const visit = (value) => {
|
||||||
|
if (value == null) return;
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value.forEach(visit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
typeof value === 'object' &&
|
||||||
|
!(value instanceof mongoose.Types.ObjectId) &&
|
||||||
|
!(value instanceof Date) &&
|
||||||
|
value._id != null
|
||||||
|
) {
|
||||||
|
visit(value._id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flattened.push(value);
|
||||||
|
};
|
||||||
|
visit(ids);
|
||||||
|
return flattened;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchBasicObjectsByIds(refName, ids) {
|
async function fetchBasicObjectsByIds(refName, ids) {
|
||||||
const uniqueIds = [
|
const uniqueIds = [
|
||||||
...new Map(
|
...new Map(flattenRefIds(ids).map((id) => [id.toString(), id])).values(),
|
||||||
(ids || [])
|
|
||||||
.filter((id) => id != null)
|
|
||||||
.map((id) => [id.toString(), id])
|
|
||||||
).values(),
|
|
||||||
];
|
];
|
||||||
if (uniqueIds.length === 0) return [];
|
if (uniqueIds.length === 0) return [];
|
||||||
|
|
||||||
@ -762,10 +791,10 @@ export const getPropertyValues = async ({ model, property, filter = {} }) => {
|
|||||||
pipeline.push({ $match: convertedFilter });
|
pipeline.push({ $match: convertedFilter });
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const parentPath of getArrayParentPaths(model, property)) {
|
for (const unwindPath of getArrayUnwindPaths(model, property)) {
|
||||||
pipeline.push({
|
pipeline.push({
|
||||||
$unwind: {
|
$unwind: {
|
||||||
path: `$${parentPath}`,
|
path: `$${unwindPath}`,
|
||||||
preserveNullAndEmptyArrays: false,
|
preserveNullAndEmptyArrays: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -803,6 +832,28 @@ export const getPropertyValues = async ({ model, property, filter = {} }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hasFixedRef) {
|
if (hasFixedRef) {
|
||||||
|
const unwindPaths = getArrayUnwindPaths(model, property);
|
||||||
|
if (unwindPaths.length > 0) {
|
||||||
|
const pipeline = [];
|
||||||
|
if (Object.keys(convertedFilter).length > 0) {
|
||||||
|
pipeline.push({ $match: convertedFilter });
|
||||||
|
}
|
||||||
|
for (const unwindPath of unwindPaths) {
|
||||||
|
pipeline.push({
|
||||||
|
$unwind: {
|
||||||
|
path: `$${unwindPath}`,
|
||||||
|
preserveNullAndEmptyArrays: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
pipeline.push(
|
||||||
|
{ $match: { [property]: { $ne: null } } },
|
||||||
|
{ $group: { _id: `$${property}` } }
|
||||||
|
);
|
||||||
|
const ids = (await model.aggregate(pipeline)).map((row) => row._id);
|
||||||
|
return fetchBasicObjectsByIds(pathInfo.ref, ids);
|
||||||
|
}
|
||||||
|
|
||||||
const ids = await model.distinct(property, convertedFilter);
|
const ids = await model.distinct(property, convertedFilter);
|
||||||
return fetchBasicObjectsByIds(pathInfo.ref, ids);
|
return fetchBasicObjectsByIds(pathInfo.ref, ids);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,12 @@ const documentJobSchema = new Schema(
|
|||||||
ref: 'documentPrinter',
|
ref: 'documentPrinter',
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
quantity: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
default: 1,
|
||||||
|
min: 1,
|
||||||
|
},
|
||||||
content: {
|
content: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ const router = express.Router();
|
|||||||
|
|
||||||
const listAllowedFilters = [
|
const listAllowedFilters = [
|
||||||
'name',
|
'name',
|
||||||
|
'quantity',
|
||||||
'width',
|
'width',
|
||||||
'height',
|
'height',
|
||||||
'state',
|
'state',
|
||||||
@ -14,7 +15,7 @@ const listAllowedFilters = [
|
|||||||
'updatedAt',
|
'updatedAt',
|
||||||
'_reference',
|
'_reference',
|
||||||
];
|
];
|
||||||
const listAllowedSorters = ['name', 'state', 'createdAt', 'updatedAt'];
|
const listAllowedSorters = ['name', 'quantity', 'state', 'createdAt', 'updatedAt'];
|
||||||
const propertiesAllowedFilters = [];
|
const propertiesAllowedFilters = [];
|
||||||
import {
|
import {
|
||||||
listDocumentJobsRouteHandler,
|
listDocumentJobsRouteHandler,
|
||||||
|
|||||||
@ -113,6 +113,9 @@ export const editDocumentJobRouteHandler = async (req, res) => {
|
|||||||
logger.trace(`Document Job with ID: ${id}`);
|
logger.trace(`Document Job with ID: ${id}`);
|
||||||
|
|
||||||
const updateData = {};
|
const updateData = {};
|
||||||
|
if (req.body.quantity != null) {
|
||||||
|
updateData.quantity = req.body.quantity;
|
||||||
|
}
|
||||||
// Create audit log before updating
|
// Create audit log before updating
|
||||||
const result = await editObject({
|
const result = await editObject({
|
||||||
model: documentJobModel,
|
model: documentJobModel,
|
||||||
@ -142,6 +145,7 @@ export const newDocumentJobRouteHandler = async (req, res) => {
|
|||||||
objectType: req.body.objectType,
|
objectType: req.body.objectType,
|
||||||
object: req.body.object,
|
object: req.body.object,
|
||||||
content: req.body.content,
|
content: req.body.content,
|
||||||
|
quantity: req.body.quantity ?? 1,
|
||||||
state: { type: 'draft' },
|
state: { type: 'draft' },
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
|
|||||||
39
src/utils.js
39
src/utils.js
@ -93,8 +93,19 @@ function getBaseProperty(property) {
|
|||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isObjectIdSchemaType(path) {
|
function getEmbeddedSchemaType(path) {
|
||||||
return path?.instance === 'ObjectId' || path?.instance === 'ObjectID';
|
if (!path) return null;
|
||||||
|
return path.embeddedSchemaType ?? path.$embeddedSchemaType ?? path.caster ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getObjectIdSchemaTypeFromPath(path) {
|
||||||
|
if (!path) return null;
|
||||||
|
const schemaType = path.instance === 'Array' ? getEmbeddedSchemaType(path) : path;
|
||||||
|
if (!schemaType) return null;
|
||||||
|
if (schemaType.instance === 'ObjectId' || schemaType.instance === 'ObjectID') {
|
||||||
|
return schemaType;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSchemaPathFromModels(property, model = null) {
|
function getSchemaPathFromModels(property, model = null) {
|
||||||
@ -112,12 +123,14 @@ function getFilterFieldKind(property, model = null) {
|
|||||||
const inspectPath = (path) => {
|
const inspectPath = (path) => {
|
||||||
if (!path) return null;
|
if (!path) return null;
|
||||||
|
|
||||||
if (isObjectIdPath(property) || isObjectIdSchemaType(path)) {
|
const objectIdType = getObjectIdSchemaTypeFromPath(path);
|
||||||
if (property.endsWith('._id') && property !== '_id' && path.options?.ref) {
|
if (isObjectIdPath(property) || objectIdType) {
|
||||||
|
const ref = objectIdType?.options?.ref ?? path.options?.ref;
|
||||||
|
if (property.endsWith('._id') && property !== '_id' && ref) {
|
||||||
return { kind: 'objectId', property: baseProperty };
|
return { kind: 'objectId', property: baseProperty };
|
||||||
}
|
}
|
||||||
if (path.options?.ref) {
|
if (ref) {
|
||||||
return { kind: 'objectRef', property: baseProperty, ref: path.options.ref };
|
return { kind: 'objectRef', property: baseProperty, ref };
|
||||||
}
|
}
|
||||||
return { kind: 'objectId', property: baseProperty };
|
return { kind: 'objectId', property: baseProperty };
|
||||||
}
|
}
|
||||||
@ -162,7 +175,8 @@ function buildRegexOp(pattern, useOptions = true) {
|
|||||||
function getSchemaRefName(property, model = null) {
|
function getSchemaRefName(property, model = null) {
|
||||||
const baseProperty = getBaseProperty(property);
|
const baseProperty = getBaseProperty(property);
|
||||||
const path = model?.schema?.path(baseProperty) ?? getSchemaPathFromModels(baseProperty);
|
const path = model?.schema?.path(baseProperty) ?? getSchemaPathFromModels(baseProperty);
|
||||||
return path?.options?.ref ?? path?.caster?.options?.ref ?? null;
|
const embeddedType = getEmbeddedSchemaType(path);
|
||||||
|
return path?.options?.ref ?? embeddedType?.options?.ref ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRefModelEntryFromSchemaRef(refName) {
|
function getRefModelEntryFromSchemaRef(refName) {
|
||||||
@ -1264,6 +1278,7 @@ function filterDistributeKeys(value, keys = DISTRIBUTE_KEYS) {
|
|||||||
result[key] = val;
|
result[key] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log('filterDistributeKeys', result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1276,11 +1291,11 @@ async function distributeStats(value, type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function distributeNew(value, type) {
|
async function distributeNew(value, type) {
|
||||||
await natsServer.publish(`${type}s.new`, filterDistributeKeys(value));
|
await natsServer.publish(`${type}s.new`, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function distributeDelete(value, type) {
|
async function distributeDelete(value, type) {
|
||||||
await natsServer.publish(`${type}s.delete`, filterDistributeKeys(value));
|
await natsServer.publish(`${type}s.delete`, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReferenceId(value) {
|
function getReferenceId(value) {
|
||||||
@ -1589,7 +1604,11 @@ function normalizeFilterQuery(query = {}) {
|
|||||||
|
|
||||||
// qs turns `order._id=` into `{ order: { _id } }`. Lift it so it can be parsed
|
// qs turns `order._id=` into `{ order: { _id } }`. Lift it so it can be parsed
|
||||||
// as the order object filter instead of a nested query object.
|
// as the order object filter instead of a nested query object.
|
||||||
if (queryClean.order && typeof queryClean.order === 'object' && !Array.isArray(queryClean.order)) {
|
if (
|
||||||
|
queryClean.order &&
|
||||||
|
typeof queryClean.order === 'object' &&
|
||||||
|
!Array.isArray(queryClean.order)
|
||||||
|
) {
|
||||||
if (queryClean.order._id !== undefined) {
|
if (queryClean.order._id !== undefined) {
|
||||||
queryClean['order._id'] = queryClean.order._id;
|
queryClean['order._id'] = queryClean.order._id;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user