Skip to content
This repository has been archived by the owner on Apr 12, 2022. It is now read-only.

refactor: Improve database models [WIP] #5

Merged
merged 5 commits into from
Mar 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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.

<!-- Footnotes -->

Expand Down
2 changes: 2 additions & 0 deletions src/constants/database/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./models.js";
export * from "./timestamps.js";
11 changes: 11 additions & 0 deletions src/constants/database/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export enum MODEL {
FAVORITE = "Favorite",
PROFILE = "Profile",
SIMULATOR = "Simulator",
}

export enum COLLECTION {
FAVORITE = "favorites",
PROFILE = "profiles",
SIMULATOR = "simulators",
}
16 changes: 16 additions & 0 deletions src/constants/database/timestamps.ts
Original file line number Diff line number Diff line change
@@ -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,
}
1 change: 1 addition & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./database/index.js";
52 changes: 41 additions & 11 deletions src/models/Favorite.ts
Original file line number Diff line number Diff line change
@@ -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<FavoriteSchemaI>(
{
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<FavoriteSchemaI, FavoriteModelI>(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<FavoriteSchemaI> {
}
62 changes: 51 additions & 11 deletions src/models/Profile.ts
Original file line number Diff line number Diff line change
@@ -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<ProfileSchemaI>(
{
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<ProfileSchemaI, ProfileModelI>(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<ProfileSchemaI> {
}
64 changes: 52 additions & 12 deletions src/models/Simulator.ts
Original file line number Diff line number Diff line change
@@ -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<SimulatorSchemaI>(
{
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<SimulatorSchemaI, SimulatorModelI>(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<SimulatorSchemaI> {
}
3 changes: 3 additions & 0 deletions src/models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./Favorite.js";
export * from "./Profile.js";
export * from "./Simulator.js";
2 changes: 1 addition & 1 deletion src/routes/favorite.router.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
2 changes: 1 addition & 1 deletion src/routes/profile.router.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
2 changes: 1 addition & 1 deletion src/routes/simulator.router.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand Down
8 changes: 2 additions & 6 deletions src/scripts/seed.ts
Original file line number Diff line number Diff line change
@@ -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 () => {
Expand All @@ -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,
Expand Down