Skip to content

Commit

Permalink
[BREAKING] Prefer Collection over Sequence for filter(keys:) and deri…
Browse files Browse the repository at this point in the history
…ved APIs

We were frequently turning those sequences into an Array in order to check their emptiness, and generally were not sure we'd iterate a sequence only once.

Also use `some Sequence` and `some Collection` whenever possible.
  • Loading branch information
groue committed Sep 8, 2024
1 parent 110d931 commit 7fc2ea9
Show file tree
Hide file tree
Showing 20 changed files with 208 additions and 275 deletions.
8 changes: 2 additions & 6 deletions GRDB/Core/Cursor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -748,17 +748,13 @@ public final class AnyCursor<Element>: Cursor {
}

/// Creates a new cursor whose elements are elements of `iterator`.
public convenience init<I>(iterator: I)
where I: IteratorProtocol, I.Element == Element
{
public convenience init(iterator: some IteratorProtocol<Element>) {
var iterator = iterator
self.init { iterator.next() }
}

/// Creates a new cursor whose elements are elements of `sequence`.
public convenience init<S>(_ sequence: S)
where S: Sequence, S.Element == Element
{
public convenience init(_ sequence: some Sequence<Element>) {
self.init(iterator: sequence.makeIterator())
}

Expand Down
20 changes: 8 additions & 12 deletions GRDB/Core/Database+Schema.swift
Original file line number Diff line number Diff line change
Expand Up @@ -598,13 +598,11 @@ extension Database {
/// try db.table("t", hasUniqueKey: ["id", "a"]) // true
/// try db.table("t", hasUniqueKey: ["id", "a", "b", "c"]) // true
/// ```
public func table<Columns>(
public func table(
_ tableName: String,
hasUniqueKey columns: Columns)
throws -> Bool
where Columns: Sequence, Columns.Element == String
{
try columnsForUniqueKey(Array(columns), in: tableName) != nil
hasUniqueKey columns: some Collection<String>
) throws -> Bool {
try columnsForUniqueKey(columns, in: tableName) != nil
}

/// Returns the foreign keys defined on table named `tableName`.
Expand Down Expand Up @@ -929,12 +927,10 @@ extension Database {
/// returns the columns of the unique key, ordered as the matching index (or
/// primary key). The case of returned columns is not guaranteed to match
/// the case of input columns.
func columnsForUniqueKey<Columns>(
_ columns: Columns,
in tableName: String)
throws -> [String]?
where Columns: Sequence, Columns.Element == String
{
func columnsForUniqueKey(
_ columns: some Collection<String>,
in tableName: String
) throws -> [String]? {
let lowercasedColumns = Set(columns.map { $0.lowercased() })
if lowercasedColumns.isEmpty {
// Don't hit the database for trivial case
Expand Down
4 changes: 1 addition & 3 deletions GRDB/Core/Row.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2395,9 +2395,7 @@ extension RowImpl {
struct ArrayRowImpl: RowImpl {
let columns: [(String, DatabaseValue)]

init<Columns>(columns: Columns)
where Columns: Collection, Columns.Element == (String, DatabaseValue)
{
init(columns: some Collection<(String, DatabaseValue)>) {
self.columns = Array(columns)
}

Expand Down
4 changes: 1 addition & 3 deletions GRDB/Core/RowAdapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,7 @@ public struct _LayoutedColumnMapping {
///
/// // [foo:"foo" bar: "bar"]
/// try Row.fetchOne(db, sql: "SELECT NULL, 'foo', 'bar'", adapter: FooBarAdapter())
init<S>(layoutColumns: S)
where S: Sequence, S.Element == (Int, String)
{
init(layoutColumns: some Collection<(Int, String)>) {
self._layoutColumns = Array(layoutColumns)
self.lowercaseColumnIndexes = Dictionary(
layoutColumns
Expand Down
32 changes: 13 additions & 19 deletions GRDB/Core/Statement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -865,14 +865,12 @@ func checkBindingSuccess(code: CInt, sqliteStatement: SQLiteStatement) throws {
/// - parameter index: The index of the first binding.
/// - parameter body: The closure to execute when arguments are bound.
@usableFromInline
func withBindings<C, T>(
_ bindings: C,
func withBindings<T>(
_ bindings: some Collection<DatabaseValue>,
to sqliteStatement: SQLiteStatement,
from index: CInt = 1,
do body: () throws -> T)
throws -> T
where C: Collection, C.Element == DatabaseValue
{
do body: () throws -> T
) throws -> T {
guard let binding = bindings.first else {
return try body()
}
Expand Down Expand Up @@ -1019,10 +1017,8 @@ public struct StatementArguments: Hashable {
/// let values: [(any DatabaseValueConvertible)?] = ["foo", 1, nil]
/// db.execute(sql: "INSERT ... (?,?,?)", arguments: StatementArguments(values))
/// ```
public init<S>(_ sequence: S)
where S: Sequence, S.Element == (any DatabaseValueConvertible)?
{
values = sequence.map { $0?.databaseValue ?? .null }
public init(_ values: some Sequence<(any DatabaseValueConvertible)?>) {
self.values = values.map { $0?.databaseValue ?? .null }
namedValues = .init()
}

Expand All @@ -1034,10 +1030,8 @@ public struct StatementArguments: Hashable {
/// let values: [String] = ["foo", "bar"]
/// db.execute(sql: "INSERT ... (?,?)", arguments: StatementArguments(values))
/// ```
public init<S>(_ sequence: S)
where S: Sequence, S.Element: DatabaseValueConvertible
{
values = sequence.map(\.databaseValue)
public init(_ values: some Sequence<some DatabaseValueConvertible>) {
self.values = values.map(\.databaseValue)
namedValues = .init()
}

Expand Down Expand Up @@ -1078,11 +1072,11 @@ public struct StatementArguments: Hashable {

/// Creates a `StatementArguments` of named arguments from a sequence of
/// (key, value) pairs.
public init<S>(_ sequence: S)
where S: Sequence, S.Element == (String, (any DatabaseValueConvertible)?)
{
namedValues = .init(minimumCapacity: sequence.underestimatedCount)
for (key, value) in sequence {
public init(
_ keysAndValues: some Sequence<(String, (any DatabaseValueConvertible)?)>
) {
namedValues = .init(minimumCapacity: keysAndValues.underestimatedCount)
for (key, value) in keysAndValues {
namedValues[key] = value?.databaseValue ?? .null
}
values = .init()
Expand Down
2 changes: 1 addition & 1 deletion GRDB/Documentation.docc/JSON.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ The `->` and `->>` SQL operators are available on the ``SQLJSONExpressible`` pro
### Build new JSON values at the SQL level
- ``Database/json(_:)``
- ``Database/jsonArray(_:)-8xxe3``
- ``Database/jsonArray(_:)-8p2p8``
- ``Database/jsonArray(_:)-469db``
- ``Database/jsonObject(_:)``
- ``Database/jsonQuote(_:)``
Expand Down
23 changes: 11 additions & 12 deletions GRDB/JSON/SQLJSONExpressible.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/// the SQL level.
///
/// - When used in a JSON-building function such as
/// ``Database/jsonArray(_:)-8xxe3`` or ``Database/jsonObject(_:)``,
/// ``Database/jsonArray(_:)-8p2p8`` or ``Database/jsonObject(_:)``,
/// they are parsed and interpreted as JSON, not as plain strings.
///
/// To build a JSON value, create a ``JSONColumn``, or call the
Expand Down Expand Up @@ -66,7 +66,7 @@
/// ## Build JSON objects and arrays from JSON values
///
/// When used in a JSON-building function such as
/// ``Database/jsonArray(_:)-8xxe3`` or ``Database/jsonObject(_:)-5iswr``,
/// ``Database/jsonArray(_:)-8p2p8`` or ``Database/jsonObject(_:)-5iswr``,
/// JSON values are parsed and interpreted as JSON, not as plain strings.
///
/// In the example below, we can see how the `JSONColumn` is interpreted as
Expand Down Expand Up @@ -224,9 +224,9 @@ extension SQLJSONExpressible {
/// Related SQL documentation: <https://www.sqlite.org/json1.html#jex>
///
/// - parameter paths: A collection of [JSON paths](https://www.sqlite.org/json1.html#path_arguments).
public func jsonExtract<C>(atPaths paths: C) -> SQLExpression
where C: Collection, C.Element: SQLExpressible
{
public func jsonExtract(
atPaths paths: some Collection<some SQLExpressible>
) -> SQLExpression {
Database.jsonExtract(self, atPaths: paths)
}

Expand Down Expand Up @@ -335,9 +335,9 @@ extension SQLJSONExpressible {
///
/// - parameter paths: A collection of [JSON paths](https://www.sqlite.org/json1.html#path_arguments).
@available(iOS 16, macOS 10.15, tvOS 17, watchOS 9, *) // SQLite 3.38+ with exceptions for macOS
public func jsonExtract<C>(atPaths paths: C) -> SQLExpression
where C: Collection, C.Element: SQLExpressible
{
public func jsonExtract(
atPaths paths: some Collection<some SQLExpressible>
) -> SQLExpression {
Database.jsonExtract(self, atPaths: paths)
}

Expand Down Expand Up @@ -429,10 +429,9 @@ extension SQLJSONExpressible {
// /// - Parameters:
// /// - paths: A collection of [JSON paths](https://www.sqlite.org/json1.html#path_arguments).
// @available(iOS 16, macOS 10.15, tvOS 17, watchOS 9, *) // SQLite 3.38+ with exceptions for macOS
// public func jsonRemove<C>(atPaths paths: C)
// -> ColumnAssignment
// where C: Collection, C.Element: SQLExpressible
// {
// public func jsonRemove(
// atPaths paths: some Collection<some SQLExpressible>
// ) -> ColumnAssignment {
// .init(columnName: name, value: Database.jsonRemove(self, atPaths: paths))
// }
//
Expand Down
Loading

0 comments on commit 7fc2ea9

Please sign in to comment.