From 9435d5c64c487f50201c539242aea039cf238f41 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Mon, 24 Aug 2026 23:02:47 +0100 Subject: [PATCH] Add rollup statistics functionality to sales schemas This commit enhances the `client`, `listing`, and `marketplace` schemas by introducing rollup statistics and history tracking capabilities. New rollup configurations are added to count various states, such as 'active', 'inactive', and others specific to each schema. The `stats` and `history` static methods are implemented to aggregate data using the newly introduced `aggregateRollups` and `aggregateRollupsHistory` functions, improving data analysis and reporting for sales entities. --- src/database/schemas/sales/client.schema.js | 34 ++++++++++++ src/database/schemas/sales/listing.schema.js | 55 ++++++++++++++++++- .../schemas/sales/marketplace.schema.js | 50 ++++++++++++++++- 3 files changed, 137 insertions(+), 2 deletions(-) diff --git a/src/database/schemas/sales/client.schema.js b/src/database/schemas/sales/client.schema.js index 0fcfce9..5588d5d 100644 --- a/src/database/schemas/sales/client.schema.js +++ b/src/database/schemas/sales/client.schema.js @@ -1,5 +1,6 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; +import { aggregateRollups, aggregateRollupsHistory } from '../../database.js'; const addressSchema = new mongoose.Schema({ building: { required: false, type: String }, @@ -36,4 +37,37 @@ clientSchema.virtual('id').get(function () { clientSchema.set('toJSON', { virtuals: true }); +const rollupConfigs = [ + { + name: 'active', + filter: { active: true }, + rollups: [{ name: 'active', property: 'active', operation: 'count' }], + }, + { + name: 'inactive', + filter: { active: false }, + rollups: [{ name: 'inactive', property: 'active', operation: 'count' }], + }, +]; + +clientSchema.statics.stats = async function () { + const results = await aggregateRollups({ + model: this, + rollupConfigs: rollupConfigs, + }); + + return results; +}; + +clientSchema.statics.history = async function (from, to) { + const results = await aggregateRollupsHistory({ + model: this, + startDate: from, + endDate: to, + rollupConfigs: rollupConfigs, + }); + + return results; +}; + export const clientModel = mongoose.model('client', clientSchema); diff --git a/src/database/schemas/sales/listing.schema.js b/src/database/schemas/sales/listing.schema.js index 3043afc..6b3f08f 100644 --- a/src/database/schemas/sales/listing.schema.js +++ b/src/database/schemas/sales/listing.schema.js @@ -1,6 +1,6 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; -import { editObject, newObject, deleteObject } from '../../database.js'; +import { editObject, newObject, deleteObject, aggregateRollups, aggregateRollupsHistory } from '../../database.js'; const { Schema } = mongoose; const listingSchema = new Schema( @@ -171,4 +171,57 @@ listingSchema.statics.recalculate = async function (listing, user) { } }; +const rollupConfigs = [ + { + name: 'draft', + filter: { 'state.type': 'draft' }, + rollups: [{ name: 'draft', property: 'state.type', operation: 'count' }], + }, + { + name: 'active', + filter: { 'state.type': 'active' }, + rollups: [{ name: 'active', property: 'state.type', operation: 'count' }], + }, + { + name: 'inactive', + filter: { 'state.type': 'inactive' }, + rollups: [{ name: 'inactive', property: 'state.type', operation: 'count' }], + }, + { + name: 'syncing', + filter: { 'state.type': 'syncing' }, + rollups: [{ name: 'syncing', property: 'state.type', operation: 'count' }], + }, + { + name: 'suspended', + filter: { 'state.type': 'suspended' }, + rollups: [{ name: 'suspended', property: 'state.type', operation: 'count' }], + }, + { + name: 'deleted', + filter: { 'state.type': 'deleted' }, + rollups: [{ name: 'deleted', property: 'state.type', operation: 'count' }], + }, +]; + +listingSchema.statics.stats = async function () { + const results = await aggregateRollups({ + model: this, + rollupConfigs: rollupConfigs, + }); + + return results; +}; + +listingSchema.statics.history = async function (from, to) { + const results = await aggregateRollupsHistory({ + model: this, + startDate: from, + endDate: to, + rollupConfigs: rollupConfigs, + }); + + return results; +}; + export const listingModel = mongoose.model('listing', listingSchema); diff --git a/src/database/schemas/sales/marketplace.schema.js b/src/database/schemas/sales/marketplace.schema.js index 954d79d..85c79a1 100644 --- a/src/database/schemas/sales/marketplace.schema.js +++ b/src/database/schemas/sales/marketplace.schema.js @@ -1,5 +1,5 @@ import mongoose from 'mongoose'; -import { editObject } from '../../database.js'; +import { editObject, aggregateRollups, aggregateRollupsHistory } from '../../database.js'; import { generateId } from '../../utils.js'; const marketplaceSchema = new mongoose.Schema( @@ -56,6 +56,54 @@ marketplaceSchema.statics.recalculate = async function (marketplace, user) { }); }; +const rollupConfigs = [ + { + name: 'ready', + filter: { 'state.type': 'ready' }, + rollups: [{ name: 'ready', property: 'state.type', operation: 'count' }], + }, + { + name: 'syncing', + filter: { 'state.type': 'syncing' }, + rollups: [{ name: 'syncing', property: 'state.type', operation: 'count' }], + }, + { + name: 'disconnected', + filter: { 'state.type': 'disconnected' }, + rollups: [{ name: 'disconnected', property: 'state.type', operation: 'count' }], + }, + { + name: 'inactive', + filter: { 'state.type': 'inactive' }, + rollups: [{ name: 'inactive', property: 'state.type', operation: 'count' }], + }, + { + name: 'offline', + filter: { 'state.type': 'offline' }, + rollups: [{ name: 'offline', property: 'state.type', operation: 'count' }], + }, +]; + +marketplaceSchema.statics.stats = async function () { + const results = await aggregateRollups({ + model: this, + rollupConfigs: rollupConfigs, + }); + + return results; +}; + +marketplaceSchema.statics.history = async function (from, to) { + const results = await aggregateRollupsHistory({ + model: this, + startDate: from, + endDate: to, + rollupConfigs: rollupConfigs, + }); + + return results; +}; + marketplaceSchema.set('toJSON', { virtuals: true }); export const marketplaceModel = mongoose.model('marketplace', marketplaceSchema);