feat: Adds script to generate database seeded values and removes old mock storage.

This commit is contained in:
2025-01-16 21:00:27 -05:00
parent 09b46f672a
commit e1d07008a1
16 changed files with 399 additions and 535 deletions

View File

@@ -32,70 +32,3 @@ extension Employee.Update: Content {}
extension DatabaseClient.Employees: TestDependencyKey {
public static let testValue = Self()
}
#if DEBUG
typealias EmployeeMockStorage = MockStorage<
Employee,
Employee.Create,
DatabaseClient.Employees.FetchRequest,
Void,
Employee.Update
>
private extension EmployeeMockStorage {
init(_ mocks: [Employee]) {
@Dependency(\.date.now) var now
@Dependency(\.uuid) var uuid
self.init(
mocks,
create: { employee in
Employee(
id: uuid(),
active: employee.active ?? true,
createdAt: now,
firstName: employee.firstName,
lastName: employee.lastName,
updatedAt: now
)
},
fetch: { request in
switch request {
case .all:
return { _ in true }
case .active:
return { $0.active == true }
case .inactive:
return { $0.active == false }
}
},
update: { employee, updates in
let model = Employee(
id: employee.id,
active: updates.active ?? employee.active,
createdAt: employee.createdAt,
firstName: updates.firstName ?? employee.firstName,
lastName: updates.lastName ?? employee.lastName,
updatedAt: now
)
employee = model
}
)
}
}
public extension DatabaseClient.Employees {
static func mock(_ mocks: [Employee] = []) -> Self {
let storage = EmployeeMockStorage(mocks)
return .init(
create: { try await storage.create($0) },
delete: { try await storage.delete($0) },
fetchAll: { try await storage.fetchAll($0) },
get: { try await storage.get($0) },
update: { try await storage.update($0, $1) }
)
}
}
#endif

View File

@@ -1,142 +0,0 @@
#if DEBUG
import Dependencies
import Vapor
actor MockStorage<
Model: Identifiable,
Create: Sendable,
Fetch: Sendable,
Get: Sendable,
Update: Sendable
> where Model: Sendable {
@Dependency(\.date.now) var now
@Dependency(\.uuid) var uuid
private var storage: [Model.ID: Model]
private let modelFromCreate: @Sendable (Create) async throws -> Model
private let fetchToPredicate: @Sendable (Fetch) -> ((Model) -> Bool)
private let fetchExtras: @Sendable (Fetch, [Model]) async throws -> [Model]
private let applyUpdates: @Sendable (inout Model, Update, Get?) async throws -> Void
private let getExtras: @Sendable (Get?, Model) async throws -> Model
init(
_ mocks: [Model] = [],
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
fetch fetchToPredicate: @Sendable @escaping (Fetch) -> ((Model) -> Bool),
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
get getExtras: @Sendable @escaping (Get?, Model) async throws -> Model,
update applyUpdates: @Sendable @escaping (inout Model, Update, Get?) async throws -> Void
) {
self.storage = mocks.reduce(into: [Model.ID: Model]()) { $0[$1.id] = $1 }
self.modelFromCreate = modelFromCreate
self.fetchToPredicate = fetchToPredicate
self.fetchExtras = fetchExtras
self.applyUpdates = applyUpdates
self.getExtras = getExtras
}
func count() async throws -> Int {
storage.count
}
func create(_ create: Create) async throws -> Model {
let model = try await modelFromCreate(create)
storage[model.id] = model
return model
}
func delete(_ id: Model.ID) async throws {
storage[id] = nil
}
func fetchAll(_ request: Fetch) async throws -> [Model] {
let predicate = fetchToPredicate(request)
return try await fetchExtras(request, Array(storage.values.filter { predicate($0) }))
}
func get(_ id: Model.ID, _ request: Get?) async throws -> Model? {
if let model = storage[id] {
return try await getExtras(request, model)
}
return nil
}
func update(_ id: Model.ID, _ updates: Update, _ get: Get?) async throws -> Model {
guard var model = storage[id] else {
throw Abort(.badRequest, reason: "Model not found.")
}
try await applyUpdates(&model, updates, get)
storage[id] = model
return model
}
}
extension MockStorage where Get == Void {
init(
_ mocks: [Model] = [],
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
fetch fetchToPredicate: @Sendable @escaping (Fetch) -> ((Model) -> Bool),
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
update applyUpdates: @Sendable @escaping (inout Model, Update) async throws -> Void
) {
self.init(
mocks,
create: modelFromCreate,
fetch: fetchToPredicate,
fetchExtras: fetchExtras,
get: { _, model in model },
update: { model, updates, _ in try await applyUpdates(&model, updates) }
)
}
func get(_ id: Model.ID) async throws -> Model? {
storage[id]
}
func update(_ id: Model.ID, _ updates: Update) async throws -> Model {
try await update(id, updates, ())
}
}
extension MockStorage where Fetch == Void {
init(
_ mocks: [Model] = [],
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
get getExtras: @Sendable @escaping (Get?, Model) async throws -> Model,
update applyUpdates: @Sendable @escaping (inout Model, Update, Get?) async throws -> Void
) {
self.init(
mocks,
create: modelFromCreate,
fetch: { _ in { _ in true } },
fetchExtras: fetchExtras,
get: getExtras,
update: applyUpdates
)
}
func fetchAll() async throws -> [Model] {
try await fetchAll(())
}
}
extension MockStorage where Fetch == Void, Get == Void {
init(
_ mocks: [Model] = [],
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
update applyUpdates: @Sendable @escaping (inout Model, Update) async throws -> Void
) {
self.init(
mocks,
create: modelFromCreate,
fetchExtras: fetchExtras,
get: { _, model in model },
update: { model, updates, _ in try await applyUpdates(&model, updates) }
)
}
}
#endif

