Skip to content

Commit

Permalink
Add mongodb and repository
Browse files Browse the repository at this point in the history
  • Loading branch information
Telokis committed Oct 27, 2023
1 parent b362777 commit fa3def4
Show file tree
Hide file tree
Showing 15 changed files with 411 additions and 5 deletions.
6 changes: 6 additions & 0 deletions apps/teloalapi/config/custom-environment-variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@ module.exports = {
al: {
token: "AL_TOKEN",
},
mongo: {
host: "MONGO_HOST",
user: "MONGO_USER",
password: "MONGO_PASSWORD",
database: "MONGO_DATABASE",
},
};
4 changes: 4 additions & 0 deletions apps/teloalapi/config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ module.exports = {
al: {
url: urlDefault(process.env.AL_URL, "https://adventure.land"),
},
mongo: {
port: parseIntDefault(process.env.MONGO_PORT, 10, 27027),
database: "teloal",
},
};
5 changes: 5 additions & 0 deletions apps/teloalapi/config/development.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
module.exports = {
host: "127.0.0.1",
mongo: {
host: "localhost",
user: "teloal",
password: "teloal",
},
};
1 change: 1 addition & 0 deletions apps/teloalapi/config/production.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const boolVal = (val, def) => (val ? val === "true" : def);

// `undefined` means the default value is ignored and an environment variable is required
module.exports = {
host: undefined,
};
9 changes: 9 additions & 0 deletions apps/teloalapi/src/controllers/adventure-land.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ import { cache } from "@teloal/lb4-cache";
import { parseCharacters, AlCharacter } from "@teloal/parse-character";
import { AlMerchants } from "../types/AlMerchants";
import { AlMerchant } from "../models";
import { repository } from "@loopback/repository";
import { AlCharacterRepository } from "../repositories";

@api({ basePath: "/v1/al" })
export class AdventureLandController {
@inject("services.AdventureLand")
protected alService: AdventureLandService;

@repository(AlCharacterRepository)
protected alCharRepo: AlCharacterRepository;

@cache({ ttl: 5 })
@get("/character/{name}")
@response(200, {
Expand All @@ -35,6 +40,10 @@ export class AdventureLandController {
throw new HttpErrors.NotFound(`The character "${name}" doesn't exist.`);
}

const res = await this.alCharRepo.upsert(char);

console.log(res);

return char;
}

Expand Down
3 changes: 2 additions & 1 deletion apps/teloalapi/src/datasources/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './adventure-land.datasource';
export * from "./adventure-land.datasource";
export * from "./mongo.datasource";
31 changes: 31 additions & 0 deletions apps/teloalapi/src/datasources/mongo.datasource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { inject, lifeCycleObserver, LifeCycleObserver } from "@loopback/core";
import { juggler } from "@loopback/repository";
import config from "config";

const connectorConfig = {
name: "mongo",
connector: "mongodb",
host: config.mongo.host,
port: config.mongo.port,
user: config.mongo.user,
password: config.mongo.password,
database: config.mongo.database,
useNewUrlParser: true,
};

// Observe application's life cycle to disconnect the datasource when
// application is stopped. This allows the application to be shut down
// gracefully. The `stop()` method is inherited from `juggler.DataSource`.
// Learn more at https://loopback.io/doc/en/lb4/Life-cycle.html
@lifeCycleObserver("datasource")
export class MongoDataSource extends juggler.DataSource implements LifeCycleObserver {
static dataSourceName = "mongo";
static readonly defaultConfig = connectorConfig;

constructor(
@inject("datasources.config.mongo", { optional: true })
dsConfig: object = connectorConfig,
) {
super(dsConfig);
}
}
91 changes: 91 additions & 0 deletions apps/teloalapi/src/repositories/al-character.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { inject } from "@loopback/core";
import {
Count,
DefaultCrudRepository,
Entity,
Options,
Where,
model,
property,
} from "@loopback/repository";
import { MongoDataSource } from "../datasources";
import { AlCharacter } from "@teloal/parse-character";

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

type GConstructor<T = {}> = new (...args: any[]) => T;

function extendClassWithTimestamps<T extends GConstructor<Entity>>(Base: T) {
@model({
name: "AlCharacter",
})
class Extended extends Base {
constructor(...args: any[]) {
super(...args);
}

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

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

return Extended;
}

type TimestampedAlCharacter = AlCharacter & Timestamps;

export class AlCharacterRepository extends DefaultCrudRepository<
TimestampedAlCharacter,
typeof AlCharacter.prototype.name
> {
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 await this.updateById(char.name, char);
}

return await this.create(char);
}
}
1 change: 1 addition & 0 deletions apps/teloalapi/src/repositories/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./al-character.repository";
8 changes: 8 additions & 0 deletions apps/teloalapi/src/types/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,12 @@ declare module "config" {
url: string;
token: string | undefined;
};

export const mongo: {
host: string;
port: number;
user: string;
password: string;
database: string;
};
}
32 changes: 32 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This docker-compose is meant for local development.
# It should not be used in production.

version: "3"
services:
teloal-mongo:
image: mongo
container_name: teloal-mongo
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: mongo-user
MONGO_INITDB_ROOT_PASSWORD: mongo-password
command: --port 27027
ports:
- "27027:27027"
volumes:
- ./scripts/init-mongo.js:/docker-entrypoint-initdb.d/mongo-init.js:ro

teloal-mongo-express:
image: mongo-express
container_name: teloal-mongo-express
restart: unless-stopped
environment:
ME_CONFIG_BASICAUTH_USERNAME: ""
ME_CONFIG_MONGODB_ADMINUSERNAME: mongo-user
ME_CONFIG_MONGODB_ADMINPASSWORD: mongo-password
ME_CONFIG_SITE_COOKIESECRET: teloal-cookie-secret
ME_CONFIG_SITE_SESSIONSECRET: teloal-session-secret
ME_CONFIG_MONGODB_URL: mongodb://mongo-user:mongo-password@teloal-mongo:27027/
ME_CONFIG_OPTIONS_EDITORTHEME: dracula
ports:
- "127.0.0.1:7937:8081"
5 changes: 3 additions & 2 deletions libs/parse-character/src/lib/models/al-character.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Model, model, property } from "@loopback/repository";
import { Entity, Model, model, property } from "@loopback/repository";
import type { ClassKey, SlotType } from "typed-adventureland";
import { ALCharacterCleanSlot, AlCharacterItem } from "./al-character-item.model";

Expand Down Expand Up @@ -72,8 +72,9 @@ export class AlCharacterItemSlots extends Model {
required: ["name", "level", "ctype", "slots"],
},
})
export class AlCharacter extends Model implements ALCharacterDefinition {
export class AlCharacter extends Entity implements ALCharacterDefinition {
@property({
id: true,
description: "Name of the character.",
})
name: string;
Expand Down
Loading

0 comments on commit fa3def4

Please sign in to comment.