'use strict';
const { getPostgresDAL } = require('../db-postgres');
const type = require('../dal').type;
const debug = require('../util/debug');
const { initializeModel } = require('../dal/lib/model-initializer');
const { ConstraintError, DuplicateSlugNameError } = require('../dal/lib/errors');
let TeamSlug = null;
/**
* Initialize the PostgreSQL TeamSlug model
* @param {DataAccessLayer} dal - Optional DAL instance for testing
*/
async function initializeTeamSlugModel(dal = null) {
const activeDAL = dal || await getPostgresDAL();
if (!activeDAL) {
debug.db('PostgreSQL DAL not available, skipping TeamSlug model initialization');
return null;
}
try {
const schema = {
id: type.string().uuid(4),
teamID: type.string().uuid(4).required(true),
slug: type.string().max(255).required(true),
createdOn: type.date().default(() => new Date()),
createdBy: type.string().uuid(4),
name: type.string().max(255)
};
const { model, isNew } = initializeModel({
dal: activeDAL,
baseTable: 'team_slugs',
schema,
camelToSnake: {
teamID: 'team_id',
createdOn: 'created_on',
createdBy: 'created_by'
},
staticMethods: {
getByName
},
instanceMethods: {
qualifiedSave
}
});
TeamSlug = model;
if (!isNew) {
return TeamSlug;
}
debug.db('PostgreSQL TeamSlug model initialized');
return TeamSlug;
} catch (error) {
debug.error('Failed to initialize PostgreSQL TeamSlug model:', error);
return null;
}
}
// Synchronous handle for production use - proxies to the registered model
// Create synchronous handle using the model handle factory
const { createAutoModelHandle } = require('../dal/lib/model-handle');
const TeamSlugHandle = createAutoModelHandle('team_slugs', initializeTeamSlugModel);
/**
* Get the PostgreSQL TeamSlug model (initialize if needed)
* @param {DataAccessLayer} dal - Optional DAL instance for testing
*/
async function getPostgresTeamSlugModel(dal = null) {
TeamSlug = await initializeTeamSlugModel(dal);
return TeamSlug;
}
/**
* Get a team slug by its name field.
*
* @param {string} name - The slug name to look up
* @returns {Promise<TeamSlug|null>} The team slug instance or null if not found
* @static
* @memberof TeamSlug
*/
async function getByName(name) {
try {
return await this.filter({ name }).first();
} catch (error) {
debug.error(`Error getting team slug by name '${name}':`, error);
return null;
}
}
/**
* For team slugs, we don't do automatic de-duplication (like thing-2, thing-3).
* A qualifiedSave is just a regular save, but it translates constraint violations
* into business logic errors that routes can handle.
*
* @returns {Promise<TeamSlug>} This slug instance
* @throws {DuplicateSlugNameError} If a slug with this name already exists
* @memberof TeamSlug
* @instance
*/
async function qualifiedSave() {
if (!this.createdOn) {
this.createdOn = new Date();
}
try {
return await this.save();
} catch (error) {
// Translate database constraint violations into business logic errors
// This keeps route handlers from needing to know about constraint names
if (error instanceof ConstraintError && error.constraint === 'team_slugs_slug_unique') {
throw new DuplicateSlugNameError(
`Team slug '${this.name}' already exists`,
this.name,
'team_slugs'
);
}
throw error;
}
}
module.exports = TeamSlugHandle;
// Export factory function for fixtures and tests
module.exports.initializeModel = initializeTeamSlugModel;
module.exports.getPostgresTeamSlugModel = getPostgresTeamSlugModel;