import { defineModel } from '@stacksjs/orm' import { slug } from '@stacksjs/strings' import { schema } from '@stacksjs/validation' export default defineModel({ name: 'Category', table: 'categories', primaryKey: 'id', autoIncrement: true, traits: { useUuid: true, useTimestamps: true, useSearch: { displayable: ['id', 'name', 'description', 'isActive', 'parentCategoryId', 'displayOrder'], searchable: ['name', 'description'], sortable: ['displayOrder', 'createdAt', 'updatedAt'], filterable: ['parentCategoryId', 'isActive'], }, useSeeder: { count: 10, }, useApi: { // Public catalog: anyone may browse, only authenticated callers may // write. Declared explicitly because the trait now defaults BOTH sides to // `auth` — an undeclared read route is how a customer list leaks // (stacksjs/stacks#2224). Behaviour here is unchanged. middleware: { read: [], write: ['auth'] }, uri: 'product-categories', }, observe: true, }, hasMany: ['Product'], belongsToMany: { posts: { model: 'Post', table: 'categorizable_models', foreignKey: 'category_id', relatedKey: 'categorizable_id', pivot: { columns: { categorizable_type: { default: 'posts' }, }, timestamps: true, uniques: [['category_id', 'categorizable_id', 'categorizable_type']], }, }, }, attributes: { name: { order: 1, fillable: true, validation: { rule: schema.string().required().max(50), message: { max: 'Name must have a maximum of 50 characters', }, }, factory: faker => faker.commerce.department(), }, description: { order: 2, fillable: true, validation: { rule: schema.string(), }, factory: faker => faker.commerce.productDescription(), }, slug: { order: 3, fillable: true, validation: { rule: schema.string().required(), }, factory: faker => slug(faker.commerce.department()), }, imageUrl: { order: 3, fillable: true, validation: { rule: schema.string(), }, factory: faker => faker.image.url(), }, isActive: { order: 4, fillable: true, validation: { rule: schema.boolean(), }, factory: () => true, }, parentCategoryId: { order: 5, fillable: true, validation: { rule: schema.string(), }, factory: () => null, // Most categories won't have a parent }, displayOrder: { order: 6, fillable: true, validation: { rule: schema.number().required(), }, factory: faker => faker.number.int({ min: 1, max: 100 }), }, }, dashboard: { highlight: true, }, } as const)