Skip to content

Commit

Permalink
Merge pull request #9 from roanutil/feature/sequence-filter
Browse files Browse the repository at this point in the history
Add SequenceFilter and CollectionFilter
  • Loading branch information
roanutil authored Apr 25, 2024
2 parents e1676bb + 871ac5f commit a79f104
Show file tree
Hide file tree
Showing 23 changed files with 1,650 additions and 0 deletions.
34 changes: 34 additions & 0 deletions Sources/Filter/Collection/AnyCollectionPredicate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// AnyCollectionPredicate.swift
// Filter
//
//
// MIT License
//
// Copyright © 2024 Andrew Roan

import Foundation

/// Builds predicates where the output is type-erased of the incoming `Root` and `Value` types.
public protocol AnyCollectionPredicate {
associatedtype Output
/// Builds a predicate of type `Output` for a given property on a root type.
/// - Parameters
/// - filter: CollectionFilter<Value>
/// - keyPath: KeyPath<Root, Value>
/// - Returns
/// - Output
static func build<Root, Value>(from filter: CollectionFilter<Value>, on keyPath: KeyPath<Root, Value>) -> Output
where Value: Collection
}

extension AnyCollectionPredicate {
/// Builds a predicate of type `Output` for a given `Value` type.
/// - Parameters
/// - filter: CollectionFilter<Value>
/// - Returns
/// - Output
@inlinable
public static func build<Value>(from filter: CollectionFilter<Value>) -> Output where Value: Collection {
build(from: filter, on: \.self)
}
}
51 changes: 51 additions & 0 deletions Sources/Filter/Collection/CollectionFilter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// CollectionFilter.swift
// Filter
//
//
// MIT License
//
// Copyright © 2024 Andrew Roan

import Foundation

public enum CollectionFilter<S>: Equatable where S: Collection, S: Equatable, S.Element: Equatable {
case isIn(S)
case sequence(SequenceFilter<S>)
indirect case or(Self, Self)
indirect case orMulti([Self])
indirect case and(Self, Self)
indirect case andMulti([Self])
indirect case not(Self)

/// A wrapper for CollectionFilter when comparing an optional type.
public enum Optional: Equatable {
case orNil(CollectionFilter<S>)
case notNil(CollectionFilter<S>?)
case isNil

/// Returns the wrapped CollectionFilter from `self`.
@inlinable
public var unwrapped: CollectionFilter<S>? {
switch self {
case let .orNil(unwrapped):
return unwrapped
case let .notNil(unwrapped):
return unwrapped
case .isNil:
return nil
}
}
}

public enum Element: Equatable {
case equatable(EquatableFilter<S.Element>)
}
}

extension CollectionFilter: Hashable where S: Hashable, S.Element: Hashable {}

extension CollectionFilter.Optional: Hashable where S: Hashable, S.Element: Hashable {}

extension CollectionFilter: Sendable where S: Sendable, S.Element: Sendable {}

extension CollectionFilter.Optional: Sendable where S: Sendable, S.Element: Sendable {}
39 changes: 39 additions & 0 deletions Sources/Filter/Collection/CollectionPredicate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// CollectionPredicate.swift
// Filter
//
//
// MIT License
//
// Copyright © 2024 Andrew Roan

import Foundation

/// Builds predicates where the output is type constrained by the incoming `Root` and `Value` types.
public protocol CollectionPredicate {
/// The predicate this type builds
associatedtype Output
/// Root type being filtered
associatedtype Root
/// Property type on `Root` being filtered
associatedtype Value: Collection where Value: Equatable, Value.Element: Equatable

/// Builds a predicate of type `Output` for a given property on a root type.
/// - Parameters
/// - filter: CollectionFilter<Value>
/// - keyPath: KeyPath<Root, Value>
/// - Returns
/// - Output
static func build(from filter: CollectionFilter<Value>, on keyPath: KeyPath<Root, Value>) -> Output
}

extension CollectionPredicate where Root == Value {
/// Builds a predicate of type `Output` for a given `Value` type.
/// - Parameters
/// - filter: CollectionFilter<Value>
/// - Returns
/// - Output
@inlinable
public static func build(from filter: CollectionFilter<Value>) -> Output {
build(from: filter, on: \.self)
}
}
33 changes: 33 additions & 0 deletions Sources/Filter/Collection/OptionalAnyCollectionPredicate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// OptionalAnyCollectionPredicate.swift
// Filter
//
//
// MIT License
//
// Copyright © 2024 Andrew Roan

import Foundation

/// Builds predicates where the output is type-erased of the incoming `Root` and `Value?` types.
public protocol OptionalAnyCollectionPredicate: AnyCollectionPredicate {
/// Builds a predicate of type `Output` for a given property on a root type.
/// - Parameters
/// - filter: CollectionFilter<Value>.Optional
/// - keyPath: KeyPath<Root, Value?>
/// - Returns
/// - Output
static func build<Model, Value>(from filter: CollectionFilter<Value>.Optional, on keyPath: KeyPath<Model, Value?>)
-> Output where Value: Collection
}

extension OptionalAnyCollectionPredicate {
/// Builds a predicate of type `Output` for a given `Value` type.
/// - Parameters
/// - filter: CollectionFilter<Value>.Optional
/// - Returns
/// - Output
@inlinable
public static func build<Value>(from filter: CollectionFilter<Value>.Optional) -> Output where Value: Collection {
build(from: filter, on: \.self)
}
}
32 changes: 32 additions & 0 deletions Sources/Filter/Collection/OptionalCollectionPredicate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// OptionalCollectionPredicate.swift
// Filter
//
//
// MIT License
//
// Copyright © 2024 Andrew Roan

import Foundation

/// Builds predicates where the output is type constrained by the incoming `Root` and `Value?` types.
public protocol OptionalCollectionPredicate: CollectionPredicate {
/// Builds a predicate of type `Output` for a given property on a root type.
/// - Parameters
/// - filter: CollectionFilter<Value>.Optional
/// - keyPath: KeyPath<Root, Value>
/// - Returns
/// - Output
static func build(from filter: CollectionFilter<Value>.Optional, on keyPath: KeyPath<Root, Value?>) -> Output
}

extension OptionalCollectionPredicate where Root == Value? {
/// Builds a predicate of type `Output` for a given `Value?` type.
/// - Parameters
/// - filter: CollectionFilter<Value>.Optional
/// - Returns
/// - Output
@inlinable
public static func build(from filter: CollectionFilter<Value>.Optional) -> Output {
build(from: filter, on: \.self)
}
}
34 changes: 34 additions & 0 deletions Sources/Filter/Sequence/AnySequencePredicate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// AnySequencePredicate.swift
// Filter
//
//
// MIT License
//
// Copyright © 2024 Andrew Roan

import Foundation

/// Builds predicates where the output is type-erased of the incoming `Root` and `Value` types.
public protocol AnySequencePredicate {
associatedtype Output
/// Builds a predicate of type `Output` for a given property on a root type.
/// - Parameters
/// - filter: SequenceFilter<Value>
/// - keyPath: KeyPath<Root, Value>
/// - Returns
/// - Output
static func build<Root, Value>(from filter: SequenceFilter<Value>, on keyPath: KeyPath<Root, Value>) -> Output
where Value: Sequence
}

extension AnySequencePredicate {
/// Builds a predicate of type `Output` for a given `Value` type.
/// - Parameters
/// - filter: SequenceFilter<Value>
/// - Returns
/// - Output
@inlinable
public static func build<Value>(from filter: SequenceFilter<Value>) -> Output where Value: Sequence {
build(from: filter, on: \.self)
}
}
33 changes: 33 additions & 0 deletions Sources/Filter/Sequence/OptionalAnySequencePredicate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// OptionalAnySequencePredicate.swift
// Filter
//
//
// MIT License
//
// Copyright © 2024 Andrew Roan

import Foundation

/// Builds predicates where the output is type-erased of the incoming `Root` and `Value?` types.
public protocol OptionalAnySequencePredicate: AnySequencePredicate {
/// Builds a predicate of type `Output` for a given property on a root type.
/// - Parameters
/// - filter: SequenceFilter<Value>.Optional
/// - keyPath: KeyPath<Root, Value?>
/// - Returns
/// - Output
static func build<Model, Value>(from filter: SequenceFilter<Value>.Optional, on keyPath: KeyPath<Model, Value?>)
-> Output where Value: Sequence
}

