diff --git a/.eslintrc.json b/.eslintrc.json index ec7da8d..fe664dc 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -24,6 +24,7 @@ "rules": { "@typescript-eslint/lines-between-class-members": "off", "no-underscore-dangle": "off", - "import/prefer-default-export": "off" + "import/prefer-default-export": "off", + "max-len": ["warn", 120] } } diff --git a/src/@types/Entities.ts b/src/@types/Entities.ts index 06aa4c6..47f9fc3 100644 --- a/src/@types/Entities.ts +++ b/src/@types/Entities.ts @@ -6,12 +6,23 @@ import { export type Entity = z.infer; -export type User = z.infer; +export type User = Omit, 'company'> & { + company: string | Record; +}; -export type Company = z.infer; +export type Company = Omit, 'employees' | 'assets' | 'units'> & { + employees: string[] | Record[]; + assets: string[] | Record[]; + units: string[] | Record[]; +}; -export type Unit = z.infer; +export type Unit = Omit, 'assets' | 'owner'> & { + assets: string[] | Record[]; + owner: string | Record; +}; -export type Asset = z.infer; +export type Asset = Omit, 'owner'> & { + owner: string | Record; +}; export type Archive = z.infer; diff --git a/src/database/models/AssetModel.ts b/src/database/models/AssetModel.ts deleted file mode 100644 index 44ff06c..0000000 --- a/src/database/models/AssetModel.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Asset } from '../../@types/Entities'; -import { IAssetModel } from '../../interfaces/IAssetModel'; -import assetSchema from '../schemas/assetSchema'; -import Model from './Model'; - -class AssetModel extends Model implements IAssetModel { - protected _populate = 'owner'; - - constructor() { - super('Asset', assetSchema); - } -} - -export default AssetModel; diff --git a/src/database/models/index.ts b/src/database/models/index.ts new file mode 100644 index 0000000..d513f8d --- /dev/null +++ b/src/database/models/index.ts @@ -0,0 +1,12 @@ +import { model } from 'mongoose'; +import archiveSchema from '../schemas/archiveSchema'; +import assetSchema from '../schemas/assetSchema'; +import companySchema from '../schemas/companySchema'; +import unitSchema from '../schemas/unitSchema'; +import userSchema from '../schemas/userSchema'; + +export const User = model('User', userSchema); +export const Asset = model('Asset', assetSchema); +export const Company = model('Company', companySchema); +export const Unit = model('Unit', unitSchema); +export const Archive = model('Archive', archiveSchema); diff --git a/src/database/schemas/assetSchema.ts b/src/database/schemas/assetSchema.ts index af7dcf9..7bdb4de 100644 --- a/src/database/schemas/assetSchema.ts +++ b/src/database/schemas/assetSchema.ts @@ -1,11 +1,7 @@ -import { ObjectId, Schema } from 'mongoose'; +import { Schema } from 'mongoose'; import { Asset } from '../../@types/Entities'; -type SchemaCompatibleAsset = Omit & { - owner: ObjectId; -}; - -const assetSchema = new Schema({ +const assetSchema = new Schema({ name: { type: String, require: [true, 'Asset name field is required.'], diff --git a/src/database/schemas/companySchema.ts b/src/database/schemas/companySchema.ts index 7f51eba..9905a72 100644 --- a/src/database/schemas/companySchema.ts +++ b/src/database/schemas/companySchema.ts @@ -1,13 +1,7 @@ -import { ObjectId, Schema } from 'mongoose'; +import { Schema } from 'mongoose'; import { Company } from '../../@types/Entities'; -type SchemaCompatibleCompany = Omit & { - assets: ObjectId[]; - employees: ObjectId[]; - units: ObjectId[]; -}; - -const companySchema = new Schema({ +const companySchema = new Schema({ name: { type: String, required: [true, 'Company name field is required.'], diff --git a/src/database/schemas/unitSchema.ts b/src/database/schemas/unitSchema.ts index 628c42b..3389ddc 100644 --- a/src/database/schemas/unitSchema.ts +++ b/src/database/schemas/unitSchema.ts @@ -1,12 +1,7 @@ -import { ObjectId, Schema } from 'mongoose'; +import { Schema } from 'mongoose'; import { Unit } from '../../@types/Entities'; -type SchemaCompatibleUnit = Omit & { - assets: ObjectId[]; - owner: ObjectId; -}; - -const unitSchema = new Schema({ +const unitSchema = new Schema({ name: { type: String, required: [true, 'Unit name field is required.'], diff --git a/src/database/schemas/userSchema.ts b/src/database/schemas/userSchema.ts index 4cc4f03..18a91fd 100644 --- a/src/database/schemas/userSchema.ts +++ b/src/database/schemas/userSchema.ts @@ -1,11 +1,7 @@ -import { ObjectId, Schema } from 'mongoose'; +import { Schema } from 'mongoose'; import { User } from '../../@types/Entities'; -type SchemaCompatibleUser = Omit & { - company: ObjectId; -}; - -const userSchema = new Schema({ +const userSchema = new Schema({ name: { type: String, required: [true, 'User name is required.'], diff --git a/src/database/seeders/index.ts b/src/database/seeders/index.ts index 90e1a8d..1da435e 100644 --- a/src/database/seeders/index.ts +++ b/src/database/seeders/index.ts @@ -1,34 +1,28 @@ /* eslint-disable no-console */ -import AssetModel from '../models/AssetModel'; -import CompanyModel from '../models/CompanyModel'; -import UnitModel from '../models/UnitModel'; -import UserModel from '../models/UserModel'; import assets from './Assets'; import companies from './Companies'; import units from './Units'; import users from './Users'; import { connect, disconnect, MONGO_URI_DEV } from '..'; +import { + Asset, Company, User, Unit, +} from '../models'; const seed = async (mongoURI = MONGO_URI_DEV) => { - const userModel = new UserModel(); - const companyModel = new CompanyModel(); - const assetModel = new AssetModel(); - const unitModel = new UnitModel(); - try { await connect(mongoURI); console.log('Seeding users collection.'); - await userModel.seed(users); + await User.insertMany(users); console.log('Seeding companies collection.'); - await companyModel.seed(companies); + await Company.insertMany(companies); console.log('Seeding assets collection.'); - await assetModel.seed(assets); + await Asset.insertMany(assets); console.log('Seeding units collection.'); - await unitModel.seed(units); + await Unit.insertMany(units); console.log('Database seeding completed successfully.'); await disconnect(); diff --git a/src/models/AssetModel.ts b/src/models/AssetModel.ts new file mode 100644 index 0000000..0a73aff --- /dev/null +++ b/src/models/AssetModel.ts @@ -0,0 +1,14 @@ +import { Asset as AssetType } from '../@types/Entities'; +import { IAssetModel } from '../interfaces/IAssetModel'; +import Model from './Model'; +import { Asset } from '../database/models'; + +class AssetModel extends Model implements IAssetModel { + protected _populate = 'owner'; + + constructor() { + super(Asset); + } +} + +export default AssetModel; diff --git a/src/database/models/CompanyModel.ts b/src/models/CompanyModel.ts similarity index 67% rename from src/database/models/CompanyModel.ts rename to src/models/CompanyModel.ts index 40dd061..a20335e 100644 --- a/src/database/models/CompanyModel.ts +++ b/src/models/CompanyModel.ts @@ -1,16 +1,16 @@ -import { Company } from '../../@types/Entities'; -import { ICompanyModel } from '../../interfaces/ICompanyModel'; -import companySchema from '../schemas/companySchema'; +import { Company as CompanyType } from '../@types/Entities'; +import { Company } from '../database/models'; +import { ICompanyModel } from '../interfaces/ICompanyModel'; import Model from './Model'; -class CompanyModel extends Model implements ICompanyModel { +class CompanyModel extends Model implements ICompanyModel { protected _populate = 'employees assets units'; constructor() { - super('Company', companySchema); + super(Company); } - async editEmployeeList(id: string, employeeId: string, add: boolean): Promise { + async editEmployeeList(id: string, employeeId: string, add: boolean): Promise { const edited = add ? await this._model.findByIdAndUpdate(id, { $push: { employees: employeeId }, @@ -19,10 +19,10 @@ class CompanyModel extends Model implements ICompanyModel { $pull: { employees: employeeId }, }, { new: true }); - return edited?.toObject() as Company; + return edited?.toObject() as CompanyType; } - async editAssetList(id: string, assetId: string, add: boolean): Promise { + async editAssetList(id: string, assetId: string, add: boolean): Promise { const edited = add ? await this._model.findByIdAndUpdate(id, { $push: { assets: assetId }, @@ -31,10 +31,10 @@ class CompanyModel extends Model implements ICompanyModel { $pull: { assets: assetId }, }, { new: true }); - return edited?.toObject() as Company; + return edited?.toObject() as CompanyType; } - async editUnitList(id: string, unitId: string, add: boolean): Promise { + async editUnitList(id: string, unitId: string, add: boolean): Promise { const edited = add ? await this._model.findByIdAndUpdate(id, { $push: { units: unitId }, @@ -43,7 +43,7 @@ class CompanyModel extends Model implements ICompanyModel { $pull: { units: unitId }, }, { new: true }); - return edited?.toObject() as Company; + return edited?.toObject() as CompanyType; } } diff --git a/src/database/models/Model.ts b/src/models/Model.ts similarity index 68% rename from src/database/models/Model.ts rename to src/models/Model.ts index 0013dec..b50f909 100644 --- a/src/database/models/Model.ts +++ b/src/models/Model.ts @@ -1,16 +1,14 @@ -import { model, Schema } from 'mongoose'; -import { IModel } from '../../interfaces/IModel'; -import { Entity, Archive } from '../../@types/Entities'; -import archiveSchema from '../schemas/archiveSchema'; +import { Model as MongoModel } from 'mongoose'; +import { IModel } from '../interfaces/IModel'; +import { Entity, Archive as ArchiveType } from '../@types/Entities'; +import { Archive } from '../database/models'; abstract class Model implements IModel { protected abstract _populate: string; - private _archive; protected _model; - constructor(entityName: string, schema: Schema) { - this._model = model(entityName, schema); - this._archive = model('Archive', archiveSchema); + constructor(model: MongoModel) { + this._model = model; } async createOne(object: T): Promise { @@ -51,20 +49,15 @@ abstract class Model implements IModel { // This saves the object in an archive that is only accessible by the database admins. // With this, data is not lost forever and can be consulted if necessary. - const archived: Archive = { + const archived: ArchiveType = { collectionName: this._model.collection.collectionName, document: deleted, }; - await this._archive.create(archived); + await Archive.create(archived); return deleted as T; } - - async seed(objects: T[], reset = true): Promise { - if (reset) await this._model.deleteMany(); - await this._model.insertMany(objects); - } } export default Model; diff --git a/src/database/models/UnitModel.ts b/src/models/UnitModel.ts similarity index 57% rename from src/database/models/UnitModel.ts rename to src/models/UnitModel.ts index d8667de..498caa9 100644 --- a/src/database/models/UnitModel.ts +++ b/src/models/UnitModel.ts @@ -1,16 +1,16 @@ -import { Unit } from '../../@types/Entities'; -import { IUnitModel } from '../../interfaces/IUnitModel'; -import unitSchema from '../schemas/unitSchema'; +import { Unit as UnitType } from '../@types/Entities'; +import { IUnitModel } from '../interfaces/IUnitModel'; import Model from './Model'; +import { Unit } from '../database/models'; -class UnitModel extends Model implements IUnitModel { +class UnitModel extends Model implements IUnitModel { protected _populate = 'owner assets'; constructor() { - super('Unit', unitSchema); + super(Unit); } - async editAssetList(id: string, assetId: string, add: boolean): Promise { + async editAssetList(id: string, assetId: string, add: boolean): Promise { const edited = add ? await this._model.findByIdAndUpdate(id, { $push: { assets: assetId }, @@ -19,7 +19,7 @@ class UnitModel extends Model implements IUnitModel { $pull: { assets: assetId }, }, { new: true }); - return edited?.toObject() as Unit; + return edited?.toObject() as UnitType; } } diff --git a/src/database/models/UserModel.ts b/src/models/UserModel.ts similarity index 57% rename from src/database/models/UserModel.ts rename to src/models/UserModel.ts index 629e7a4..818a0d2 100644 --- a/src/database/models/UserModel.ts +++ b/src/models/UserModel.ts @@ -1,19 +1,19 @@ -import { User } from '../../@types/Entities'; -import { IUserModel } from '../../interfaces/IUserModel'; -import userSchema from '../schemas/userSchema'; +import { User as UserType } from '../@types/Entities'; +import { IUserModel } from '../interfaces/IUserModel'; import Model from './Model'; +import { User } from '../database/models'; -class UserModel extends Model implements IUserModel { +class UserModel extends Model implements IUserModel { protected _populate = 'company'; constructor() { - super('User', userSchema); + super(User); } // Override for deleting the user password. - async createOne(user: User): Promise { + async createOne(user: UserType): Promise { const created = await (await this._model.create(user)).toObject(); delete created.password; - return created as User; + return created as UserType; } /** @@ -21,13 +21,13 @@ class UserModel extends Model implements IUserModel { * @param email The user's email. * @returns The user with the passed email. Null if no user found. */ - async findByEmail(email: string, login = false): Promise { + async findByEmail(email: string, login = false): Promise { const select = login ? '+password' : ''; const found = await this._model.findOne({ email }) .populate(this._populate) .select(select); - return found as User | null; + return found as UserType | null; } } diff --git a/src/services/AssetService.ts b/src/services/AssetService.ts index 5532524..41db511 100644 --- a/src/services/AssetService.ts +++ b/src/services/AssetService.ts @@ -1,6 +1,6 @@ import { AssetStatus } from '../@types/AssetStatus'; import { Asset } from '../@types/Entities'; -import AssetModel from '../database/models/AssetModel'; +import AssetModel from '../models/AssetModel'; import Service from './Service'; class AssetService extends Service {