Skip to content

Commit

Permalink
fix aggregates bug for postgres.
Browse files Browse the repository at this point in the history
  • Loading branch information
hsharghi committed Jun 17, 2023
1 parent a999bb0 commit 713b577
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 268 deletions.
26 changes: 21 additions & 5 deletions Sources/VaporWallet/HasWallet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Vapor
import Fluent
import FluentPostgresDriver

public protocol HasWallet: FluentKit.Model {
static var idKey: KeyPath<Self, Self.ID<UUID>> { get }
Expand All @@ -27,12 +28,27 @@ extension HasWallet {

extension Wallet {
public func refreshBalanceAsync(on db: Database) async throws -> Double {
let balance = try await self.$transactions
.query(on: db)
.filter(\.$confirmed == true)
.sum(\.$amount)

var balance: Int
// Temporary workaround for sum and average aggregates on Postgres DB
if let _ = db as? PostgresDatabase {
let balanceOptional = try? await self.$transactions
.query(on: db)
.filter(\.$confirmed == true)
.aggregate(.sum, \.$amount, as: Double.self)

balance = balanceOptional == nil ? 0 : Int(balanceOptional!)
} else {
let intBalance = try await self.$transactions
.query(on: db)
.filter(\.$confirmed == true)
.sum(\.$amount)

balance = intBalance ?? 0
}

self.balance = balance ?? 0
self.balance = balance

try await self.update(on: db)
return Double(self.balance)
}
Expand Down
64 changes: 32 additions & 32 deletions Sources/VaporWallet/Migrations/CreateWallet.swift
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
import Fluent
import SQLKit

public struct CreateWallet: Migration {
private var idKey: String
public init(foreignKeyColumnName idKey: String = "id") {
self.idKey = idKey
}
public func prepare(on database: Database) -> EventLoopFuture<Void> {
return database.schema(Wallet.schema)
.id()
.field("name", .string, .required)
.field("owner_type", .string, .required)
.field("owner_id", .uuid, .required)
.field("min_allowed_balance", .int, .required)
.field("balance", .int, .required)
.field("decimal_places", .uint8, .required)
.field("created_at", .datetime, .required)
.field("updated_at", .datetime, .required)
.field("deleted_at", .datetime)
.create().flatMap { _ in
let sqlDB = (database as! SQLDatabase)
return sqlDB
.create(index: "type_idx")
.on(Wallet.schema)
.column("owner_type")
.run()
}
}
public func revert(on database: Database) -> EventLoopFuture<Void> {
return database.schema(Wallet.schema).delete()
}
}
//public struct CreateWallet: Migration {
// private var idKey: String
// public init(foreignKeyColumnName idKey: String = "id") {
// self.idKey = idKey
// }
//
// public func prepare(on database: Database) -> EventLoopFuture<Void> {
// return database.schema(Wallet.schema)
// .id()
// .field("name", .string, .required)
// .field("owner_type", .string, .required)
// .field("owner_id", .uuid, .required)
// .field("min_allowed_balance", .int, .required)
// .field("balance", .int, .required)
// .field("decimal_places", .uint8, .required)
// .field("created_at", .datetime, .required)
// .field("updated_at", .datetime, .required)
// .field("deleted_at", .datetime)
// .create().flatMap { _ in
// let sqlDB = (database as! SQLDatabase)
// return sqlDB
// .create(index: "type_idx")
// .on(Wallet.schema)
// .column("owner_type")
// .run()
// }
// }
//
// public func revert(on database: Database) -> EventLoopFuture<Void> {
// return database.schema(Wallet.schema).delete()
// }
//}

public struct CreateWalletAsync: AsyncMigration {
private var idKey: String
Expand Down
73 changes: 34 additions & 39 deletions Sources/VaporWallet/Migrations/CreateWalletTransaction.swift
Original file line number Diff line number Diff line change
@@ -1,50 +1,47 @@
import Fluent

public struct CreateWalletTransaction: Migration {
public init() { }

public func prepare(on database: Database) -> EventLoopFuture<Void> {
return database.enum("type")
.case("deposit")
.case("withdraw")
.create().flatMap { transactionType in
return database.schema(WalletTransaction.schema)
.id()
.field("wallet_id", .uuid, .required, .references(Wallet.schema, "id", onDelete: .cascade))
.field("type", transactionType, .required)
.field("amount", .int, .required)
.field("confirmed", .bool, .required)
.field("meta", .json)
.field("created_at", .datetime, .required)
.field("updated_at", .datetime, .required)
.create()
}
}

public func revert(on database: Database) -> EventLoopFuture<Void> {
return database.enum("type")
.deleteCase("deposit")
.deleteCase("withdraw")
.update().flatMap { _ in
return database.schema(WalletTransaction.schema).delete()
}

}
}
//public struct CreateWalletTransaction: Migration {
// public init() { }
//
// public func prepare(on database: Database) -> EventLoopFuture<Void> {
// return database.enum("type")
// .case("deposit")
// .case("withdraw")
// .create().flatMap { transactionType in
// return database.schema(WalletTransaction.schema)
// .id()
// .field("wallet_id", .uuid, .required, .references(Wallet.schema, "id", onDelete: .cascade))
// .field("type", transactionType, .required)
// .field("amount", .int, .required)
// .field("confirmed", .bool, .required)
// .field("meta", .json)
// .field("created_at", .datetime, .required)
// .field("updated_at", .datetime, .required)
// .create()
// }
// }
//
// public func revert(on database: Database) -> EventLoopFuture<Void> {
// return database.enum("type")
// .deleteCase("deposit")
// .deleteCase("withdraw")
// .update().flatMap { _ in
// return database.schema(WalletTransaction.schema).delete()
// }
//
// }
//}

public struct CreateWalletTransactionAsync: AsyncMigration {
public init() { }

public func prepare(on database: Database) async throws {
do {
try await database.enum("transaction_type").delete()
} catch { }


let transactionType = try await database.enum("transaction_type")
.case("deposit")
.case("withdraw")
.create()

try await database.schema(WalletTransaction.schema)
.id()
.field("wallet_id", .uuid, .required, .references(Wallet.schema, "id", onDelete: .cascade))
Expand All @@ -59,10 +56,8 @@ public struct CreateWalletTransactionAsync: AsyncMigration {


public func revert(on database: Database) async throws {
do {
try await database.enum("transaction_type").delete()
} catch { }
try await database.schema(WalletTransaction.schema).delete()
try await database.enum("transaction_type").delete()
}

}
25 changes: 17 additions & 8 deletions Sources/VaporWallet/WalletRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Vapor
import Fluent
import FluentPostgresDriver

/// This calss gives access to wallet methods for a `HasWallet` model.
/// Creating multiple wallets, accessing them and getting balance of each wallet,
Expand Down Expand Up @@ -53,7 +54,7 @@ extension WalletsRepository {
.filter(\.$owner == self.id)
.filter(\.$ownerType == self.type)
.filter(\.$name == name.value)

if (withTransactions) {
walletQuery = walletQuery.with(\.$transactions)
}
Expand All @@ -72,13 +73,21 @@ extension WalletsRepository {
public func balanceAsync(type name: WalletType = .default, withUnconfirmed: Bool = false, asDecimal: Bool = false) async throws -> Double {
let wallet = try await getAsync(type: name)
if withUnconfirmed {
let intBalance = try await wallet.$transactions
.query(on: self.db)
.sum(\.$amount)
.get()

let balance = intBalance == nil ? 0.0 : Double(intBalance!)

// (1) Temporary workaround for sum and average aggregates,
var balance: Double
if let _ = self.db as? PostgresDatabase {
let balanceOptional = try? await wallet.$transactions
.query(on: self.db)
.aggregate(.sum, \.$amount, as: Double.self)

balance = balanceOptional ?? 0.0
} else {
let intBalance = try await wallet.$transactions
.query(on: self.db)
.sum(\.$amount)

balance = intBalance == nil ? 0.0 : Double(intBalance!)
}
return asDecimal ? balance.toDecimal(with: wallet.decimalPlaces) : balance
}
return asDecimal ? Double(wallet.balance).toDecimal(with: wallet.decimalPlaces) : Double(wallet.balance)
Expand Down
Loading

0 comments on commit 713b577

Please sign in to comment.