-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add User model and repository * Specify versions for mongo and mongo-express in docker-compose
- Loading branch information
Showing
7 changed files
with
189 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters