Skip to content

Commit

Permalink
Create user model (#19)
Browse files Browse the repository at this point in the history
* Add User model and repository

* Specify versions for mongo and mongo-express in docker-compose
  • Loading branch information
Telokis authored Dec 3, 2023
1 parent 67af235 commit 28c4f9f
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 89 deletions.
39 changes: 39 additions & 0 deletions apps/teloalapi/src/models/User.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Entity, model, property } from "@loopback/repository";
import { User, UserRole } from "../types/User";

@model({
settings: {
description: "A TeloAL user. Created when registering and used when authenticating.",
},
})
export class UserModel extends Entity implements User {
@property({
id: true,
jsonSchema: {
description: "Uniquely identifies a user.",
},
})
username: string;

@property({
jsonSchema: {
description: "Optional email address of the user.",
},
})
email?: string;

@property({
jsonSchema: {
description: "Hashed user password.",
},
})
password: string;

@property({
jsonSchema: {
description: "Hashed user password.",
enum: ["admin", "user"],
},
})
role: UserRole;
}
109 changes: 109 additions & 0 deletions apps/teloalapi/src/repositories/AutoDateRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {
Count,
DataObject,
DefaultCrudRepository,
Entity,
JugglerDataSource,
Options,
Where,
model,
property,
} from "@loopback/repository";

