feat: Updates to use swift-validations for database.
All checks were successful
CI / Linux Tests (push) Successful in 6m28s
All checks were successful
CI / Linux Tests (push) Successful in 6m28s
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"originHash" : "300df15f5af26da69cfcf959d16ee1b9eada6101dc105a17fc01ddd244d476b4",
|
"originHash" : "ed354a8e92f6b810403986d192b495a0e8e67cc9577e8ec24bce4ba275c0513d",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "async-http-client",
|
"identity" : "async-http-client",
|
||||||
@@ -415,6 +415,15 @@
|
|||||||
"version" : "0.6.2"
|
"version" : "0.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-validations",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/m-housh/swift-validations.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "95ea5d267e37f6cdb9f91c5c8a01e718b9299db6",
|
||||||
|
"version" : "0.3.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "vapor",
|
"identity" : "vapor",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ let package = Package(
|
|||||||
.package(url: "https://github.com/elementary-swift/elementary.git", from: "0.6.0"),
|
.package(url: "https://github.com/elementary-swift/elementary.git", from: "0.6.0"),
|
||||||
.package(url: "https://github.com/elementary-swift/elementary-htmx.git", from: "0.5.0"),
|
.package(url: "https://github.com/elementary-swift/elementary-htmx.git", from: "0.5.0"),
|
||||||
.package(url: "https://github.com/vapor-community/vapor-elementary.git", from: "0.1.0"),
|
.package(url: "https://github.com/vapor-community/vapor-elementary.git", from: "0.1.0"),
|
||||||
|
.package(url: "https://github.com/m-housh/swift-validations.git", from: "0.1.0"),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.executableTarget(
|
.executableTarget(
|
||||||
@@ -67,6 +68,7 @@ let package = Package(
|
|||||||
.product(name: "DependenciesMacros", package: "swift-dependencies"),
|
.product(name: "DependenciesMacros", package: "swift-dependencies"),
|
||||||
.product(name: "Fluent", package: "fluent"),
|
.product(name: "Fluent", package: "fluent"),
|
||||||
.product(name: "Vapor", package: "vapor"),
|
.product(name: "Vapor", package: "vapor"),
|
||||||
|
.product(name: "Validations", package: "swift-validations"),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
|
|||||||
48
Sources/DatabaseClient/Internal/Array+validator.swift
Normal file
48
Sources/DatabaseClient/Internal/Array+validator.swift
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import Validations
|
||||||
|
|
||||||
|
extension Validator {
|
||||||
|
|
||||||
|
static func validate<Child: Validatable>(
|
||||||
|
_ toChild: KeyPath<Value, [Child]>
|
||||||
|
)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
|
self.mapValue({ $0[keyPath: toChild] }, with: ArrayValidator())
|
||||||
|
}
|
||||||
|
|
||||||
|
static func validate<Child: Validatable>(
|
||||||
|
_ toChild: KeyPath<Value, [Child]?>
|
||||||
|
)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
|
self.mapValue({ $0[keyPath: toChild] }, with: ArrayValidator().optional())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Array where Element: Validatable {
|
||||||
|
static func validator() -> some Validation<Self> {
|
||||||
|
ArrayValidator<Element>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ArrayValidator<Element>: Validation where Element: Validatable {
|
||||||
|
func validate(_ value: [Element]) throws {
|
||||||
|
for item in value {
|
||||||
|
try item.validate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ForEachValidator<T, E>: Validation where T: Validation, T.Value == E {
|
||||||
|
let validator: T
|
||||||
|
|
||||||
|
init(@ValidationBuilder<E> builder: () -> T) {
|
||||||
|
self.validator = builder()
|
||||||
|
}
|
||||||
|
|
||||||
|
func validate(_ value: [E]) throws {
|
||||||
|
for item in value {
|
||||||
|
try validator.validate(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import Fluent
|
|||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
import SQLKit
|
import SQLKit
|
||||||
|
import Validations
|
||||||
|
|
||||||
extension DatabaseClient.ComponentLosses: TestDependencyKey {
|
extension DatabaseClient.ComponentLosses: TestDependencyKey {
|
||||||
public static let testValue = Self()
|
public static let testValue = Self()
|
||||||
@@ -13,8 +14,8 @@ extension DatabaseClient.ComponentLosses {
|
|||||||
public static func live(database: any Database) -> Self {
|
public static func live(database: any Database) -> Self {
|
||||||
.init(
|
.init(
|
||||||
create: { request in
|
create: { request in
|
||||||
let model = try request.toModel()
|
let model = request.toModel()
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
},
|
},
|
||||||
delete: { id in
|
delete: { id in
|
||||||
@@ -35,13 +36,13 @@ extension DatabaseClient.ComponentLosses {
|
|||||||
try await ComponentLossModel.find(id, on: database).map { try $0.toDTO() }
|
try await ComponentLossModel.find(id, on: database).map { try $0.toDTO() }
|
||||||
},
|
},
|
||||||
update: { id, updates in
|
update: { id, updates in
|
||||||
try updates.validate()
|
// try updates.validate()
|
||||||
guard let model = try await ComponentLossModel.find(id, on: database) else {
|
guard let model = try await ComponentLossModel.find(id, on: database) else {
|
||||||
throw NotFoundError()
|
throw NotFoundError()
|
||||||
}
|
}
|
||||||
model.applyUpdates(updates)
|
model.applyUpdates(updates)
|
||||||
if model.hasChanges {
|
if model.hasChanges {
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
}
|
}
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
}
|
}
|
||||||
@@ -51,40 +52,9 @@ extension DatabaseClient.ComponentLosses {
|
|||||||
|
|
||||||
extension ComponentPressureLoss.Create {
|
extension ComponentPressureLoss.Create {
|
||||||
|
|
||||||
func toModel() throws(ValidationError) -> ComponentLossModel {
|
func toModel() -> ComponentLossModel {
|
||||||
try validate()
|
|
||||||
return .init(name: name, value: value, projectID: projectID)
|
return .init(name: name, value: value, projectID: projectID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
guard !name.isEmpty else {
|
|
||||||
throw ValidationError("Component loss name should not be empty.")
|
|
||||||
}
|
|
||||||
guard value > 0 else {
|
|
||||||
throw ValidationError("Component loss value should be greater than 0.")
|
|
||||||
}
|
|
||||||
guard value < 1.0 else {
|
|
||||||
throw ValidationError("Component loss value should be less than 1.0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ComponentPressureLoss.Update {
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
if let name {
|
|
||||||
guard !name.isEmpty else {
|
|
||||||
throw ValidationError("Component loss name should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let value {
|
|
||||||
guard value > 0 else {
|
|
||||||
throw ValidationError("Component loss value should be greater than 0.")
|
|
||||||
}
|
|
||||||
guard value < 1.0 else {
|
|
||||||
throw ValidationError("Component loss value should be less than 1.0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ComponentPressureLoss {
|
extension ComponentPressureLoss {
|
||||||
@@ -171,3 +141,19 @@ final class ComponentLossModel: Model, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ComponentLossModel: Validatable {
|
||||||
|
|
||||||
|
var body: some Validation<ComponentLossModel> {
|
||||||
|
Validator.accumulating {
|
||||||
|
Validator.validate(\.name, with: .notEmpty())
|
||||||
|
.errorLabel("Name", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.value) {
|
||||||
|
Double.greaterThan(0.0)
|
||||||
|
Double.lessThanOrEquals(1.0)
|
||||||
|
}
|
||||||
|
.errorLabel("Value", inline: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import DependenciesMacros
|
|||||||
import Fluent
|
import Fluent
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
|
import Validations
|
||||||
|
|
||||||
extension DatabaseClient.Equipment: TestDependencyKey {
|
extension DatabaseClient.Equipment: TestDependencyKey {
|
||||||
public static let testValue = Self()
|
public static let testValue = Self()
|
||||||
@@ -10,8 +11,8 @@ extension DatabaseClient.Equipment: TestDependencyKey {
|
|||||||
public static func live(database: any Database) -> Self {
|
public static func live(database: any Database) -> Self {
|
||||||
.init(
|
.init(
|
||||||
create: { request in
|
create: { request in
|
||||||
let model = try request.toModel()
|
let model = request.toModel()
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
},
|
},
|
||||||
delete: { id in
|
delete: { id in
|
||||||
@@ -37,10 +38,9 @@ extension DatabaseClient.Equipment: TestDependencyKey {
|
|||||||
guard let model = try await EquipmentModel.find(id, on: database) else {
|
guard let model = try await EquipmentModel.find(id, on: database) else {
|
||||||
throw NotFoundError()
|
throw NotFoundError()
|
||||||
}
|
}
|
||||||
try updates.validate()
|
|
||||||
model.applyUpdates(updates)
|
model.applyUpdates(updates)
|
||||||
if model.hasChanges {
|
if model.hasChanges {
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
}
|
}
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
}
|
}
|
||||||
@@ -50,8 +50,7 @@ extension DatabaseClient.Equipment: TestDependencyKey {
|
|||||||
|
|
||||||
extension EquipmentInfo.Create {
|
extension EquipmentInfo.Create {
|
||||||
|
|
||||||
func toModel() throws(ValidationError) -> EquipmentModel {
|
func toModel() -> EquipmentModel {
|
||||||
try validate()
|
|
||||||
return .init(
|
return .init(
|
||||||
staticPressure: staticPressure,
|
staticPressure: staticPressure,
|
||||||
heatingCFM: heatingCFM,
|
heatingCFM: heatingCFM,
|
||||||
@@ -60,44 +59,6 @@ extension EquipmentInfo.Create {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
guard staticPressure >= 0 else {
|
|
||||||
throw ValidationError("Equipment info static pressure should be greater than 0.")
|
|
||||||
}
|
|
||||||
guard staticPressure <= 1.0 else {
|
|
||||||
throw ValidationError("Equipment info static pressure should be less than 1.0.")
|
|
||||||
}
|
|
||||||
guard heatingCFM >= 0 else {
|
|
||||||
throw ValidationError("Equipment info heating CFM should be greater than 0.")
|
|
||||||
}
|
|
||||||
guard coolingCFM >= 0 else {
|
|
||||||
throw ValidationError("Equipment info heating CFM should be greater than 0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension EquipmentInfo.Update {
|
|
||||||
var hasUpdates: Bool {
|
|
||||||
staticPressure != nil || heatingCFM != nil || coolingCFM != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
if let staticPressure {
|
|
||||||
guard staticPressure >= 0 else {
|
|
||||||
throw ValidationError("Equipment info static pressure should be greater than 0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let heatingCFM {
|
|
||||||
guard heatingCFM >= 0 else {
|
|
||||||
throw ValidationError("Equipment info heating CFM should be greater than 0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let coolingCFM {
|
|
||||||
guard coolingCFM >= 0 else {
|
|
||||||
throw ValidationError("Equipment info heating CFM should be greater than 0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension EquipmentInfo {
|
extension EquipmentInfo {
|
||||||
@@ -197,3 +158,22 @@ final class EquipmentModel: Model, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension EquipmentModel: Validatable {
|
||||||
|
|
||||||
|
var body: some Validation<EquipmentModel> {
|
||||||
|
Validator.accumulating {
|
||||||
|
Validator.validate(\.staticPressure) {
|
||||||
|
Double.greaterThan(0.0)
|
||||||
|
Double.lessThan(1.0)
|
||||||
|
}
|
||||||
|
.errorLabel("Static Pressure", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.heatingCFM, with: .greaterThan(0))
|
||||||
|
.errorLabel("Heating CFM", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.coolingCFM, with: .greaterThan(0))
|
||||||
|
.errorLabel("Cooling CFM", inline: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import DependenciesMacros
|
|||||||
import Fluent
|
import Fluent
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
|
import Validations
|
||||||
|
|
||||||
extension DatabaseClient.EquivalentLengths: TestDependencyKey {
|
extension DatabaseClient.EquivalentLengths: TestDependencyKey {
|
||||||
public static let testValue = Self()
|
public static let testValue = Self()
|
||||||
@@ -11,7 +12,7 @@ extension DatabaseClient.EquivalentLengths: TestDependencyKey {
|
|||||||
.init(
|
.init(
|
||||||
create: { request in
|
create: { request in
|
||||||
let model = try request.toModel()
|
let model = try request.toModel()
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
},
|
},
|
||||||
delete: { id in
|
delete: { id in
|
||||||
@@ -53,7 +54,7 @@ extension DatabaseClient.EquivalentLengths: TestDependencyKey {
|
|||||||
}
|
}
|
||||||
try model.applyUpdates(updates)
|
try model.applyUpdates(updates)
|
||||||
if model.hasChanges {
|
if model.hasChanges {
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
}
|
}
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
}
|
}
|
||||||
@@ -64,7 +65,9 @@ extension DatabaseClient.EquivalentLengths: TestDependencyKey {
|
|||||||
extension EquivalentLength.Create {
|
extension EquivalentLength.Create {
|
||||||
|
|
||||||
func toModel() throws -> EffectiveLengthModel {
|
func toModel() throws -> EffectiveLengthModel {
|
||||||
try validate()
|
if groups.count > 0 {
|
||||||
|
try [EquivalentLength.FittingGroup].validator().validate(groups)
|
||||||
|
}
|
||||||
return try .init(
|
return try .init(
|
||||||
name: name,
|
name: name,
|
||||||
type: type.rawValue,
|
type: type.rawValue,
|
||||||
@@ -73,12 +76,6 @@ extension EquivalentLength.Create {
|
|||||||
projectID: projectID
|
projectID: projectID
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
guard !name.isEmpty else {
|
|
||||||
throw ValidationError("Effective length name can not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension EquivalentLength {
|
extension EquivalentLength {
|
||||||
@@ -184,7 +181,51 @@ final class EffectiveLengthModel: Model, @unchecked Sendable {
|
|||||||
self.straightLengths = straightLengths
|
self.straightLengths = straightLengths
|
||||||
}
|
}
|
||||||
if let groups = updates.groups {
|
if let groups = updates.groups {
|
||||||
|
if groups.count > 0 {
|
||||||
|
try [EquivalentLength.FittingGroup].validator().validate(groups)
|
||||||
|
}
|
||||||
self.groups = try JSONEncoder().encode(groups)
|
self.groups = try JSONEncoder().encode(groups)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension EffectiveLengthModel: Validatable {
|
||||||
|
|
||||||
|
var body: some Validation<EffectiveLengthModel> {
|
||||||
|
Validator.accumulating {
|
||||||
|
Validator.validate(\.name, with: .notEmpty())
|
||||||
|
.errorLabel("Name", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(
|
||||||
|
\.straightLengths,
|
||||||
|
with: [Int].empty().or(
|
||||||
|
ForEachValidator {
|
||||||
|
Int.greaterThan(0)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.errorLabel("Straight Lengths", inline: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension EquivalentLength.FittingGroup: Validatable {
|
||||||
|
|
||||||
|
public var body: some Validation<Self> {
|
||||||
|
Validator.accumulating {
|
||||||
|
Validator.validate(\.group) {
|
||||||
|
Int.greaterThanOrEquals(1)
|
||||||
|
Int.lessThanOrEquals(12)
|
||||||
|
}
|
||||||
|
.errorLabel("Group", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.letter, with: .regex(matching: "[a-zA-Z]"))
|
||||||
|
.errorLabel("Letter", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.value, with: .greaterThan(0))
|
||||||
|
.errorLabel("Value", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.quantity, with: .greaterThanOrEquals(1))
|
||||||
|
.errorLabel("Quantity", inline: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
10
Sources/DatabaseClient/Internal/Model+validateAndSave.swift
Normal file
10
Sources/DatabaseClient/Internal/Model+validateAndSave.swift
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import Fluent
|
||||||
|
import Validations
|
||||||
|
|
||||||
|
extension Model where Self: Validations.Validatable {
|
||||||
|
|
||||||
|
func validateAndSave(on database: any Database) async throws {
|
||||||
|
try self.validate()
|
||||||
|
try await self.save(on: database)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import DependenciesMacros
|
|||||||
import Fluent
|
import Fluent
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
|
import Validations
|
||||||
|
|
||||||
extension DatabaseClient.Projects: TestDependencyKey {
|
extension DatabaseClient.Projects: TestDependencyKey {
|
||||||
public static let testValue = Self()
|
public static let testValue = Self()
|
||||||
@@ -10,8 +11,8 @@ extension DatabaseClient.Projects: TestDependencyKey {
|
|||||||
public static func live(database: any Database) -> Self {
|
public static func live(database: any Database) -> Self {
|
||||||
.init(
|
.init(
|
||||||
create: { userID, request in
|
create: { userID, request in
|
||||||
let model = try request.toModel(userID: userID)
|
let model = request.toModel(userID: userID)
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
},
|
},
|
||||||
delete: { id in
|
delete: { id in
|
||||||
@@ -81,10 +82,9 @@ extension DatabaseClient.Projects: TestDependencyKey {
|
|||||||
guard let model = try await ProjectModel.find(id, on: database) else {
|
guard let model = try await ProjectModel.find(id, on: database) else {
|
||||||
throw NotFoundError()
|
throw NotFoundError()
|
||||||
}
|
}
|
||||||
try updates.validate()
|
|
||||||
model.applyUpdates(updates)
|
model.applyUpdates(updates)
|
||||||
if model.hasChanges {
|
if model.hasChanges {
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
}
|
}
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
}
|
}
|
||||||
@@ -94,8 +94,7 @@ extension DatabaseClient.Projects: TestDependencyKey {
|
|||||||
|
|
||||||
extension Project.Create {
|
extension Project.Create {
|
||||||
|
|
||||||
func toModel(userID: User.ID) throws -> ProjectModel {
|
func toModel(userID: User.ID) -> ProjectModel {
|
||||||
try validate()
|
|
||||||
return .init(
|
return .init(
|
||||||
name: name,
|
name: name,
|
||||||
streetAddress: streetAddress,
|
streetAddress: streetAddress,
|
||||||
@@ -106,70 +105,6 @@ extension Project.Create {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
guard !name.isEmpty else {
|
|
||||||
throw ValidationError("Project name should not be empty.")
|
|
||||||
}
|
|
||||||
guard !streetAddress.isEmpty else {
|
|
||||||
throw ValidationError("Project street address should not be empty.")
|
|
||||||
}
|
|
||||||
guard !city.isEmpty else {
|
|
||||||
throw ValidationError("Project city should not be empty.")
|
|
||||||
}
|
|
||||||
guard !state.isEmpty else {
|
|
||||||
throw ValidationError("Project state should not be empty.")
|
|
||||||
}
|
|
||||||
guard !zipCode.isEmpty else {
|
|
||||||
throw ValidationError("Project zipCode should not be empty.")
|
|
||||||
}
|
|
||||||
if let sensibleHeatRatio {
|
|
||||||
guard sensibleHeatRatio >= 0 else {
|
|
||||||
throw ValidationError("Project sensible heat ratio should be greater than 0.")
|
|
||||||
}
|
|
||||||
guard sensibleHeatRatio <= 1 else {
|
|
||||||
throw ValidationError("Project sensible heat ratio should be less than 1.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Project.Update {
|
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
if let name {
|
|
||||||
guard !name.isEmpty else {
|
|
||||||
throw ValidationError("Project name should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let streetAddress {
|
|
||||||
guard !streetAddress.isEmpty else {
|
|
||||||
throw ValidationError("Project street address should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let city {
|
|
||||||
guard !city.isEmpty else {
|
|
||||||
throw ValidationError("Project city should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let state {
|
|
||||||
guard !state.isEmpty else {
|
|
||||||
throw ValidationError("Project state should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let zipCode {
|
|
||||||
guard !zipCode.isEmpty else {
|
|
||||||
throw ValidationError("Project zipCode should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let sensibleHeatRatio {
|
|
||||||
guard sensibleHeatRatio >= 0 else {
|
|
||||||
throw ValidationError("Project sensible heat ratio should be greater than 0.")
|
|
||||||
}
|
|
||||||
guard sensibleHeatRatio <= 1 else {
|
|
||||||
throw ValidationError("Project sensible heat ratio should be less than 1.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Project {
|
extension Project {
|
||||||
@@ -342,3 +277,35 @@ final class ProjectModel: Model, @unchecked Sendable {
|
|||||||
return model
|
return model
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ProjectModel: Validatable {
|
||||||
|
|
||||||
|
var body: some Validation<ProjectModel> {
|
||||||
|
Validator.accumulating {
|
||||||
|
Validator.validate(\.name, with: .notEmpty())
|
||||||
|
.errorLabel("Name", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.streetAddress, with: .notEmpty())
|
||||||
|
.errorLabel("Address", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.city, with: .notEmpty())
|
||||||
|
.errorLabel("City", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.state, with: .notEmpty())
|
||||||
|
.errorLabel("State", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.zipCode, with: .notEmpty())
|
||||||
|
.errorLabel("Zip", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.sensibleHeatRatio) {
|
||||||
|
Validator {
|
||||||
|
Double.greaterThan(0)
|
||||||
|
Double.lessThanOrEquals(1.0)
|
||||||
|
}
|
||||||
|
.optional()
|
||||||
|
}
|
||||||
|
.errorLabel("Sensible Heat Ratio", inline: true)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import DependenciesMacros
|
|||||||
import Fluent
|
import Fluent
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
|
import Validations
|
||||||
|
|
||||||
extension DatabaseClient.Rooms: TestDependencyKey {
|
extension DatabaseClient.Rooms: TestDependencyKey {
|
||||||
public static let testValue = Self()
|
public static let testValue = Self()
|
||||||
@@ -11,7 +12,7 @@ extension DatabaseClient.Rooms: TestDependencyKey {
|
|||||||
.init(
|
.init(
|
||||||
create: { request in
|
create: { request in
|
||||||
let model = try request.toModel()
|
let model = try request.toModel()
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
},
|
},
|
||||||
delete: { id in
|
delete: { id in
|
||||||
@@ -31,7 +32,7 @@ extension DatabaseClient.Rooms: TestDependencyKey {
|
|||||||
model.rectangularSizes = nil
|
model.rectangularSizes = nil
|
||||||
}
|
}
|
||||||
if model.hasChanges {
|
if model.hasChanges {
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
}
|
}
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
},
|
},
|
||||||
@@ -50,11 +51,9 @@ extension DatabaseClient.Rooms: TestDependencyKey {
|
|||||||
guard let model = try await RoomModel.find(id, on: database) else {
|
guard let model = try await RoomModel.find(id, on: database) else {
|
||||||
throw NotFoundError()
|
throw NotFoundError()
|
||||||
}
|
}
|
||||||
|
|
||||||
try updates.validate()
|
|
||||||
model.applyUpdates(updates)
|
model.applyUpdates(updates)
|
||||||
if model.hasChanges {
|
if model.hasChanges {
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
}
|
}
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
},
|
},
|
||||||
@@ -77,8 +76,7 @@ extension DatabaseClient.Rooms: TestDependencyKey {
|
|||||||
|
|
||||||
extension Room.Create {
|
extension Room.Create {
|
||||||
|
|
||||||
func toModel() throws(ValidationError) -> RoomModel {
|
func toModel() throws -> RoomModel {
|
||||||
try validate()
|
|
||||||
return .init(
|
return .init(
|
||||||
name: name,
|
name: name,
|
||||||
heatingLoad: heatingLoad,
|
heatingLoad: heatingLoad,
|
||||||
@@ -88,57 +86,6 @@ extension Room.Create {
|
|||||||
projectID: projectID
|
projectID: projectID
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
guard !name.isEmpty else {
|
|
||||||
throw ValidationError("Room name should not be empty.")
|
|
||||||
}
|
|
||||||
guard heatingLoad >= 0 else {
|
|
||||||
throw ValidationError("Room heating load should not be less than 0.")
|
|
||||||
}
|
|
||||||
guard coolingTotal >= 0 else {
|
|
||||||
throw ValidationError("Room cooling total should not be less than 0.")
|
|
||||||
}
|
|
||||||
if let coolingSensible {
|
|
||||||
guard coolingSensible >= 0 else {
|
|
||||||
throw ValidationError("Room cooling sensible should not be less than 0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
guard registerCount >= 1 else {
|
|
||||||
throw ValidationError("Room cooling sensible should not be less than 1.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Room.Update {
|
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
if let name {
|
|
||||||
guard !name.isEmpty else {
|
|
||||||
throw ValidationError("Room name should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let heatingLoad {
|
|
||||||
guard heatingLoad >= 0 else {
|
|
||||||
throw ValidationError("Room heating load should not be less than 0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let coolingTotal {
|
|
||||||
guard coolingTotal >= 0 else {
|
|
||||||
throw ValidationError("Room cooling total should not be less than 0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let coolingSensible {
|
|
||||||
guard coolingSensible >= 0 else {
|
|
||||||
throw ValidationError("Room cooling sensible should not be less than 0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let registerCount {
|
|
||||||
guard registerCount >= 1 else {
|
|
||||||
throw ValidationError("Room cooling sensible should not be less than 1.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Room {
|
extension Room {
|
||||||
@@ -169,7 +116,7 @@ extension Room {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class RoomModel: Model, @unchecked Sendable {
|
final class RoomModel: Model, @unchecked Sendable, Validatable {
|
||||||
|
|
||||||
static let schema = "room"
|
static let schema = "room"
|
||||||
|
|
||||||
@@ -267,4 +214,38 @@ final class RoomModel: Model, @unchecked Sendable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var body: some Validation<RoomModel> {
|
||||||
|
Validator.accumulating {
|
||||||
|
Validator.validate(\.name, with: .notEmpty())
|
||||||
|
.errorLabel("Name", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.heatingLoad, with: .greaterThanOrEquals(0))
|
||||||
|
.errorLabel("Heating Load", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.coolingTotal, with: .greaterThanOrEquals(0))
|
||||||
|
.errorLabel("Cooling Total", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.coolingSensible, with: Double.greaterThanOrEquals(0).optional())
|
||||||
|
.errorLabel("Cooling Sensible", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.registerCount, with: .greaterThanOrEquals(1))
|
||||||
|
.errorLabel("Register Count", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.rectangularSizes)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Room.RectangularSize: Validatable {
|
||||||
|
|
||||||
|
public var body: some Validation<Self> {
|
||||||
|
Validator.accumulating {
|
||||||
|
Validator.validate(\.register, with: Int.greaterThanOrEquals(1).optional())
|
||||||
|
.errorLabel("Register", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.height, with: Int.greaterThanOrEquals(1))
|
||||||
|
.errorLabel("Height", inline: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import DependenciesMacros
|
|||||||
import Fluent
|
import Fluent
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
|
import Validations
|
||||||
|
|
||||||
extension DatabaseClient.TrunkSizes: TestDependencyKey {
|
extension DatabaseClient.TrunkSizes: TestDependencyKey {
|
||||||
public static let testValue = Self()
|
public static let testValue = Self()
|
||||||
@@ -10,12 +11,12 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey {
|
|||||||
public static func live(database: any Database) -> Self {
|
public static func live(database: any Database) -> Self {
|
||||||
.init(
|
.init(
|
||||||
create: { request in
|
create: { request in
|
||||||
try request.validate()
|
// try request.validate()
|
||||||
|
|
||||||
let trunk = request.toModel()
|
let trunk = request.toModel()
|
||||||
var roomProxies = [TrunkSize.RoomProxy]()
|
var roomProxies = [TrunkSize.RoomProxy]()
|
||||||
|
|
||||||
try await trunk.save(on: database)
|
try await trunk.validateAndSave(on: database)
|
||||||
|
|
||||||
for (roomID, registers) in request.rooms {
|
for (roomID, registers) in request.rooms {
|
||||||
guard let room = try await RoomModel.find(roomID, on: database) else {
|
guard let room = try await RoomModel.find(roomID, on: database) else {
|
||||||
@@ -27,7 +28,7 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey {
|
|||||||
registers: registers,
|
registers: registers,
|
||||||
type: request.type
|
type: request.type
|
||||||
)
|
)
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
roomProxies.append(
|
roomProxies.append(
|
||||||
.init(room: try room.toDTO(), registers: registers)
|
.init(room: try room.toDTO(), registers: registers)
|
||||||
)
|
)
|
||||||
@@ -80,7 +81,7 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey {
|
|||||||
else {
|
else {
|
||||||
throw NotFoundError()
|
throw NotFoundError()
|
||||||
}
|
}
|
||||||
try updates.validate()
|
// try updates.validate()
|
||||||
try await model.applyUpdates(updates, on: database)
|
try await model.applyUpdates(updates, on: database)
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
}
|
}
|
||||||
@@ -90,17 +91,6 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey {
|
|||||||
|
|
||||||
extension TrunkSize.Create {
|
extension TrunkSize.Create {
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
guard rooms.count > 0 else {
|
|
||||||
throw ValidationError("Trunk size should have associated rooms / registers.")
|
|
||||||
}
|
|
||||||
if let height {
|
|
||||||
guard height > 0 else {
|
|
||||||
throw ValidationError("Trunk size height should be greater than 0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toModel() -> TrunkModel {
|
func toModel() -> TrunkModel {
|
||||||
.init(
|
.init(
|
||||||
projectID: projectID,
|
projectID: projectID,
|
||||||
@@ -111,21 +101,6 @@ extension TrunkSize.Create {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TrunkSize.Update {
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
if let rooms {
|
|
||||||
guard rooms.count > 0 else {
|
|
||||||
throw ValidationError("Trunk size should have associated rooms / registers.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let height {
|
|
||||||
guard height > 0 else {
|
|
||||||
throw ValidationError("Trunk size height should be greater than 0.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TrunkSize {
|
extension TrunkSize {
|
||||||
|
|
||||||
struct Migrate: AsyncMigration {
|
struct Migrate: AsyncMigration {
|
||||||
@@ -205,7 +180,17 @@ final class TrunkRoomModel: Model, @unchecked Sendable {
|
|||||||
registers: registers
|
registers: registers
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TrunkRoomModel: Validatable {
|
||||||
|
var body: some Validation<TrunkRoomModel> {
|
||||||
|
Validator.validate(\.registers) {
|
||||||
|
[Int].notEmpty()
|
||||||
|
ForEachValidator {
|
||||||
|
Int.greaterThanOrEquals(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class TrunkModel: Model, @unchecked Sendable {
|
final class TrunkModel: Model, @unchecked Sendable {
|
||||||
@@ -276,7 +261,7 @@ final class TrunkModel: Model, @unchecked Sendable {
|
|||||||
self.name = name
|
self.name = name
|
||||||
}
|
}
|
||||||
if hasChanges {
|
if hasChanges {
|
||||||
try await self.save(on: database)
|
try await self.validateAndSave(on: database)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let updateRooms = updates.rooms else {
|
guard let updateRooms = updates.rooms else {
|
||||||
@@ -297,7 +282,7 @@ final class TrunkModel: Model, @unchecked Sendable {
|
|||||||
currRoom.registers = registers
|
currRoom.registers = registers
|
||||||
}
|
}
|
||||||
if currRoom.hasChanges {
|
if currRoom.hasChanges {
|
||||||
try await currRoom.save(on: database)
|
try await currRoom.validateAndSave(on: database)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
database.logger.debug("CREATING NEW TrunkRoomModel")
|
database.logger.debug("CREATING NEW TrunkRoomModel")
|
||||||
@@ -324,6 +309,21 @@ final class TrunkModel: Model, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension TrunkModel: Validatable {
|
||||||
|
|
||||||
|
var body: some Validation<TrunkModel> {
|
||||||
|
Validator.accumulating {
|
||||||
|
|
||||||
|
Validator.validate(\.height, with: Int.greaterThan(0).optional())
|
||||||
|
.errorLabel("Height", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.name, with: String.notEmpty().optional())
|
||||||
|
.errorLabel("Name", inline: true)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension Array where Element == TrunkModel {
|
extension Array where Element == TrunkModel {
|
||||||
|
|
||||||
func toDTO() throws -> [TrunkSize] {
|
func toDTO() throws -> [TrunkSize] {
|
||||||
|
|||||||
20
Sources/DatabaseClient/Internal/User+validation.swift
Normal file
20
Sources/DatabaseClient/Internal/User+validation.swift
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import ManualDCore
|
||||||
|
import Validations
|
||||||
|
|
||||||
|
// Declaring this in seperate file because some Vapor imports
|
||||||
|
// have same name's and this was easiest solution.
|
||||||
|
extension User.Create: Validatable {
|
||||||
|
public var body: some Validation<Self> {
|
||||||
|
Validator.accumulating {
|
||||||
|
Validator.validate(\.email, with: .email())
|
||||||
|
.errorLabel("Email", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.password.count, with: .greaterThanOrEquals(8))
|
||||||
|
.errorLabel("Password Count", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.confirmPassword, with: .equals(password))
|
||||||
|
.mapError(ValidationError("Confirm password does not match."))
|
||||||
|
.errorLabel("Confirm Password", inline: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import Dependencies
|
import Dependencies
|
||||||
import DependenciesMacros
|
import DependenciesMacros
|
||||||
import Fluent
|
import Fluent
|
||||||
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
import Vapor
|
import Validations
|
||||||
|
|
||||||
extension DatabaseClient.UserProfiles: TestDependencyKey {
|
extension DatabaseClient.UserProfiles: TestDependencyKey {
|
||||||
|
|
||||||
@@ -11,9 +12,8 @@ extension DatabaseClient.UserProfiles: TestDependencyKey {
|
|||||||
public static func live(database: any Database) -> Self {
|
public static func live(database: any Database) -> Self {
|
||||||
.init(
|
.init(
|
||||||
create: { profile in
|
create: { profile in
|
||||||
try profile.validate()
|
|
||||||
let model = profile.toModel()
|
let model = profile.toModel()
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
},
|
},
|
||||||
delete: { id in
|
delete: { id in
|
||||||
@@ -37,10 +37,9 @@ extension DatabaseClient.UserProfiles: TestDependencyKey {
|
|||||||
guard let model = try await UserProfileModel.find(id, on: database) else {
|
guard let model = try await UserProfileModel.find(id, on: database) else {
|
||||||
throw NotFoundError()
|
throw NotFoundError()
|
||||||
}
|
}
|
||||||
try updates.validate()
|
|
||||||
model.applyUpdates(updates)
|
model.applyUpdates(updates)
|
||||||
if model.hasChanges {
|
if model.hasChanges {
|
||||||
try await model.save(on: database)
|
try await model.validateAndSave(on: database)
|
||||||
}
|
}
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
}
|
}
|
||||||
@@ -50,30 +49,6 @@ extension DatabaseClient.UserProfiles: TestDependencyKey {
|
|||||||
|
|
||||||
extension User.Profile.Create {
|
extension User.Profile.Create {
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
guard !firstName.isEmpty else {
|
|
||||||
throw ValidationError("User first name should not be empty.")
|
|
||||||
}
|
|
||||||
guard !lastName.isEmpty else {
|
|
||||||
throw ValidationError("User last name should not be empty.")
|
|
||||||
}
|
|
||||||
guard !companyName.isEmpty else {
|
|
||||||
throw ValidationError("User company name should not be empty.")
|
|
||||||
}
|
|
||||||
guard !streetAddress.isEmpty else {
|
|
||||||
throw ValidationError("User street address should not be empty.")
|
|
||||||
}
|
|
||||||
guard !city.isEmpty else {
|
|
||||||
throw ValidationError("User city should not be empty.")
|
|
||||||
}
|
|
||||||
guard !state.isEmpty else {
|
|
||||||
throw ValidationError("User state should not be empty.")
|
|
||||||
}
|
|
||||||
guard !zipCode.isEmpty else {
|
|
||||||
throw ValidationError("User zip code should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toModel() -> UserProfileModel {
|
func toModel() -> UserProfileModel {
|
||||||
.init(
|
.init(
|
||||||
userID: userID,
|
userID: userID,
|
||||||
@@ -89,47 +64,6 @@ extension User.Profile.Create {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension User.Profile.Update {
|
|
||||||
|
|
||||||
func validate() throws(ValidationError) {
|
|
||||||
if let firstName {
|
|
||||||
guard !firstName.isEmpty else {
|
|
||||||
throw ValidationError("User first name should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let lastName {
|
|
||||||
guard !lastName.isEmpty else {
|
|
||||||
throw ValidationError("User last name should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let companyName {
|
|
||||||
guard !companyName.isEmpty else {
|
|
||||||
throw ValidationError("User company name should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let streetAddress {
|
|
||||||
guard !streetAddress.isEmpty else {
|
|
||||||
throw ValidationError("User street address should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let city {
|
|
||||||
guard !city.isEmpty else {
|
|
||||||
throw ValidationError("User city should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let state {
|
|
||||||
guard !state.isEmpty else {
|
|
||||||
throw ValidationError("User state should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let zipCode {
|
|
||||||
guard !zipCode.isEmpty else {
|
|
||||||
throw ValidationError("User zip code should not be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension User.Profile {
|
extension User.Profile {
|
||||||
|
|
||||||
struct Migrate: AsyncMigration {
|
struct Migrate: AsyncMigration {
|
||||||
@@ -270,3 +204,31 @@ final class UserProfileModel: Model, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension UserProfileModel: Validatable {
|
||||||
|
|
||||||
|
var body: some Validation<UserProfileModel> {
|
||||||
|
Validator.accumulating {
|
||||||
|
Validator.validate(\.firstName, with: .notEmpty())
|
||||||
|
.errorLabel("First Name", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.lastName, with: .notEmpty())
|
||||||
|
.errorLabel("Last Name", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.companyName, with: .notEmpty())
|
||||||
|
.errorLabel("Company", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.streetAddress, with: .notEmpty())
|
||||||
|
.errorLabel("Address", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.city, with: .notEmpty())
|
||||||
|
.errorLabel("City", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.state, with: .notEmpty())
|
||||||
|
.errorLabel("State", inline: true)
|
||||||
|
|
||||||
|
Validator.validate(\.zipCode, with: .notEmpty())
|
||||||
|
.errorLabel("Zip", inline: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Dependencies
|
import Dependencies
|
||||||
import DependenciesMacros
|
import DependenciesMacros
|
||||||
import Fluent
|
import Fluent
|
||||||
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
import Vapor
|
import Vapor
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ extension DatabaseClient.Users: TestDependencyKey {
|
|||||||
public static func live(database: any Database) -> Self {
|
public static func live(database: any Database) -> Self {
|
||||||
.init(
|
.init(
|
||||||
create: { request in
|
create: { request in
|
||||||
|
try request.validate()
|
||||||
let model = try request.toModel()
|
let model = try request.toModel()
|
||||||
try await model.save(on: database)
|
try await model.save(on: database)
|
||||||
return try model.toDTO()
|
return try model.toDTO()
|
||||||
@@ -118,21 +120,8 @@ extension User {
|
|||||||
extension User.Create {
|
extension User.Create {
|
||||||
|
|
||||||
func toModel() throws -> UserModel {
|
func toModel() throws -> UserModel {
|
||||||
try validate()
|
|
||||||
return try .init(email: email, passwordHash: User.hashPassword(password))
|
return try .init(email: email, passwordHash: User.hashPassword(password))
|
||||||
}
|
}
|
||||||
|
|
||||||
func validate() throws {
|
|
||||||
guard !email.isEmpty else {
|
|
||||||
throw ValidationError("Email should not be empty")
|
|
||||||
}
|
|
||||||
guard password.count > 8 else {
|
|
||||||
throw ValidationError("Password should be more than 8 characters long.")
|
|
||||||
}
|
|
||||||
guard password == confirmPassword else {
|
|
||||||
throw ValidationError("Passwords do not match.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final class UserModel: Model, @unchecked Sendable {
|
final class UserModel: Model, @unchecked Sendable {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import DatabaseClient
|
|
||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
import Testing
|
import Testing
|
||||||
|
|
||||||
|
@testable import DatabaseClient
|
||||||
|
|
||||||
@Suite
|
@Suite
|
||||||
struct ComponentLossTests {
|
struct ComponentLossTests {
|
||||||
|
|
||||||
@@ -50,4 +51,18 @@ struct ComponentLossTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
arguments: [
|
||||||
|
ComponentLossModel(name: "", value: 0.2, projectID: UUID(0)),
|
||||||
|
ComponentLossModel(name: "Foo", value: -0.2, projectID: UUID(0)),
|
||||||
|
ComponentLossModel(name: "Foo", value: 1.2, projectID: UUID(0)),
|
||||||
|
ComponentLossModel(name: "", value: -0.2, projectID: UUID(0)),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
func validations(model: ComponentLossModel) {
|
||||||
|
#expect(throws: (any Error).self) {
|
||||||
|
try model.validate()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import DatabaseClient
|
|
||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
import Testing
|
import Testing
|
||||||
|
|
||||||
|
@testable import DatabaseClient
|
||||||
|
|
||||||
@Suite
|
@Suite
|
||||||
struct EquipmentTests {
|
struct EquipmentTests {
|
||||||
|
|
||||||
@@ -51,4 +52,18 @@ struct EquipmentTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
arguments: [
|
||||||
|
EquipmentModel(staticPressure: -1, heatingCFM: 1000, coolingCFM: 1000, projectID: UUID(0)),
|
||||||
|
EquipmentModel(staticPressure: 0.5, heatingCFM: -1, coolingCFM: 1000, projectID: UUID(0)),
|
||||||
|
EquipmentModel(staticPressure: 0.5, heatingCFM: 1000, coolingCFM: -1000, projectID: UUID(0)),
|
||||||
|
EquipmentModel(staticPressure: 1.1, heatingCFM: 1000, coolingCFM: -1000, projectID: UUID(0)),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
func validations(model: EquipmentModel) {
|
||||||
|
#expect(throws: (any Error).self) {
|
||||||
|
try model.validate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import DatabaseClient
|
|
||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
import Testing
|
import Testing
|
||||||
|
|
||||||
|
@testable import DatabaseClient
|
||||||
|
|
||||||
@Suite
|
@Suite
|
||||||
struct EquivalentLengthTests {
|
struct EquivalentLengthTests {
|
||||||
|
|
||||||
@@ -76,4 +77,47 @@ struct EquivalentLengthTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
arguments: [
|
||||||
|
EquivalentLength.Create(
|
||||||
|
projectID: UUID(0), name: "", type: .return, straightLengths: [], groups: []
|
||||||
|
),
|
||||||
|
EquivalentLength.Create(
|
||||||
|
projectID: UUID(0), name: "Testy", type: .return, straightLengths: [-1, 1], groups: []
|
||||||
|
),
|
||||||
|
EquivalentLength.Create(
|
||||||
|
projectID: UUID(0), name: "Testy", type: .return, straightLengths: [1, -1], groups: []
|
||||||
|
),
|
||||||
|
EquivalentLength.Create(
|
||||||
|
projectID: UUID(0), name: "Testy", type: .return, straightLengths: [1, 1],
|
||||||
|
groups: [
|
||||||
|
.init(group: -1, letter: "a", value: 1.0, quantity: 1)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
EquivalentLength.Create(
|
||||||
|
projectID: UUID(0), name: "Testy", type: .return, straightLengths: [1, 1],
|
||||||
|
groups: [
|
||||||
|
.init(group: 1, letter: "1", value: 1.0, quantity: 1)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
EquivalentLength.Create(
|
||||||
|
projectID: UUID(0), name: "Testy", type: .return, straightLengths: [1, 1],
|
||||||
|
groups: [
|
||||||
|
.init(group: 1, letter: "a", value: -1.0, quantity: 1)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
EquivalentLength.Create(
|
||||||
|
projectID: UUID(0), name: "Testy", type: .return, straightLengths: [1, 1],
|
||||||
|
groups: [
|
||||||
|
.init(group: 1, letter: "a", value: 1.0, quantity: -1)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
func validations(model: EquivalentLength.Create) {
|
||||||
|
#expect(throws: (any Error).self) {
|
||||||
|
try model.toModel().validate()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import Dependencies
|
import Dependencies
|
||||||
import DependenciesTestSupport
|
|
||||||
import Fluent
|
import Fluent
|
||||||
import FluentSQLiteDriver
|
import FluentSQLiteDriver
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
@@ -151,4 +150,55 @@ struct ProjectTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
arguments: [
|
||||||
|
ProjectModel(
|
||||||
|
name: "", streetAddress: "1234 Sesame St", city: "Nowhere", state: "OH", zipCode: "55555",
|
||||||
|
sensibleHeatRatio: nil, userID: UUID(0)
|
||||||
|
),
|
||||||
|
ProjectModel(
|
||||||
|
name: "Testy", streetAddress: "", city: "Nowhere", state: "OH", zipCode: "55555",
|
||||||
|
sensibleHeatRatio: nil, userID: UUID(0)
|
||||||
|
),
|
||||||
|
ProjectModel(
|
||||||
|
name: "Testy", streetAddress: "1234 Sesame St", city: "", state: "OH", zipCode: "55555",
|
||||||
|
sensibleHeatRatio: nil, userID: UUID(0)
|
||||||
|
),
|
||||||
|
ProjectModel(
|
||||||
|
name: "Testy", streetAddress: "1234 Sesame St", city: "Nowhere", state: "",
|
||||||
|
zipCode: "55555",
|
||||||
|
sensibleHeatRatio: nil, userID: UUID(0)
|
||||||
|
),
|
||||||
|
ProjectModel(
|
||||||
|
name: "Testy", streetAddress: "1234 Sesame St", city: "Nowhere", state: "OH",
|
||||||
|
zipCode: "",
|
||||||
|
sensibleHeatRatio: nil, userID: UUID(0)
|
||||||
|
),
|
||||||
|
ProjectModel(
|
||||||
|
name: "Testy", streetAddress: "1234 Sesame St", city: "Nowhere", state: "OH",
|
||||||
|
zipCode: "55555",
|
||||||
|
sensibleHeatRatio: -1, userID: UUID(0)
|
||||||
|
),
|
||||||
|
ProjectModel(
|
||||||
|
name: "Testy", streetAddress: "1234 Sesame St", city: "Nowhere", state: "OH",
|
||||||
|
zipCode: "55555",
|
||||||
|
sensibleHeatRatio: 1.1, userID: UUID(0)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
func validations(model: ProjectModel) {
|
||||||
|
var errors = [String]()
|
||||||
|
|
||||||
|
#expect(throws: (any Error).self) {
|
||||||
|
do {
|
||||||
|
try model.validate()
|
||||||
|
} catch {
|
||||||
|
// Just checking to make sure I'm not testing the same error over and over /
|
||||||
|
// making sure I've reset to good values / only testing one property at a time.
|
||||||
|
#expect(!errors.contains("\(error)"))
|
||||||
|
errors.append("\(error)")
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import DatabaseClient
|
|
||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
import Testing
|
import Testing
|
||||||
|
import Validations
|
||||||
|
|
||||||
|
@testable import DatabaseClient
|
||||||
|
|
||||||
@Suite
|
@Suite
|
||||||
struct RoomTests {
|
struct RoomTests {
|
||||||
@@ -63,4 +65,124 @@ struct RoomTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
arguments: [
|
||||||
|
Room.Create(
|
||||||
|
projectID: UUID(0),
|
||||||
|
name: "",
|
||||||
|
heatingLoad: 12345,
|
||||||
|
coolingTotal: 12344,
|
||||||
|
coolingSensible: nil,
|
||||||
|
registerCount: 1
|
||||||
|
),
|
||||||
|
Room.Create(
|
||||||
|
projectID: UUID(0),
|
||||||
|
name: "Test",
|
||||||
|
heatingLoad: -12345,
|
||||||
|
coolingTotal: 12344,
|
||||||
|
coolingSensible: nil,
|
||||||
|
registerCount: 1
|
||||||
|
),
|
||||||
|
Room.Create(
|
||||||
|
projectID: UUID(0),
|
||||||
|
name: "Test",
|
||||||
|
heatingLoad: 12345,
|
||||||
|
coolingTotal: -12344,
|
||||||
|
coolingSensible: nil,
|
||||||
|
registerCount: 1
|
||||||
|
),
|
||||||
|
Room.Create(
|
||||||
|
projectID: UUID(0),
|
||||||
|
name: "Test",
|
||||||
|
heatingLoad: 12345,
|
||||||
|
coolingTotal: 12344,
|
||||||
|
coolingSensible: -123,
|
||||||
|
registerCount: 1
|
||||||
|
),
|
||||||
|
Room.Create(
|
||||||
|
projectID: UUID(0),
|
||||||
|
name: "Test",
|
||||||
|
heatingLoad: 12345,
|
||||||
|
coolingTotal: 12344,
|
||||||
|
coolingSensible: nil,
|
||||||
|
registerCount: -1
|
||||||
|
),
|
||||||
|
Room.Create(
|
||||||
|
projectID: UUID(0),
|
||||||
|
name: "",
|
||||||
|
heatingLoad: -12345,
|
||||||
|
coolingTotal: -12344,
|
||||||
|
coolingSensible: -1,
|
||||||
|
registerCount: -1
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
func validations(room: Room.Create) throws {
|
||||||
|
#expect(throws: (any Error).self) {
|
||||||
|
// do {
|
||||||
|
try room.toModel().validate()
|
||||||
|
// } catch {
|
||||||
|
// print("\(error)")
|
||||||
|
// throw error
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test(
|
||||||
|
// arguments: [
|
||||||
|
// Room.Update(
|
||||||
|
// name: "",
|
||||||
|
// heatingLoad: 12345,
|
||||||
|
// coolingTotal: 12344,
|
||||||
|
// coolingSensible: nil,
|
||||||
|
// registerCount: 1
|
||||||
|
// ),
|
||||||
|
// Room.Update(
|
||||||
|
// name: "Test",
|
||||||
|
// heatingLoad: -12345,
|
||||||
|
// coolingTotal: 12344,
|
||||||
|
// coolingSensible: nil,
|
||||||
|
// registerCount: 1
|
||||||
|
// ),
|
||||||
|
// Room.Update(
|
||||||
|
// name: "Test",
|
||||||
|
// heatingLoad: 12345,
|
||||||
|
// coolingTotal: -12344,
|
||||||
|
// coolingSensible: nil,
|
||||||
|
// registerCount: 1
|
||||||
|
// ),
|
||||||
|
// Room.Update(
|
||||||
|
// name: "Test",
|
||||||
|
// heatingLoad: 12345,
|
||||||
|
// coolingTotal: 12344,
|
||||||
|
// coolingSensible: -123,
|
||||||
|
// registerCount: 1
|
||||||
|
// ),
|
||||||
|
// Room.Update(
|
||||||
|
// name: "Test",
|
||||||
|
// heatingLoad: 12345,
|
||||||
|
// coolingTotal: 12344,
|
||||||
|
// coolingSensible: nil,
|
||||||
|
// registerCount: -1
|
||||||
|
// ),
|
||||||
|
// Room.Update(
|
||||||
|
// name: "",
|
||||||
|
// heatingLoad: -12345,
|
||||||
|
// coolingTotal: -12344,
|
||||||
|
// coolingSensible: -1,
|
||||||
|
// registerCount: -1
|
||||||
|
// ),
|
||||||
|
// ]
|
||||||
|
// )
|
||||||
|
// func updateValidations(room: Room.Update) throws {
|
||||||
|
// #expect(throws: (any Error).self) {
|
||||||
|
// // do {
|
||||||
|
// try room.validate()
|
||||||
|
// // } catch {
|
||||||
|
// // print("\(error)")
|
||||||
|
// // throw error
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import DatabaseClient
|
|
||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
import Testing
|
import Testing
|
||||||
|
|
||||||
|
@testable import DatabaseClient
|
||||||
|
|
||||||
@Suite
|
@Suite
|
||||||
struct TrunkSizeTests {
|
struct TrunkSizeTests {
|
||||||
|
|
||||||
@@ -64,4 +65,29 @@ struct TrunkSizeTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
arguments: [
|
||||||
|
TrunkModel(projectID: UUID(0), type: .return, height: 8, name: ""),
|
||||||
|
TrunkModel(projectID: UUID(0), type: .return, height: -8, name: "Test"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
func validations(model: TrunkModel) {
|
||||||
|
#expect(throws: (any Error).self) {
|
||||||
|
try model.validate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
arguments: [
|
||||||
|
TrunkRoomModel(trunkID: UUID(0), roomID: UUID(0), registers: [-1, 1], type: .return),
|
||||||
|
TrunkRoomModel(trunkID: UUID(0), roomID: UUID(0), registers: [1, -1], type: .return),
|
||||||
|
TrunkRoomModel(trunkID: UUID(0), roomID: UUID(0), registers: [], type: .return),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
func trunkRoomModelValidations(model: TrunkRoomModel) {
|
||||||
|
#expect(throws: (any Error).self) {
|
||||||
|
try model.validate()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import DatabaseClient
|
|
||||||
import Dependencies
|
import Dependencies
|
||||||
import Foundation
|
import Foundation
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
@@ -41,26 +40,6 @@ struct UserDatabaseTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
func createUserFails() async throws {
|
|
||||||
try await withDatabase {
|
|
||||||
@Dependency(\.database.users) var users
|
|
||||||
|
|
||||||
await #expect(throws: ValidationError.self) {
|
|
||||||
try await users.create(.init(email: "", password: "", confirmPassword: ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
await #expect(throws: ValidationError.self) {
|
|
||||||
try await users.create(.init(email: "testy@example.com", password: "", confirmPassword: ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
await #expect(throws: ValidationError.self) {
|
|
||||||
try await users.create(
|
|
||||||
.init(email: "testy@example.com", password: "super-secret", confirmPassword: ""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
func deleteFailsWithInvalidUserID() async throws {
|
func deleteFailsWithInvalidUserID() async throws {
|
||||||
try await withDatabase {
|
try await withDatabase {
|
||||||
@@ -148,4 +127,64 @@ struct UserDatabaseTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
arguments: [
|
||||||
|
UserProfileModel(
|
||||||
|
userID: UUID(0), firstName: "", lastName: "McTestface", companyName: "Acme Co.",
|
||||||
|
streetAddress: "1234 Sesame St", city: "Nowhere", state: "CA", zipCode: "55555"
|
||||||
|
),
|
||||||
|
UserProfileModel(
|
||||||
|
userID: UUID(0), firstName: "Testy", lastName: "", companyName: "Acme Co.",
|
||||||
|
streetAddress: "1234 Sesame St", city: "Nowhere", state: "CA", zipCode: "55555"
|
||||||
|
),
|
||||||
|
UserProfileModel(
|
||||||
|
userID: UUID(0), firstName: "Testy", lastName: "McTestface", companyName: "",
|
||||||
|
streetAddress: "1234 Sesame St", city: "Nowhere", state: "CA", zipCode: "55555"
|
||||||
|
),
|
||||||
|
UserProfileModel(
|
||||||
|
userID: UUID(0), firstName: "Testy", lastName: "McTestface", companyName: "Acme Co.",
|
||||||
|
streetAddress: "", city: "Nowhere", state: "CA", zipCode: "55555"
|
||||||
|
),
|
||||||
|
UserProfileModel(
|
||||||
|
userID: UUID(0), firstName: "Testy", lastName: "McTestface", companyName: "Acme Co.",
|
||||||
|
streetAddress: "1234 Sesame St", city: "", state: "CA", zipCode: "55555"
|
||||||
|
),
|
||||||
|
UserProfileModel(
|
||||||
|
userID: UUID(0), firstName: "Testy", lastName: "McTestface", companyName: "Acme Co.",
|
||||||
|
streetAddress: "1234 Sesame St", city: "Nowhere", state: "", zipCode: "55555"
|
||||||
|
),
|
||||||
|
UserProfileModel(
|
||||||
|
userID: UUID(0), firstName: "Testy", lastName: "McTestface", companyName: "Acme Co.",
|
||||||
|
streetAddress: "1234 Sesame St", city: "Nowhere", state: "CA", zipCode: ""
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
func profileValidations(model: UserProfileModel) {
|
||||||
|
var errors = [String]()
|
||||||
|
#expect(throws: (any Error).self) {
|
||||||
|
do {
|
||||||
|
try model.validate()
|
||||||
|
} catch {
|
||||||
|
// Just checking to make sure I'm not testing the same error over and over /
|
||||||
|
// making sure I've reset to good values / only testing one property at a time.
|
||||||
|
#expect(!errors.contains("\(error)"))
|
||||||
|
errors.append("\(error)")
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
arguments: [
|
||||||
|
User.Create(email: "", password: "super-secret", confirmPassword: "super-secret"),
|
||||||
|
User.Create(email: "testy@example.com", password: "", confirmPassword: "super-secret"),
|
||||||
|
User.Create(email: "testy@example.com", password: "super-secret", confirmPassword: ""),
|
||||||
|
User.Create(email: "testy@example.com", password: "super", confirmPassword: "super"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
func userValidations(model: User.Create) {
|
||||||
|
#expect(throws: (any Error).self) {
|
||||||
|
try model.validate()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user