extension OptionalAnySequencePredicate {
/// Builds a predicate of type `Output` for a given `Value` type.
/// - Parameters
/// - filter: SequenceFilter<Value>.Optional
/// - Returns
/// - Output
@inlinable
public static func build<Value>(from filter: SequenceFilter<Value>.Optional) -> Output where Value: Sequence {
build(from: filter, on: \.self)
}
}
32 changes: 32 additions & 0 deletions Sources/Filter/Sequence/OptionalSequencePredicate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// OptionalSequencePredicate.swift
// Filter
//
//
// MIT License
//
// Copyright © 2024 Andrew Roan

import Foundation

/// Builds predicates where the output is type constrained by the incoming `Root` and `Value?` types.
public protocol OptionalSequencePredicate: SequencePredicate {
/// Builds a predicate of type `Output` for a given property on a root type.
/// - Parameters
/// - filter: SequenceFilter<Value>.Optional
/// - keyPath: KeyPath<Root, Value>
/// - Returns
/// - Output
static func build(from filter: SequenceFilter<Value>.Optional, on keyPath: KeyPath<Root, Value?>) -> Output
}

extension OptionalSequencePredicate where Root == Value? {
/// Builds a predicate of type `Output` for a given `Value?` type.
/// - Parameters
/// - filter: SequenceFilter<Value>.Optional
/// - Returns
/// - Output
@inlinable
public static func build(from filter: SequenceFilter<Value>.Optional) -> Output {
build(from: filter, on: \.self)
}
}
46 changes: 46 additions & 0 deletions Sources/Filter/Sequence/SequenceFilter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SequenceFilter.swift
// Filter
//
//
// MIT License
//
// Copyright © 2024 Andrew Roan

import Foundation

public enum SequenceFilter<S>: Equatable where S: Sequence, S: Equatable, S.Element: Equatable {
case contains(S.Element)
indirect case or(Self, Self)
indirect case orMulti([Self])
indirect case and(Self, Self)
indirect case andMulti([Self])
indirect case not(Self)

/// A wrapper for SequenceFilter when comparing an optional type.
public enum Optional: Equatable {
case orNil(SequenceFilter<S>)
case notNil(SequenceFilter<S>?)
case isNil

/// Returns the wrapped SequenceFilter from `self`.
@inlinable
public var unwrapped: SequenceFilter<S>? {
switch self {
case let .orNil(unwrapped):
return unwrapped
case let .notNil(unwrapped):
return unwrapped
case .isNil:
return nil
}
}
}
}

extension SequenceFilter: Hashable where S: Hashable, S.Element: Hashable {}

extension SequenceFilter.Optional: Hashable where S: Hashable, S.Element: Hashable {}

extension SequenceFilter: Sendable where S: Sendable, S.Element: Sendable {}

extension SequenceFilter.Optional: Sendable where S: Sendable, S.Element: Sendable {}
39 changes: 39 additions & 0 deletions Sources/Filter/Sequence/SequencePredicate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SequencePredicate.swift
// Filter
//
//
// MIT License
//
// Copyright © 2024 Andrew Roan

import Foundation

/// Builds predicates where the output is type constrained by the incoming `Root` and `Value` types.
public protocol SequencePredicate {
/// The predicate this type builds
associatedtype Output
/// Root type being filtered
associatedtype Root
/// Property type on `Root` being filtered
associatedtype Value: Sequence where Value: Equatable, Value.Element: Equatable

/// Builds a predicate of type `Output` for a given property on a root type.
/// - Parameters
/// - filter: SequenceFilter<Value>
/// - keyPath: KeyPath<Root, Value>
/// - Returns
/// - Output
static func build(from filter: SequenceFilter<Value>, on keyPath: KeyPath<Root, Value>) -> Output
}

extension SequencePredicate where Root == Value {
/// Builds a predicate of type `Output` for a given `Value` type.
/// - Parameters
/// - filter: SequenceFilter<Value>
/// - Returns
/// - Output
@inlinable
public static func build(from filter: SequenceFilter<Value>) -> Output {
build(from: filter, on: \.self)
}
}
Loading

0 comments on commit a79f104

Please sign in to comment.