View File

@@ -22,74 +22,3 @@ extension PurchaseOrder.Create: Content {}
extension DatabaseClient.PurchaseOrders: TestDependencyKey {
public static let testValue: DatabaseClient.PurchaseOrders = Self()
}
#if DEBUG
typealias PurchaseOrderMockStorage = MockStorage<
PurchaseOrder,
PurchaseOrder.Create,
Void,
Void,
Void
>
public extension DependencyValues {
var purchaseOrderID: PurchaseOrderIDGenerator {
get { self[PurchaseOrderIDGenerator.self] }
set { self[PurchaseOrderIDGenerator.self] = newValue }
}
}
@DependencyClient
public struct PurchaseOrderIDGenerator: Sendable {
var nextID: @Sendable () async throws -> Int
}
extension PurchaseOrderIDGenerator: DependencyKey {
public static let testValue: PurchaseOrderIDGenerator = .liveValue
public static var liveValue: Self {
let counter = Counter()
return .init(nextID: { await counter.nextID() })
}
actor Counter {
private var count: Int
init(starting: Int = 1) {
self.count = starting
}
func nextID() async -> Int {
count += 1
return count
}
}
}
// private extension PurchaseOrderMockStorage {
// static func make(_ mocks: [PurchaseOrder]) -> Self {
// @Dependency(\.date.now) var now
// @Dependency(\.purchaseOrderID) var purchaseOrderID
//
// return .init(
// mocks,
// create: { model in
// try await PurchaseOrder(
// id: purchaseOrderID.nextID(),
// workOrder: model.workOrder,
// materials: model.materials,
// customer: model.customer,
// truckStock: model.truckStock,
// createdBy: model.createdForID,
// createdFor: model.createdForID,
// vendorBranch: .i
//
// )
// },
// update: { _, _ in
// fatalError()
// }
// )
// }
// }
#endif

View File

@@ -28,66 +28,3 @@ extension User.Update: Content {}
extension DatabaseClient.Users: TestDependencyKey {
public static let testValue: DatabaseClient.Users = Self()
}
#if DEBUG
typealias UserMockStorage = MockStorage<
User,
User.Create,
Void,
Void,
User.Update
>
private extension UserMockStorage {
static func make(_ mocks: [User]) -> Self {
@Dependency(\.date.now) var now
@Dependency(\.uuid) var uuid
return .init(
create: { model in
User(
id: uuid(),
email: model.email,
username: model.username,
createdAt: now,
updatedAt: now
)
},
update: { model, updates in
let user = User(
id: model.id,
email: updates.email ?? model.email,
username: updates.username ?? model.username,
createdAt: model.createdAt,
updatedAt: now
)
model = user
}
)
}
}
public extension User.Token {
static func mock(id: User.ID) -> Self {
.init(id: UUID(0), userID: id, value: "test")
}
}
public extension DatabaseClient.Users {
static func mock(_ mocks: [User]) -> Self {
let storage = UserMockStorage.make(mocks)
return .init(
count: { try await storage.count() },
create: { try await storage.create($0) },
delete: { try await storage.delete($0) },
fetchAll: { try await storage.fetchAll() },
get: { try await storage.get($0) },
login: { _ in .mock(id: UUID(0)) },
logout: { _ in },
token: { .mock(id: $0) },
update: { try await storage.update($0, $1) }
)
}
}
#endif

View File

@@ -31,61 +31,3 @@ extension DatabaseClient.VendorBranches.FetchRequest: Content {}
extension DatabaseClient.VendorBranches: TestDependencyKey {
public static let testValue: DatabaseClient.VendorBranches = Self()
}
#if DEBUG
typealias VendorBranchMockStorage = MockStorage<
VendorBranch,
VendorBranch.Create,
DatabaseClient.VendorBranches.FetchRequest,
Void,
VendorBranch.Update
>
private extension VendorBranchMockStorage {
init(_ mocks: [VendorBranch]) {
@Dependency(\.date.now) var now
@Dependency(\.uuid) var uuid
self.init(
mocks,
create: {
VendorBranch(id: uuid(), name: $0.name, vendorID: $0.vendorID, createdAt: now, updatedAt: now)
},
fetch: { request in
switch request {
case .all:
return { _ in true }
case let .for(vendorID):
return { $0.vendorID == vendorID }
}
},
update: { branch, updates in
let model = VendorBranch(
id: branch.id,
name: updates.name ?? branch.name,
vendorID: branch.vendorID,
createdAt: branch.createdAt,
updatedAt: now
)
branch = model
}
)
}
}
public extension DatabaseClient.VendorBranches {
static func mock(_ mocks: [VendorBranch] = []) -> Self {
let storage = VendorBranchMockStorage(mocks)
return .init(
create: { try await storage.create($0) },
delete: { try await storage.delete($0) },
fetchAll: { try await storage.fetchAll($0) },
get: { try await storage.get($0) },
update: { try await storage.update($0, $1) }
)
}
}
#endif

View File

@@ -51,94 +51,3 @@ extension DatabaseClient.Vendors.GetRequest: Content {}
extension DatabaseClient.Vendors: TestDependencyKey {
public static let testValue: DatabaseClient.Vendors = Self()
}
#if DEBUG
typealias VendorMockStorage = MockStorage<
Vendor,
Vendor.Create,
DatabaseClient.Vendors.FetchRequest,
DatabaseClient.Vendors.GetRequest,
Vendor.Update
>
private extension VendorMockStorage {
// swiftlint:disable function_body_length
static func vendors(_ mocks: [Vendor]) -> Self {
@Dependency(\.date.now) var now
@Dependency(\.uuid) var uuid
@Dependency(\.database.vendorBranches) var vendorBranches
return .init(
mocks,
create: {
Vendor(
id: uuid(),
name: $0.name,
createdAt: now,
updatedAt: now
)
},
fetch: { _ in
{ _ in true }
},
fetchExtras: { request, models in
guard request == .withBranches else { return models }
let branches = try await vendorBranches.fetchAll()
return models.map { model in
Vendor(
id: model.id,
name: model.name,
branches: Array(branches.filter { $0.vendorID == model.id }),
createdAt: model.createdAt,
updatedAt: model.updatedAt
)
}
},
get: { req, model in
guard req == .withBranches else { return model }
let branches = try await vendorBranches.fetchAll(.for(vendorID: model.id))
return Vendor(
id: model.id,
name: model.name,
branches: branches,
createdAt: model.createdAt,
updatedAt: model.updatedAt
)
},
update: { model, updates, get in
var branches: [VendorBranch]?
if get == .withBranches {
branches = try await vendorBranches.fetchAll(.for(vendorID: model.id))
}
let vendor = Vendor(
id: model.id,
name: updates.name ?? model.name,
branches: branches ?? model.branches,
createdAt: model.createdAt,
updatedAt: now
)
model = vendor
}
)
}
// swiftlint:enable function_body_length
}
public extension DatabaseClient.Vendors {
static func mock(_ mocks: [Vendor]) -> Self {
let storage = VendorMockStorage.vendors(mocks)
return .init(
create: { try await storage.create($0) },
delete: { try await storage.delete($0) },
fetchAll: { try await storage.fetchAll($0) },
get: { try await storage.get($0, $1) },
update: { req, updates, get in try await storage.update(req, updates, get) }
)
}
}
#endif