diff --git a/backend/src/graphql/models/Decay.ts b/backend/src/graphql/models/Decay.ts index 17ee8fbac..860580e8f 100644 --- a/backend/src/graphql/models/Decay.ts +++ b/backend/src/graphql/models/Decay.ts @@ -15,13 +15,6 @@ export class Decay { } } - static async getDecayStartBlock(): Promise { - if (!this.decayStartBlockTransaction) { - this.decayStartBlockTransaction = await Transaction.getDecayStartBlock() - } - return this.decayStartBlockTransaction - } - @Field(() => Number) balance: number @@ -38,6 +31,4 @@ export class Decay { @Field(() => Int, { nullable: true }) decayStartBlock?: string - - static decayStartBlockTransaction: Transaction | undefined } diff --git a/backend/src/graphql/resolvers/BalanceResolver.ts b/backend/src/graphql/resolvers/BalanceResolver.ts index 1d1afaa2a..4c83bbbcd 100644 --- a/backend/src/graphql/resolvers/BalanceResolver.ts +++ b/backend/src/graphql/resolvers/BalanceResolver.ts @@ -2,9 +2,10 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Resolver, Query, Ctx, Authorized } from 'type-graphql' +import { getCustomRepository } from 'typeorm' import { Balance } from '../models/Balance' -import { User as dbUser } from '../../typeorm/entity/User' -import { Balance as dbBalance } from '../../typeorm/entity/Balance' +import { BalanceRepository } from '../../typeorm/repository/Balance' +import { UserRepository } from '../../typeorm/repository/User' import { calculateDecay } from '../../util/decay' import { roundFloorFrom4 } from '../../util/round' @@ -14,8 +15,11 @@ export class BalanceResolver { @Query(() => Balance) async balance(@Ctx() context: any): Promise { // load user and balance - const userEntity = await dbUser.findByPubkeyHex(context.pubKey) - const balanceEntity = await dbBalance.findByUser(userEntity.id) + const balanceRepository = getCustomRepository(BalanceRepository) + const userRepository = getCustomRepository(UserRepository) + + const userEntity = await userRepository.findByPubkeyHex(context.pubKey) + const balanceEntity = await balanceRepository.findByUser(userEntity.id) let balance: Balance const now = new Date() if (balanceEntity) { diff --git a/backend/src/graphql/resolvers/GdtResolver.ts b/backend/src/graphql/resolvers/GdtResolver.ts index 0e9af5ad6..8ea006313 100644 --- a/backend/src/graphql/resolvers/GdtResolver.ts +++ b/backend/src/graphql/resolvers/GdtResolver.ts @@ -2,11 +2,12 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Resolver, Query, Args, Ctx, Authorized } from 'type-graphql' +import { getCustomRepository } from 'typeorm' import CONFIG from '../../config' import { GdtEntryList } from '../models/GdtEntryList' import { GdtTransactionSessionIdInput } from '../inputs/GdtInputs' import { apiGet } from '../../apis/HttpRequest' -import { User as dbUser } from '../../typeorm/entity/User' +import { UserRepository } from '../../typeorm/repository/User' @Resolver() export class GdtResolver { @@ -19,7 +20,8 @@ export class GdtResolver { @Ctx() context: any, ): Promise { // load user - const userEntity = await dbUser.findByPubkeyHex(context.pubKey) + const userRepository = getCustomRepository(UserRepository) + const userEntity = await userRepository.findByPubkeyHex(context.pubKey) const resultGDT = await apiGet( `${CONFIG.GDT_API_URL}/GdtEntries/listPerEmailApi/${userEntity.email}/${currentPage}/${pageSize}/${order}`, diff --git a/backend/src/graphql/resolvers/TransactionResolver.ts b/backend/src/graphql/resolvers/TransactionResolver.ts index 3762cccee..cd07a94f5 100644 --- a/backend/src/graphql/resolvers/TransactionResolver.ts +++ b/backend/src/graphql/resolvers/TransactionResolver.ts @@ -2,12 +2,13 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Resolver, Query, Args, Authorized, Ctx, Mutation } from 'type-graphql' +import { getCustomRepository } from 'typeorm' import CONFIG from '../../config' import { TransactionList } from '../models/Transaction' import { TransactionListInput, TransactionSendArgs } from '../inputs/TransactionInput' import { apiGet, apiPost } from '../../apis/HttpRequest' -import { User as dbUser } from '../../typeorm/entity/User' -import { Balance as dbBalance } from '../../typeorm/entity/Balance' +import { BalanceRepository } from '../../typeorm/repository/Balance' +import { UserRepository } from '../../typeorm/repository/User' import listTransactions from './listTransactions' import { roundFloorFrom4 } from '../../util/round' import { calculateDecay } from '../../util/decay' @@ -25,7 +26,8 @@ export class TransactionResolver { if (!result.success) throw new Error(result.data) // load user - const userEntity = await dbUser.findByPubkeyHex(result.data.user.public_hex) + const userRepository = getCustomRepository(UserRepository) + const userEntity = await userRepository.findByPubkeyHex(result.data.user.public_hex) const transactions = await listTransactions(firstPage, items, order, userEntity) @@ -37,7 +39,8 @@ export class TransactionResolver { transactions.gdtSum = resultGDTSum.data.sum // get balance - const balanceEntity = await dbBalance.findByUser(userEntity.id) + const balanceRepository = getCustomRepository(BalanceRepository) + const balanceEntity = await balanceRepository.findByUser(userEntity.id) if (balanceEntity) { const now = new Date() transactions.balance = roundFloorFrom4(balanceEntity.amount) diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts index 1de7d7dcc..bf84e17d4 100644 --- a/backend/src/graphql/resolvers/listTransactions.ts +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -1,8 +1,11 @@ +import { getCustomRepository } from 'typeorm' import { User as dbUser } from '../../typeorm/entity/User' +import { UserRepository } from '../../typeorm/repository/User' import { TransactionList, Transaction } from '../models/Transaction' import { UserTransaction as dbUserTransaction } from '../../typeorm/entity/UserTransaction' +import { UserTransactionRepository } from '../../typeorm/repository/UserTransaction' import { Transaction as dbTransaction } from '../../typeorm/entity/Transaction' -import { Decay } from '../models/Decay' +import { TransactionRepository } from '../../typeorm/repository/Transaction' import { calculateDecayWithInterval } from '../../util/decay' import { roundFloorFrom4 } from '../../util/round' @@ -20,20 +23,8 @@ async function calculateAndAddDecayTransactions( transactionIds.push(userTransaction.transactionId) }) - const transactions = await dbTransaction - .createQueryBuilder('transaction') - .where('transaction.id IN (:...transactions)', { transactions: transactionIds }) - .leftJoinAndSelect( - 'transaction.transactionSendCoin', - 'transactionSendCoin', - // 'transactionSendCoin.transaction_id = transaction.id', - ) - .leftJoinAndSelect( - 'transaction.transactionCreation', - 'transactionCreation', - // 'transactionSendCoin.transaction_id = transaction.id', - ) - .getMany() + const transactionRepository = getCustomRepository(TransactionRepository) + const transactions = await transactionRepository.joinFullTransactionsByIds(transactionIds) const transactionIndiced: dbTransaction[] = [] transactions.forEach((transaction: dbTransaction) => { @@ -46,9 +37,10 @@ async function calculateAndAddDecayTransactions( // remove duplicates // https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates const involvedUsersUnique = involvedUserIds.filter((v, i, a) => a.indexOf(v) === i) - const userIndiced = await dbUser.getUsersIndiced(involvedUsersUnique) + const userRepository = getCustomRepository(UserRepository) + const userIndiced = await userRepository.getUsersIndiced(involvedUsersUnique) - const decayStartTransaction = await Decay.getDecayStartBlock() + const decayStartTransaction = await transactionRepository.findDecayStartBlock() for (let i = 0; i < userTransactions.length; i++) { const userTransaction = userTransactions[i] @@ -163,7 +155,8 @@ export default async function listTransactions( if (offset && order === 'ASC') { offset-- } - let [userTransactions, userTransactionsCount] = await dbUserTransaction.findByUserPaged( + const userTransactionRepository = getCustomRepository(UserTransactionRepository) + let [userTransactions, userTransactionsCount] = await userTransactionRepository.findByUserPaged( user.id, limit, offset, diff --git a/backend/src/typeorm/entity/Balance.ts b/backend/src/typeorm/entity/Balance.ts index 23b21de78..c1ca359f1 100644 --- a/backend/src/typeorm/entity/Balance.ts +++ b/backend/src/typeorm/entity/Balance.ts @@ -16,8 +16,4 @@ export class Balance extends BaseEntity { @Column({ type: 'bigint' }) amount: number - - static findByUser(userId: number): Promise { - return this.createQueryBuilder('balance').where('balance.userId = :userId', { userId }).getOne() - } } diff --git a/backend/src/typeorm/entity/Group.ts b/backend/src/typeorm/entity/Group.ts deleted file mode 100644 index 6694ea742..000000000 --- a/backend/src/typeorm/entity/Group.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from "typeorm"; -import { User } from "./User" - -@Entity() -export class Group { - - @PrimaryGeneratedColumn() - id: number; - - @Column() - alias: string; - - @Column() - name: string; - - @Column() - url: string; - - @Column() - description: string; - - @OneToMany(type => User, user => user.group) - users: User[]; - -} */ diff --git a/backend/src/typeorm/entity/Transaction.ts b/backend/src/typeorm/entity/Transaction.ts index d8b87828c..53dce4d08 100644 --- a/backend/src/typeorm/entity/Transaction.ts +++ b/backend/src/typeorm/entity/Transaction.ts @@ -27,19 +27,4 @@ export class Transaction extends BaseEntity { @OneToOne(() => TransactionCreation, (transactionCreation) => transactionCreation.transaction) transactionCreation: TransactionCreation - - static async findByTransactionTypeId(transactionTypeId: number): Promise { - return this.createQueryBuilder('transaction') - .where('transaction.transactionTypeId = :transactionTypeId', { - transactionTypeId: transactionTypeId, - }) - .getMany() - } - - static async getDecayStartBlock(): Promise { - return this.createQueryBuilder('transaction') - .where('transaction.transactionTypeId = :transactionTypeId', { transactionTypeId: 9 }) - .orderBy('received', 'ASC') - .getOne() - } } diff --git a/backend/src/typeorm/entity/User.ts b/backend/src/typeorm/entity/User.ts index 84a40a5cd..ad76bd4a3 100644 --- a/backend/src/typeorm/entity/User.ts +++ b/backend/src/typeorm/entity/User.ts @@ -28,25 +28,4 @@ export class User extends BaseEntity { @Column() disabled: boolean - - // Moriz: I am voting for the data mapper implementation. - // see: https://typeorm.io/#/active-record-data-mapper/what-is-the-data-mapper-pattern - // We should discuss this ASAP - static findByPubkeyHex(pubkeyHex: string): Promise { - return this.createQueryBuilder('user') - .where('hex(user.pubkey) = :pubkeyHex', { pubkeyHex }) - .getOneOrFail() - } - - static async getUsersIndiced(userIds: number[]): Promise { - const users = await this.createQueryBuilder('user') - .select(['user.id', 'user.firstName', 'user.lastName', 'user.email']) - .where('user.id IN (:...users)', { users: userIds }) - .getMany() - const usersIndiced: User[] = [] - users.forEach((value) => { - usersIndiced[value.id] = value - }) - return usersIndiced - } } diff --git a/backend/src/typeorm/entity/UserTransaction.ts b/backend/src/typeorm/entity/UserTransaction.ts index 2f5bd69fc..7e24b66b0 100644 --- a/backend/src/typeorm/entity/UserTransaction.ts +++ b/backend/src/typeorm/entity/UserTransaction.ts @@ -19,18 +19,4 @@ export class UserTransaction extends BaseEntity { @Column({ name: 'balance_date', type: 'timestamp' }) balanceDate: Date - - static findByUserPaged( - userId: number, - limit: number, - offset: number, - order: 'ASC' | 'DESC', - ): Promise<[UserTransaction[], number]> { - return this.createQueryBuilder('userTransaction') - .where('userTransaction.userId = :userId', { userId }) - .orderBy('userTransaction.balanceDate', order) - .limit(limit) - .offset(offset) - .getManyAndCount() - } } diff --git a/backend/src/typeorm/repository/Balance.ts b/backend/src/typeorm/repository/Balance.ts new file mode 100644 index 000000000..2cec58fdf --- /dev/null +++ b/backend/src/typeorm/repository/Balance.ts @@ -0,0 +1,11 @@ +import { EntityRepository, Repository } from 'typeorm' +import { Balance } from '../entity/Balance' + +@EntityRepository(Balance) +export class BalanceRepository extends Repository { + findByUser(userId: number): Promise { + return this.createQueryBuilder('balance') + .where('balance.userId = :userId', { userId }) + .getOneOrFail() + } +} diff --git a/backend/src/typeorm/repository/Transaction.ts b/backend/src/typeorm/repository/Transaction.ts new file mode 100644 index 000000000..2c26fe7b5 --- /dev/null +++ b/backend/src/typeorm/repository/Transaction.ts @@ -0,0 +1,28 @@ +import { EntityRepository, Repository } from 'typeorm' +import { Transaction } from '../entity/Transaction' + +@EntityRepository(Transaction) +export class TransactionRepository extends Repository { + async findDecayStartBlock(): Promise { + return this.createQueryBuilder('transaction') + .where('transaction.transactionTypeId = :transactionTypeId', { transactionTypeId: 9 }) + .orderBy('received', 'ASC') + .getOne() + } + + async joinFullTransactionsByIds(transactionIds: number[]): Promise { + return this.createQueryBuilder('transaction') + .where('transaction.id IN (:...transactions)', { transactions: transactionIds }) + .leftJoinAndSelect( + 'transaction.transactionSendCoin', + 'transactionSendCoin', + // 'transactionSendCoin.transaction_id = transaction.id', + ) + .leftJoinAndSelect( + 'transaction.transactionCreation', + 'transactionCreation', + // 'transactionSendCoin.transaction_id = transaction.id', + ) + .getMany() + } +} diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts new file mode 100644 index 000000000..2a2299a4c --- /dev/null +++ b/backend/src/typeorm/repository/User.ts @@ -0,0 +1,23 @@ +import { EntityRepository, Repository } from 'typeorm' +import { User } from '../entity/User' + +@EntityRepository(User) +export class UserRepository extends Repository { + async findByPubkeyHex(pubkeyHex: string): Promise { + return this.createQueryBuilder('user') + .where('hex(user.pubkey) = :pubkeyHex', { pubkeyHex }) + .getOneOrFail() + } + + async getUsersIndiced(userIds: number[]): Promise { + const users = await this.createQueryBuilder('user') + .select(['user.id', 'user.firstName', 'user.lastName', 'user.email']) + .where('user.id IN (:...users)', { users: userIds }) + .getMany() + const usersIndiced: User[] = [] + users.forEach((value) => { + usersIndiced[value.id] = value + }) + return usersIndiced + } +} diff --git a/backend/src/typeorm/repository/UserTransaction.ts b/backend/src/typeorm/repository/UserTransaction.ts new file mode 100644 index 000000000..7efd8f12b --- /dev/null +++ b/backend/src/typeorm/repository/UserTransaction.ts @@ -0,0 +1,19 @@ +import { EntityRepository, Repository } from 'typeorm' +import { UserTransaction } from '../entity/UserTransaction' + +@EntityRepository(UserTransaction) +export class UserTransactionRepository extends Repository { + findByUserPaged( + userId: number, + limit: number, + offset: number, + order: 'ASC' | 'DESC', + ): Promise<[UserTransaction[], number]> { + return this.createQueryBuilder('userTransaction') + .where('userTransaction.userId = :userId', { userId }) + .orderBy('userTransaction.balanceDate', order) + .limit(limit) + .offset(offset) + .getManyAndCount() + } +} diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index 3d39b198f..7b064b0b1 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -1,4 +1,6 @@ +import { getCustomRepository } from 'typeorm' import { Decay } from '../graphql/models/Decay' +import { TransactionRepository } from '../typeorm/repository/Transaction' function decayFormula(amount: number, durationInSeconds: number): number { return amount * Math.pow(0.99999997802044727, durationInSeconds) @@ -6,7 +8,8 @@ function decayFormula(amount: number, durationInSeconds: number): number { async function calculateDecay(amount: number, from: Date, to: Date): Promise { // load decay start block - const decayStartBlock = await Decay.getDecayStartBlock() + const transactionRepository = getCustomRepository(TransactionRepository) + const decayStartBlock = await transactionRepository.findDecayStartBlock() // if decay hasn't started yet we return input amount if (!decayStartBlock) return amount @@ -20,7 +23,8 @@ async function calculateDecayWithInterval( from: number | Date, to: number | Date, ): Promise { - const decayStartBlock = await Decay.getDecayStartBlock() + const transactionRepository = getCustomRepository(TransactionRepository) + const decayStartBlock = await transactionRepository.findDecayStartBlock() const result = new Decay(undefined) result.balance = amount