Add production database, user model and controller

This commit is contained in:
Norbi Peti 2021-11-10 17:10:20 +01:00
parent 8e855fd454
commit 828fd52302
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
12 changed files with 535 additions and 4 deletions

View file

@ -8,4 +8,5 @@ fi
echo "Installing packages"
npm install
echo "Running application"
npm run rebuild
npm run start:watch

View file

@ -14,6 +14,7 @@
"@loopback/rest": "^10.1.0",
"@loopback/rest-explorer": "^3.3.4",
"@loopback/service-proxy": "^3.2.4",
"loopback-connector-mysql": "^5.4.4",
"tslib": "^2.0.0"
},
"devDependencies": {
@ -1662,6 +1663,14 @@
"node": ">=0.10"
}
},
"node_modules/bignumber.js": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==",
"engines": {
"node": "*"
}
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@ -4092,6 +4101,128 @@
"node": ">=10"
}
},
"node_modules/loopback-connector-mysql": {
"version": "5.4.4",
"resolved": "https://registry.npmjs.org/loopback-connector-mysql/-/loopback-connector-mysql-5.4.4.tgz",
"integrity": "sha512-6y+eXbP1YJWfEqBsuaNoK6zGSTurN1h0X67qpRj/pf0U9qWphjuJGYbU4Z8DnutY3J1OTeSycQgvt1qLJNHj/w==",
"dependencies": {
"async": "^2.6.1",
"debug": "^3.1.0",
"lodash": "^4.17.11",
"loopback-connector": "^4.0.0",
"mysql": "^2.11.1",
"strong-globalize": "^5.0.5"
},
"engines": {
"node": ">=8"
}
},
"node_modules/loopback-connector-mysql/node_modules/async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"dependencies": {
"lodash": "^4.17.14"
}
},
"node_modules/loopback-connector-mysql/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/loopback-connector-mysql/node_modules/loopback-connector": {
"version": "4.11.1",
"resolved": "https://registry.npmjs.org/loopback-connector/-/loopback-connector-4.11.1.tgz",
"integrity": "sha512-EA31zur3xIhP4UW+P2rWEcSbqpk4jPddpTBZSSw8KCszM7T0/Pe4HvEmG0MndAWJctRPtrwKDEu/8rWuMDLf+A==",
"dependencies": {
"async": "^3.2.0",
"bluebird": "^3.7.2",
"debug": "^4.1.1",
"msgpack5": "^4.2.0",
"strong-globalize": "^5.1.0",
"uuid": "^7.0.3"
},
"engines": {
"node": ">=8.9"
}
},
"node_modules/loopback-connector-mysql/node_modules/loopback-connector/node_modules/async": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz",
"integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g=="
},
"node_modules/loopback-connector-mysql/node_modules/loopback-connector/node_modules/debug": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/loopback-connector-mysql/node_modules/mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"dependencies": {
"minimist": "^1.2.5"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/loopback-connector-mysql/node_modules/strong-globalize": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/strong-globalize/-/strong-globalize-5.1.0.tgz",
"integrity": "sha512-9cooAb6kNMDFmTDybkkch1x7b+LuzZNva8oIr+MxXnvx9jcvw4/4DTSXPc53mG68G0Q9YOTYZkhDkWe/DiJ1Qg==",
"dependencies": {
"accept-language": "^3.0.18",
"debug": "^4.1.1",
"globalize": "^1.5.0",
"lodash": "^4.17.15",
"md5": "^2.2.1",
"mkdirp": "^0.5.5",
"os-locale": "^5.0.0",
"yamljs": "^0.3.0"
},
"engines": {
"node": ">=8.9"
}
},
"node_modules/loopback-connector-mysql/node_modules/strong-globalize/node_modules/debug": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/loopback-connector-mysql/node_modules/uuid": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
"integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/loopback-datasource-juggler": {
"version": "4.26.0",
"resolved": "https://registry.npmjs.org/loopback-datasource-juggler/-/loopback-datasource-juggler-4.26.0.tgz",
@ -4299,8 +4430,7 @@
"node_modules/minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"node_modules/mkdirp": {
"version": "1.0.4",
@ -4446,6 +4576,25 @@
"safe-buffer": "^5.1.2"
}
},
"node_modules/mysql": {
"version": "2.18.1",
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
"integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
"dependencies": {
"bignumber.js": "9.0.0",
"readable-stream": "2.3.7",
"safe-buffer": "5.1.2",
"sqlstring": "2.3.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mysql/node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/nanoid": {
"version": "2.1.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz",
@ -6001,6 +6150,14 @@
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"node_modules/sqlstring": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
"integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/stable": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
@ -7993,6 +8150,11 @@
"resolved": "https://registry.npmjs.org/bcp47/-/bcp47-1.1.2.tgz",
"integrity": "sha1-NUvjMH/9CEM6ePXh4glYRfifx/4="
},
"bignumber.js": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="
},
"binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@ -9870,6 +10032,103 @@
"uuid": "^8.3.0"
}
},
"loopback-connector-mysql": {
"version": "5.4.4",
"resolved": "https://registry.npmjs.org/loopback-connector-mysql/-/loopback-connector-mysql-5.4.4.tgz",
"integrity": "sha512-6y+eXbP1YJWfEqBsuaNoK6zGSTurN1h0X67qpRj/pf0U9qWphjuJGYbU4Z8DnutY3J1OTeSycQgvt1qLJNHj/w==",
"requires": {
"async": "^2.6.1",
"debug": "^3.1.0",
"lodash": "^4.17.11",
"loopback-connector": "^4.0.0",
"mysql": "^2.11.1",
"strong-globalize": "^5.0.5"
},
"dependencies": {
"async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"requires": {
"lodash": "^4.17.14"
}
},
"debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"requires": {
"ms": "^2.1.1"
}
},
"loopback-connector": {
"version": "4.11.1",
"resolved": "https://registry.npmjs.org/loopback-connector/-/loopback-connector-4.11.1.tgz",
"integrity": "sha512-EA31zur3xIhP4UW+P2rWEcSbqpk4jPddpTBZSSw8KCszM7T0/Pe4HvEmG0MndAWJctRPtrwKDEu/8rWuMDLf+A==",
"requires": {
"async": "^3.2.0",
"bluebird": "^3.7.2",
"debug": "^4.1.1",
"msgpack5": "^4.2.0",
"strong-globalize": "^5.1.0",
"uuid": "^7.0.3"
},
"dependencies": {
"async": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz",
"integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g=="
},
"debug": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
"requires": {
"ms": "2.1.2"
}
}
}
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"requires": {
"minimist": "^1.2.5"
}
},
"strong-globalize": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/strong-globalize/-/strong-globalize-5.1.0.tgz",
"integrity": "sha512-9cooAb6kNMDFmTDybkkch1x7b+LuzZNva8oIr+MxXnvx9jcvw4/4DTSXPc53mG68G0Q9YOTYZkhDkWe/DiJ1Qg==",
"requires": {
"accept-language": "^3.0.18",
"debug": "^4.1.1",
"globalize": "^1.5.0",
"lodash": "^4.17.15",
"md5": "^2.2.1",
"mkdirp": "^0.5.5",
"os-locale": "^5.0.0",
"yamljs": "^0.3.0"
},
"dependencies": {
"debug": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
"requires": {
"ms": "2.1.2"
}
}
}
},
"uuid": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
"integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg=="
}
}
},
"loopback-datasource-juggler": {
"version": "4.26.0",
"resolved": "https://registry.npmjs.org/loopback-datasource-juggler/-/loopback-datasource-juggler-4.26.0.tgz",
@ -10028,8 +10287,7 @@
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"mkdirp": {
"version": "1.0.4",
@ -10133,6 +10391,24 @@
"safe-buffer": "^5.1.2"
}
},
"mysql": {
"version": "2.18.1",
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
"integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
"requires": {
"bignumber.js": "9.0.0",
"readable-stream": "2.3.7",
"safe-buffer": "5.1.2",
"sqlstring": "2.3.1"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"nanoid": {
"version": "2.1.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz",
@ -11336,6 +11612,11 @@
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"sqlstring": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
"integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A="
},
"stable": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",

View file

@ -56,6 +56,7 @@
"@loopback/rest": "^10.1.0",
"@loopback/rest-explorer": "^3.3.4",
"@loopback/service-proxy": "^3.2.4",
"loopback-connector-mysql": "^5.4.4",
"tslib": "^2.0.0"
},
"devDependencies": {

View file

@ -1 +1,2 @@
export * from './ping.controller';
export * from './user.controller';

View file

@ -0,0 +1,150 @@
import {
Count,
CountSchema,
Filter,
FilterExcludingWhere,
repository,
Where,
} from '@loopback/repository';
import {
post,
param,
get,
getModelSchemaRef,
patch,
put,
del,
requestBody,
response,
} from '@loopback/rest';
import {User} from '../models';
import {UserRepository} from '../repositories';
export class UserController {
constructor(
@repository(UserRepository)
public userRepository : UserRepository,
) {}
@post('/users')
@response(200, {
description: 'User model instance',
content: {'application/json': {schema: getModelSchemaRef(User)}},
})
async create(
@requestBody({
content: {
'application/json': {
schema: getModelSchemaRef(User, {
title: 'NewUser',
exclude: ['id'],
}),
},
},
})
user: Omit<User, 'id'>,
): Promise<User> {
return this.userRepository.create(user);
}
@get('/users/count')
@response(200, {
description: 'User model count',
content: {'application/json': {schema: CountSchema}},
})
async count(
@param.where(User) where?: Where<User>,
): Promise<Count> {
return this.userRepository.count(where);
}
@get('/users')
@response(200, {
description: 'Array of User model instances',
content: {
'application/json': {
schema: {
type: 'array',
items: getModelSchemaRef(User, {includeRelations: true}),
},
},
},
})
async find(
@param.filter(User) filter?: Filter<User>,
): Promise<User[]> {
return this.userRepository.find(filter);
}
@patch('/users')
@response(200, {
description: 'User PATCH success count',
content: {'application/json': {schema: CountSchema}},
})
async updateAll(
@requestBody({
content: {
'application/json': {
schema: getModelSchemaRef(User, {partial: true}),
},
},
})
user: User,
@param.where(User) where?: Where<User>,
): Promise<Count> {
return this.userRepository.updateAll(user, where);
}
@get('/users/{id}')
@response(200, {
description: 'User model instance',
content: {
'application/json': {
schema: getModelSchemaRef(User, {includeRelations: true}),
},
},
})
async findById(
@param.path.number('id') id: number,
@param.filter(User, {exclude: 'where'}) filter?: FilterExcludingWhere<User>
): Promise<User> {
return this.userRepository.findById(id, filter);
}
@patch('/users/{id}')
@response(204, {
description: 'User PATCH success',
})
async updateById(
@param.path.number('id') id: number,
@requestBody({
content: {
'application/json': {
schema: getModelSchemaRef(User, {partial: true}),
},
},
})
user: User,
): Promise<void> {
await this.userRepository.updateById(id, user);
}
@put('/users/{id}')
@response(204, {
description: 'User PUT success',
})
async replaceById(
@param.path.number('id') id: number,
@requestBody() user: User,
): Promise<void> {
await this.userRepository.replaceById(id, user);
}
@del('/users/{id}')
@response(204, {
description: 'User DELETE success',
})
async deleteById(@param.path.number('id') id: number): Promise<void> {
await this.userRepository.deleteById(id);
}
}

View file

@ -0,0 +1,31 @@
import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core';
import {juggler} from '@loopback/repository';
const config = {
name: 'database',
connector: 'mysql',
url: process.env.DATABASE_URL,
host: '',
port: 0,
user: '',
password: '',
database: ''
};
// 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 DatabaseDataSource extends juggler.DataSource
implements LifeCycleObserver {
static dataSourceName = 'database';
static readonly defaultConfig = config;
constructor(
@inject('datasources.config.database', {optional: true})
dsConfig: object = config,
) {
super(dsConfig);
}
}

View file

@ -0,0 +1 @@
export * from './database.datasource';

View file

@ -0,0 +1 @@
export * from './user.model';

View file

@ -0,0 +1,46 @@
import {Entity, model, property} from '@loopback/repository';
@model()
export class User extends Entity {
@property({
type: 'number',
id: true,
generated: true,
})
id?: number;
@property({
type: 'string',
required: true,
})
email: string;
@property({
type: 'string',
required: true,
})
name: string;
@property({
type: 'string',
required: true,
})
password: string;
@property({
type: 'object',
required: true,
})
role: object;
constructor(data?: Partial<User>) {
super(data);
}
}
export interface UserRelations {
// describe navigational properties here
}
export type UserWithRelations = User & UserRelations;

View file

@ -0,0 +1 @@
export * from './user.repository';

View file

@ -0,0 +1,16 @@
import {inject} from '@loopback/core';
import {DefaultCrudRepository} from '@loopback/repository';
import {DatabaseDataSource} from '../datasources';
import {User, UserRelations} from '../models';
export class UserRepository extends DefaultCrudRepository<
User,
typeof User.prototype.id,
UserRelations
> {
constructor(
@inject('datasources.database') dataSource: DatabaseDataSource,
) {
super(User, dataSource);
}
}

View file

@ -15,6 +15,7 @@ services:
- ./backend:/home/node/app
environment:
- COMMAND=run
- DATABASE_URL=${CLEARDB_DATABASE_URL}
networks:
default: