diff --git a/README.md b/README.md index 8042bcb..ef93125 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ docker-compose down . ├── .build # Project (TypeScript) build directory └── src # Source files + ├── constants # Constant values ├── models # Database models ├── routes # API endpoints └── scripts # Project scripts @@ -143,9 +144,16 @@ This section includes the issues, changes & improvements I've made, with the tho > The `eslint` config allows to enforce the desired code style among all the contributors. - Issues in the `src` directory: - Unused imports. (e.g. unused `lodash` import in the `src/scripts/seed.ts`) + - Wrong values passed to the database models to be created based on the provided database model schemas. + (e.g. `name`, `start_date`, `check_date`, `divisa`, `Crypto_price_start` & `Crypto_price_check` fields + for the `Simulator` model in the `src/scripts/seed.ts` file) - Using `var` to define variables. > This way the variable would be defined/redefined globally which could cause problems. > Instead of `var`, it's best to use `let` or `const`. + - Database models weren't typed. + > I added the missing interfaces that can be modified easily if needed. + - Database model fields were all optional & lacked the information about other required validations. + - Database model fields lacked consistency. (e.g. some used `snake-case` format & some `camel-case` such as `dateRecorded` in the `Simulator` model) ### Improvements @@ -164,6 +172,12 @@ This section includes the issues, changes & improvements I've made, with the tho > for this purpose, I used `imports` property in `package.json` to avoid using unnecessary third-party application, > which improves both the startup time and security, due to the fact that `Node.js` will only apply these path aliases to the current package, > meaning no installed dependency can use these path aliases (which could cause security issues as well) + - Added the `src/models/index.ts` file to provide easier & cleaner access to all database models + throughout the entire project. + - Added the `src/constants` directory to move all constant values there instead of being scattered all over the project. + > This ensures that the project is using the same consistent values everywhere. + > `MODEL` & `COLLECTION` constants are also added, due to the fact that they can be useful in scenarios such as `$lookup` aggregation stages. + > Also In case of need to change the said values, it just needs to be updated in one places only. diff --git a/src/constants/database/index.ts b/src/constants/database/index.ts new file mode 100644 index 0000000..58c4e29 --- /dev/null +++ b/src/constants/database/index.ts @@ -0,0 +1,2 @@ +export * from "./models.js"; +export * from "./timestamps.js"; diff --git a/src/constants/database/models.ts b/src/constants/database/models.ts new file mode 100644 index 0000000..fc8ef4e --- /dev/null +++ b/src/constants/database/models.ts @@ -0,0 +1,11 @@ +export enum MODEL { + FAVORITE = "Favorite", + PROFILE = "Profile", + SIMULATOR = "Simulator", +} + +export enum COLLECTION { + FAVORITE = "favorites", + PROFILE = "profiles", + SIMULATOR = "simulators", +} diff --git a/src/constants/database/timestamps.ts b/src/constants/database/timestamps.ts new file mode 100644 index 0000000..ed0d0df --- /dev/null +++ b/src/constants/database/timestamps.ts @@ -0,0 +1,16 @@ +import type { SchemaTimestampsConfig } from "mongoose"; + +export enum TIMESTAMP { + CREATED_AT = "created_at", + UPDATED_AT = "updated_at", +} + +export const TIMESTAMPS: SchemaTimestampsConfig = { + createdAt: TIMESTAMP.CREATED_AT, + updatedAt: TIMESTAMP.UPDATED_AT, +}; + +export interface TimestampsI { + created_at: Date, + updated_at: Date, +} diff --git a/src/constants/index.ts b/src/constants/index.ts new file mode 100644 index 0000000..519956a --- /dev/null +++ b/src/constants/index.ts @@ -0,0 +1 @@ +export * from "./database/index.js"; diff --git a/src/models/Favorite.ts b/src/models/Favorite.ts index a227a76..6d1b73a 100644 --- a/src/models/Favorite.ts +++ b/src/models/Favorite.ts @@ -1,18 +1,48 @@ -import mongoose from "mongoose"; +import { COLLECTION, MODEL, TIMESTAMPS, TimestampsI } from "#src/constants/index.js"; +import { Document, model, Model, Schema, Types } from "mongoose"; -const { Schema } = mongoose; - -const schema = new Schema( +// TODO: information required. +const schema = new Schema( { - profile_id: String, - name: String, - favorite1: String, - favorite2: String, - favorite3: String, + profile_id: { + type: Schema.Types.ObjectId, + required: true, + }, + name: { + type: String, + required: true, + }, + favorite1: { + type: String, + }, + favorite2: { + type: String, + }, + favorite3: { + type: String, + }, }, { - timestamps: true, + collection: COLLECTION.FAVORITE, + timestamps: TIMESTAMPS, }, ); -export const Favorite = mongoose.model("Favorite", schema); +export const Favorite = model(MODEL.FAVORITE, schema); + +/* ------------------------- Interfaces ------------------------- */ + +export interface FavoriteI extends TimestampsI { + profile_id: Types.ObjectId; + name: string; + favorite1?: string; + favorite2?: string; + favorite3?: string; +} + +export interface FavoriteSchemaI extends Document, FavoriteI { +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface FavoriteModelI extends Model { +} diff --git a/src/models/Profile.ts b/src/models/Profile.ts index 04cfa94..95febca 100644 --- a/src/models/Profile.ts +++ b/src/models/Profile.ts @@ -1,14 +1,54 @@ -import mongoose from "mongoose"; +import { COLLECTION, MODEL } from "#src/constants/index.js"; +import { Document, model, Model, Schema } from "mongoose"; -const { Schema } = mongoose; +// TODO: information required. +const schema = new Schema( + { + email: { + type: String, + required: true, + }, + name: { + type: String, + required: true, + }, + nickname: { + type: String, + }, + capital: { + type: Number, + required: true, + default: 0, + min: 0, + }, + divisa: { + type: String, + }, + prefered_cryptocurrency: { + type: String, + }, + }, + { + collection: COLLECTION.PROFILE, + }, +); -const schema = new Schema({ - name: String, - nickname: String, - email: String, - capital: Number, - divisa: String, - prefered_cryptocurrency: String, -}); +export const Profile = model(MODEL.PROFILE, schema); -export const Profile = mongoose.model("Profile", schema); +/* ------------------------- Interfaces ------------------------- */ + +export interface ProfileI { + email: `${string}@${string}.${string}`; + name: string; + nickname?: string; + capital: number; + divisa?: string; + prefered_cryptocurrency?: string; +} + +export interface ProfileSchemaI extends Document, ProfileI { +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface ProfileModelI extends Model { +} diff --git a/src/models/Simulator.ts b/src/models/Simulator.ts index d86a8a3..93bbfbc 100644 --- a/src/models/Simulator.ts +++ b/src/models/Simulator.ts @@ -1,19 +1,59 @@ -import mongoose from "mongoose"; +import { COLLECTION, MODEL, TIMESTAMPS, TimestampsI } from "#src/constants/index.js"; +import { Document, model, Model, Schema, Types } from "mongoose"; -const { Schema } = mongoose; - -const schema = new Schema( +// TODO: information required. +const schema = new Schema( { - profile_id: Schema.Types.ObjectId, - dateRecorded: Date, - cryptocurrency: String, - euros: Number, - price: Number, - quantity: Number, + profile_id: { + type: Schema.Types.ObjectId, + required: true, + }, + recorded_at: { + type: Date, + required: true, + }, + cryptocurrency: { + type: String, + required: true, + }, + euros: { + type: Number, + required: true, + min: 0, + }, + price: { + type: Number, + required: true, + min: 0, + }, + quantity: { + type: Number, + required: true, + min: 0, + }, }, { - timestamps: true, + collection: COLLECTION.SIMULATOR, + timestamps: TIMESTAMPS, }, ); -export const Simulator = mongoose.model("Simulator", schema); +export const Simulator = model(MODEL.SIMULATOR, schema); + +/* ------------------------- Interfaces ------------------------- */ + +export interface SimulatorI extends TimestampsI { + profile_id: Types.ObjectId; + recorded_at: Date; + cryptocurrency: string; + euros: number; + price: number; + quantity: number; +} + +export interface SimulatorSchemaI extends Document, SimulatorI { +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SimulatorModelI extends Model { +} diff --git a/src/models/index.ts b/src/models/index.ts new file mode 100644 index 0000000..4da25da --- /dev/null +++ b/src/models/index.ts @@ -0,0 +1,3 @@ +export * from "./Favorite.js"; +export * from "./Profile.js"; +export * from "./Simulator.js"; diff --git a/src/routes/favorite.router.ts b/src/routes/favorite.router.ts index f253786..fbd1296 100644 --- a/src/routes/favorite.router.ts +++ b/src/routes/favorite.router.ts @@ -1,4 +1,4 @@ -import { Favorite } from "#src/models/Favorite.js"; +import { Favorite } from "#src/models/index.js"; import express from "express"; export const router = express.Router(); diff --git a/src/routes/profile.router.ts b/src/routes/profile.router.ts index 2bffca1..5cfb709 100644 --- a/src/routes/profile.router.ts +++ b/src/routes/profile.router.ts @@ -1,4 +1,4 @@ -import { Profile } from "#src/models/Profile.js"; +import { Profile } from "#src/models/index.js"; import express from "express"; export const router = express.Router(); diff --git a/src/routes/simulator.router.ts b/src/routes/simulator.router.ts index d9a1125..47c39d6 100644 --- a/src/routes/simulator.router.ts +++ b/src/routes/simulator.router.ts @@ -1,4 +1,4 @@ -import { Simulator } from "#src/models/Simulator.js"; +import { Simulator } from "#src/models/index.js"; import cors from "cors"; import express from "express"; diff --git a/src/scripts/seed.ts b/src/scripts/seed.ts index f200c27..d8fa5ea 100644 --- a/src/scripts/seed.ts +++ b/src/scripts/seed.ts @@ -1,7 +1,5 @@ import { DBURL } from "#src/config.js"; -import { Favorite } from "#src/models/Favorite.js"; -import { Profile } from "#src/models/Profile.js"; -import { Simulator } from "#src/models/Simulator.js"; +import { Favorite, Profile, Simulator } from "#src/models/index.js"; import mongoose from "mongoose"; (async () => { @@ -18,9 +16,7 @@ import mongoose from "mongoose"; await profile.save(); const query = { _id: "6093abb3dfd9da1deeae56f2" }; - const idProfile = await Profile.findOne(query).then((e: any) => { - return e?._id; - }); + const idProfile = await Profile.findOne(query).then(e => e?._id); const simulator = new Simulator({ profile_id: idProfile,