diff --git a/src/database/schemas/production/job.schema.js b/src/database/schemas/production/job.schema.js index 71a2f02..3070e62 100644 --- a/src/database/schemas/production/job.schema.js +++ b/src/database/schemas/production/job.schema.js @@ -10,10 +10,12 @@ import { deleteObject, } from '../../database.js'; import { subJobModel } from './subjob.schema.js'; +import { gcodeFileModel } from './gcodefile.schema.js'; const jobSchema = new mongoose.Schema( { _reference: { type: String, default: () => generateId()() }, + name: { type: String, required: false }, state: { type: { required: true, type: String }, progress: { type: Number, required: false }, @@ -40,7 +42,7 @@ const jobSchema = new mongoose.Schema( { timestamps: true } ); -jobSchema.index({ 'state.type': 'text' }); +jobSchema.index({ name: 'text', 'state.type': 'text' }); const rollupConfigs = [ { @@ -94,6 +96,19 @@ jobSchema.statics.history = async function (from, to) { const normalizeId = (value) => value?._id ?? value; +const gcodeFileNameFrom = async (gcodeFileRef) => { + if (gcodeFileRef && typeof gcodeFileRef === 'object' && typeof gcodeFileRef.name === 'string') { + const populatedName = gcodeFileRef.name.trim(); + if (populatedName) return populatedName; + } + + const gcodeFileId = normalizeId(gcodeFileRef); + if (!gcodeFileId) return ''; + + const gcodeFile = await gcodeFileModel.findById(gcodeFileId).select('name').lean(); + return typeof gcodeFile?.name === 'string' ? gcodeFile.name.trim() : ''; +}; + jobSchema.statics.recalculate = async function (job, user) { const jobId = job._id || job; if (!jobId || job?.state?.type !== 'draft') { @@ -103,6 +118,25 @@ jobSchema.statics.recalculate = async function (job, user) { const quantity = job.quantity || 1; const printers = (job.printers || []).map((printer) => normalizeId(printer)); const gcodeFile = normalizeId(job.gcodeFile); + const gcodeFileName = await gcodeFileNameFrom(job.gcodeFile); + const jobName = gcodeFileName ? `${quantity} ${gcodeFileName}` : null; + const subJobName = gcodeFileName || null; + + if ((job.name ?? null) !== jobName) { + const jobResult = await editObject({ + model: this, + id: jobId, + updateData: { + name: jobName, + updatedAt: new Date(), + }, + user, + recalculate: false, + }); + if (jobResult?.error) { + throw jobResult; + } + } const existingSubJobs = await listObjects({ model: subJobModel, @@ -127,6 +161,7 @@ jobSchema.statics.recalculate = async function (job, user) { const printer = printers[printerCount]; const subJobUpdateData = { updatedAt: new Date(), + name: subJobName, printer, gcodeFile, number: subJobNumber, @@ -188,3 +223,24 @@ jobSchema.virtual('id').get(function () { jobSchema.set('toJSON', { virtuals: true }); export const jobModel = mongoose.model('job', jobSchema); + +const replaceTextIndex = async (model, field) => { + try { + const indexes = await model.collection.indexes(); + const textIndex = indexes.find((index) => Object.values(index.key || {}).includes('text')); + const weights = textIndex?.weights; + const includesField = weights != null && Object.prototype.hasOwnProperty.call(weights, field); + if (textIndex && !includesField) { + await model.collection.dropIndex(textIndex.name); + } + await model.createIndexes(); + } catch { + // Collection may not exist until Mongo is connected. + } +}; + +if (mongoose.connection.readyState === 1) { + replaceTextIndex(jobModel, 'name'); +} else { + mongoose.connection.once('open', () => replaceTextIndex(jobModel, 'name')); +} diff --git a/src/database/schemas/production/subjob.schema.js b/src/database/schemas/production/subjob.schema.js index 02d2522..3058393 100644 --- a/src/database/schemas/production/subjob.schema.js +++ b/src/database/schemas/production/subjob.schema.js @@ -4,6 +4,7 @@ const { Schema } = mongoose; const subJobSchema = new mongoose.Schema({ _reference: { type: String, default: () => generateId()() }, + name: { type: String, required: false }, printer: { type: Schema.Types.ObjectId, ref: 'printer', @@ -43,7 +44,7 @@ const subJobSchema = new mongoose.Schema({ finishedAt: { required: false, type: Date, default: null }, }); -subJobSchema.index({ moonrakerJobId: 'text', 'state.type': 'text' }); +subJobSchema.index({ name: 'text', moonrakerJobId: 'text', 'state.type': 'text' }); subJobSchema.virtual('id').get(function () { return this._id; @@ -52,3 +53,24 @@ subJobSchema.virtual('id').get(function () { subJobSchema.set('toJSON', { virtuals: true }); export const subJobModel = mongoose.model('subJob', subJobSchema); + +const replaceTextIndex = async (model, field) => { + try { + const indexes = await model.collection.indexes(); + const textIndex = indexes.find((index) => Object.values(index.key || {}).includes('text')); + const weights = textIndex?.weights; + const includesField = weights != null && Object.prototype.hasOwnProperty.call(weights, field); + if (textIndex && !includesField) { + await model.collection.dropIndex(textIndex.name); + } + await model.createIndexes(); + } catch { + // Collection may not exist until Mongo is connected. + } +}; + +if (mongoose.connection.readyState === 1) { + replaceTextIndex(subJobModel, 'name'); +} else { + mongoose.connection.once('open', () => replaceTextIndex(subJobModel, 'name')); +}