type Timestamps = {
createdAt?: Date;
updatedAt?: Date;
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type GConstructor<T = {}> = new (...args: any[]) => T;

type TimestampedModel<TModel extends Entity> = TModel & Timestamps;

function extendClassWithTimestamps<T extends GConstructor<Entity>>(Base: T, modelName: string) {
@model({
name: modelName,
})
class Extended extends Base {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor(...args: any[]) {
super(...args);
}

@property()
createdAt?: Date;

@property()
updatedAt?: Date;
}

return Extended;
}

export function makeRepository<TModel extends Entity, ID>(
TheModel: GConstructor<TModel>,
modelName: string,
idProp: keyof TModel,
) {
type TimestampedTModel = TimestampedModel<TModel>;

class AutoDateRepository extends DefaultCrudRepository<TimestampedTModel, ID> {
constructor(dataSource: JugglerDataSource) {
// @ts-ignore
super(extendClassWithTimestamps<GConstructor<TModel>>(TheModel, modelName), dataSource);
}

async create(
data: DataObject<TimestampedTModel>,
options?: Options,
): Promise<TimestampedTModel> {
data.createdAt = new Date();
data.updatedAt = new Date();
return super.create(data, options);
}

async update(data: TimestampedTModel, options?: Options): Promise<void> {
data.updatedAt = new Date();
return super.update(data, options);
}

async updateAll(
data: DataObject<TimestampedTModel>,
where?: Where<TimestampedTModel>,
options?: Options,
): Promise<Count> {
data.updatedAt = new Date();
return super.updateAll(data, where, options);
}

async replaceById(
id: ID,
data: DataObject<TimestampedTModel>,
options?: Options,
): Promise<void> {
data.updatedAt = new Date();
return super.replaceById(id, data, options);
}

async updateById(
id: ID,
data: DataObject<TimestampedTModel>,
options?: Options,
): Promise<void> {
data.updatedAt = new Date();
return super.updateById(id, data, options);
}

async upsert(data: DataObject<TimestampedTModel>) {
const id = data[idProp] as ID;

if (await this.exists(id)) {
return this.updateById(id, data);
}

return this.create(data);
}
}

return AutoDateRepository;
}
16 changes: 16 additions & 0 deletions apps/teloalapi/src/repositories/Users.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { inject } from "@loopback/core";
import { MongoDataSource } from "../datasources/mongo.datasource";
import { UserModel } from "../models/User.model";
import { makeRepository } from "./AutoDateRepository";

const BaseRepository = makeRepository<UserModel, typeof UserModel.prototype.username>(
UserModel,
"User",
"username",
);

export class UsersRepository extends BaseRepository {
constructor(@inject("datasources.mongo") dataSource: MongoDataSource) {
super(dataSource);
}
}
95 changes: 9 additions & 86 deletions apps/teloalapi/src/repositories/alCharacter.repository.ts
Original file line number Diff line number Diff line change
@@ -1,93 +1,16 @@
import { AlCharacter } from "@teloal/parse-character";
import { inject } from "@loopback/core";
import {
Count,
DefaultCrudRepository,
Entity,
Options,
Where,
model,
property,
} from "@loopback/repository";
import { MongoDataSource } from "../datasources/mongo.datasource";
import { AlCharacter } from "@teloal/parse-character";

type Timestamps = {
createdAt?: Date;
updatedAt?: Date;
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type GConstructor<T = {}> = new (...args: any[]) => T;

function extendClassWithTimestamps<T extends GConstructor<Entity>>(Base: T) {
@model({
name: "AlCharacter",
})
class Extended extends Base {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor(...args: any[]) {
super(...args);
}

@property({
type: "date",
})
createdAt?: Date;
import { makeRepository } from "./AutoDateRepository";

@property({
type: "date",
})
updatedAt?: Date;
}

return Extended;
}
const BaseRepository = makeRepository<AlCharacter, typeof AlCharacter.prototype.name>(
AlCharacter,
"AlCharacter",
"name",
);

type TimestampedAlCharacter = AlCharacter & Timestamps;

export class AlCharacterRepository extends DefaultCrudRepository<
TimestampedAlCharacter,
typeof AlCharacter.prototype.name
> {
export class AlCharacterRepository extends BaseRepository {
constructor(@inject("datasources.mongo") dataSource: MongoDataSource) {
super(extendClassWithTimestamps(AlCharacter), dataSource);
}

async create(entity: TimestampedAlCharacter, options?: Options): Promise<TimestampedAlCharacter> {
entity.createdAt = new Date();
entity.updatedAt = new Date();
return super.create(entity, options);
}

async update(data: TimestampedAlCharacter, options?: Options): Promise<void> {
data.updatedAt = new Date();
return super.update(data, options);
}

async updateAll(
data: TimestampedAlCharacter,
where?: Where<TimestampedAlCharacter>,
options?: Options,
): Promise<Count> {
data.updatedAt = new Date();
return super.updateAll(data, where, options);
}

async replaceById(id: string, data: TimestampedAlCharacter, options?: Options): Promise<void> {
data.updatedAt = new Date();
return super.replaceById(id, data, options);
}

async updateById(id: string, data: TimestampedAlCharacter, options?: Options): Promise<void> {
data.updatedAt = new Date();
return super.updateById(id, data, options);
}

async upsert(char: AlCharacter) {
if (await this.exists(char.name)) {
return this.updateById(char.name, char);
}

return this.create(char);
super(dataSource);
}
}
13 changes: 13 additions & 0 deletions apps/teloalapi/src/types/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export enum UserRole {
user = "user",
admin = "admin",
}

export type User = {
username: string;
email?: string;
password: string;
role: UserRole;
createdAt?: Date;
updatedAt?: Date;
};
2 changes: 1 addition & 1 deletion apps/teloalapi/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"moduleResolution": "node",
"target": "es2018",
"sourceMap": true,
"declaration": true,
"declaration": false,
"importHelpers": true,
"types": ["node"]
},
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
version: "3"
services:
teloal-mongo:
image: mongo
image: mongo:7
container_name: teloal-mongo
restart: unless-stopped
environment:
Expand All @@ -17,7 +17,7 @@ services:
- ./scripts/init-mongo.js:/docker-entrypoint-initdb.d/mongo-init.js:ro

teloal-mongo-express:
image: mongo-express
image: mongo-express:1.0.0-18-alpine3.18
container_name: teloal-mongo-express
restart: unless-stopped
environment:
Expand Down

0 comments on commit 28c4f9f

Please sign in to comment.