Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
groue committed Mar 23, 2024
2 parents bd9aea3 + bb8323b commit 77b85be
Show file tree
Hide file tree
Showing 74 changed files with 884 additions and 211 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ GRDB adheres to [Semantic Versioning](https://semver.org/), with one exception:

#### 6.x Releases

- `6.26.x` Releases - [6.26.0](#6260)
- `6.25.x` Releases - [6.25.0](#6250)
- `6.24.x` Releases - [6.24.0](#6240) - [6.24.1](#6241) - [6.24.2](#6242)
- `6.23.x` Releases - [6.23.0](#6230)
Expand Down Expand Up @@ -123,6 +124,17 @@ GRDB adheres to [Semantic Versioning](https://semver.org/), with one exception:

---

## 6.26.0

Released March 23, 2024

- **New**: [#1503](https://github.com/groue/GRDB.swift/pull/1503) by [@simba909](https://github.com/simba909): Conform Database.ColumnType to Sendable
- **New**: [#1510](https://github.com/groue/GRDB.swift/pull/1510) by [@groue](https://github.com/groue): Add Sendable conformances and unavailabilities
- **New**: [#1511](https://github.com/groue/GRDB.swift/pull/1511) by [@groue](https://github.com/groue): Database schema dump
- **New**: [#1515](https://github.com/groue/GRDB.swift/pull/1515) by [@groue](https://github.com/groue): Support for the CAST SQLite function
- **Fixed**: [#1508](https://github.com/groue/GRDB.swift/pull/1508) by [@groue](https://github.com/groue): Fix ValueObservation mishandling of database schema modification
- **Fixed**: [#1512](https://github.com/groue/GRDB.swift/issues/1512): Decoding errors are now correctly reported when decoding NULL into a non-optional property of type `Data` or `Date`.

## 6.25.0

Released February 25, 2024
Expand Down
2 changes: 1 addition & 1 deletion Documentation/AssociationsBasics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2661,7 +2661,7 @@ Aggregates can be modified and combined with Swift operators:
let request = Team.annotated(with: Team.players.min(Column("score")) ?? 0)
```

- SQL functions `ABS` and `LENGTH` are available as the `abs` and `length` Swift functions:
- SQL functions `ABS`, `CAST`, and `LENGTH` are available as the `abs`, `cast`, and `length` Swift functions:

<details>
<summary>SQL</summary>
Expand Down
2 changes: 1 addition & 1 deletion GRDB.swift.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'GRDB.swift'
s.version = '6.25.0'
s.version = '6.26.0'

s.license = { :type => 'MIT', :file => 'LICENSE' }
s.summary = 'A toolkit for SQLite databases, with a focus on application development.'
Expand Down
2 changes: 1 addition & 1 deletion GRDB/Core/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ public struct Configuration {
/// connection is opened.
///
/// Related SQLite documentation: <https://www.sqlite.org/pragma.html#pragma_journal_mode>
public enum JournalModeConfiguration {
public enum JournalModeConfiguration: Sendable {
/// The default setup has ``DatabaseQueue`` perform no specific
/// configuration of the journal mode, and ``DatabasePool``
/// configure the database for the WAL mode (just like the
Expand Down
40 changes: 40 additions & 0 deletions GRDB/Core/Cursor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,11 @@ public final class AnyCursor<Element>: Cursor {
}
}

// Explicit non-conformance to Sendable: a type-erased cursor can't be more
// sendable than non-sendable cursors (such as `DatabaseCursor`).
@available(*, unavailable)
extension AnyCursor: Sendable { }

/// A `Cursor` that consumes and drops n elements from an underlying `Base`
/// cursor before possibly returning the first available element.
public final class DropFirstCursor<Base: Cursor> {
Expand All @@ -747,6 +752,11 @@ public final class DropFirstCursor<Base: Cursor> {
}
}

// Explicit non-conformance to Sendable: `DropFirstCursor` is a mutable
// class and there is no known reason for making it thread-safe.
@available(*, unavailable)
extension DropFirstCursor: Sendable { }

extension DropFirstCursor: Cursor {
public func next() throws -> Base.Element? {
while dropped < limit {
Expand All @@ -773,6 +783,11 @@ public final class DropWhileCursor<Base: Cursor> {
}
}

// Explicit non-conformance to Sendable: `DropWhileCursor` is a mutable
// class and there is no known reason for making it thread-safe.
@available(*, unavailable)
extension DropWhileCursor: Sendable { }

extension DropWhileCursor: Cursor {
public func next() throws -> Base.Element? {
if predicateHasFailed {
Expand Down Expand Up @@ -818,6 +833,11 @@ public final class EnumeratedCursor<Base: Cursor> {
}
}

// Explicit non-conformance to Sendable: `EnumeratedCursor` is a mutable
// class and there is no known reason for making it thread-safe.
@available(*, unavailable)
extension EnumeratedCursor: Sendable { }

extension EnumeratedCursor: Cursor {
public func next() throws -> (Int, Base.Element)? {
guard let element = try base.next() else { return nil }
Expand Down Expand Up @@ -875,6 +895,11 @@ public final class FlattenCursor<Base: Cursor> where Base.Element: Cursor {
}
}

// Explicit non-conformance to Sendable: `EnumeratedCursor` is a mutable
// class and there is no known reason for making it thread-safe.
@available(*, unavailable)
extension FlattenCursor: Sendable { }

extension FlattenCursor: Cursor {
public func next() throws -> Base.Element.Element? {
while true {
Expand All @@ -901,6 +926,11 @@ public final class MapCursor<Base: Cursor, Element> {
}
}

// Explicit non-conformance to Sendable: There is no known reason for making
// it thread-safe (`transform` a Sendable closure).
@available(*, unavailable)
extension MapCursor: Sendable { }

extension MapCursor: Cursor {
public func next() throws -> Element? {
guard let element = try base.next() else { return nil }
Expand All @@ -927,6 +957,11 @@ public final class PrefixCursor<Base: Cursor> {
}
}

// Explicit non-conformance to Sendable: `PrefixCursor` is a mutable
// class and there is no known reason for making it thread-safe.
@available(*, unavailable)
extension PrefixCursor: Sendable { }

extension PrefixCursor: Cursor {
public func next() throws -> Base.Element? {
if taken >= maxLength { return nil }
Expand Down Expand Up @@ -954,6 +989,11 @@ public final class PrefixWhileCursor<Base: Cursor> {
}
}

// Explicit non-conformance to Sendable: `PrefixCursor` is a mutable
// class and there is no known reason for making it thread-safe.
@available(*, unavailable)
extension PrefixWhileCursor: Sendable { }

extension PrefixWhileCursor: Cursor {
public func next() throws -> Base.Element? {
if !predicateHasFailed, let nextElement = try base.next() {
Expand Down
12 changes: 6 additions & 6 deletions GRDB/Core/Database+Schema.swift
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,7 @@ extension Database {
///
/// - [pragma `table_info`](https://www.sqlite.org/pragma.html#pragma_table_info)
/// - [pragma `table_xinfo`](https://www.sqlite.org/pragma.html#pragma_table_xinfo)
public struct ColumnInfo: FetchableRecord {
public struct ColumnInfo: FetchableRecord, Sendable {
let cid: Int
let hidden: Int?

Expand Down Expand Up @@ -1083,9 +1083,9 @@ public struct ColumnInfo: FetchableRecord {
///
/// - [pragma `index_list`](https://www.sqlite.org/pragma.html#pragma_index_list)
/// - [pragma `index_info`](https://www.sqlite.org/pragma.html#pragma_index_info)
public struct IndexInfo {
public struct IndexInfo: Sendable{
/// The origin of an index.
public struct Origin: RawRepresentable, Equatable, DatabaseValueConvertible {
public struct Origin: RawRepresentable, Equatable, DatabaseValueConvertible, Sendable {
public var rawValue: String

public init(rawValue: String) {
Expand Down Expand Up @@ -1158,7 +1158,7 @@ public struct IndexInfo {
/// ```
///
/// Related SQLite documentation: <https://www.sqlite.org/pragma.html#pragma_foreign_key_check>
public struct ForeignKeyViolation {
public struct ForeignKeyViolation: Sendable {
/// The name of the table that contains the foreign key.
public var originTable: String

Expand Down Expand Up @@ -1307,7 +1307,7 @@ extension ForeignKeyViolation: CustomStringConvertible {
/// pk.rowIDColumn // nil
/// pk.isRowID // false
/// ```
public struct PrimaryKeyInfo {
public struct PrimaryKeyInfo: Sendable {
private enum Impl {
/// The hidden rowID.
case hiddenRowID
Expand Down Expand Up @@ -1433,7 +1433,7 @@ public struct PrimaryKeyInfo {
/// `Database` method.
///
/// Related SQLite documentation: [pragma `foreign_key_list`](https://www.sqlite.org/pragma.html#pragma_foreign_key_list).
public struct ForeignKeyInfo {
public struct ForeignKeyInfo: Sendable {
/// The first column in the output of the `foreign_key_list` pragma.
public var id: Int

Expand Down
5 changes: 5 additions & 0 deletions GRDB/Core/Database+Statements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,11 @@ public class SQLStatementCursor {
}
}

// Explicit non-conformance to Sendable: database cursors must be used from
// a serialized database access dispatch queue.
@available(*, unavailable)
extension SQLStatementCursor: Sendable { }

extension SQLStatementCursor: Cursor {
public func next() throws -> Statement? {
guard offset < cString.count - 1 /* trailing \0 */ else {
Expand Down
59 changes: 51 additions & 8 deletions GRDB/Core/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ let SQLITE_TRANSIENT = unsafeBitCast(OpaquePointer(bitPattern: -1), to: sqlite3_
///
/// - ``dumpContent(format:to:)``
/// - ``dumpRequest(_:format:to:)``
/// - ``dumpSchema(to:)``
/// - ``dumpSQL(_:format:to:)``
/// - ``dumpTables(_:format:tableHeader:stableOrder:to:)``
/// - ``DumpFormat``
Expand Down Expand Up @@ -114,6 +115,7 @@ let SQLITE_TRANSIENT = unsafeBitCast(OpaquePointer(bitPattern: -1), to: sqlite3_
/// - ``trace(options:_:)``
/// - ``CheckpointMode``
/// - ``DatabaseBackupProgress``
/// - ``StorageClass``
/// - ``TraceEvent``
/// - ``TracingOptions``
public final class Database: CustomStringConvertible, CustomDebugStringConvertible {
Expand Down Expand Up @@ -1729,6 +1731,11 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
}
}

// Explicit non-conformance to Sendable: `Database` must be used from a
// serialized database access dispatch queue (see `SerializedDatabase`).
@available(*, unavailable)
extension Database: Sendable { }

#if SQLITE_HAS_CODEC
extension Database {

Expand Down Expand Up @@ -1854,7 +1861,7 @@ extension Database {
/// The available checkpoint modes.
///
/// Related SQLite documentation: <https://www.sqlite.org/c3ref/wal_checkpoint_v2.html>
public enum CheckpointMode: CInt {
public enum CheckpointMode: CInt, Sendable {
/// The `SQLITE_CHECKPOINT_PASSIVE` mode.
case passive = 0

Expand All @@ -1873,7 +1880,7 @@ extension Database {
/// Related SQLite documentation:
/// - <https://www.sqlite.org/datatype3.html#collating_sequences>
/// - <https://www.sqlite.org/datatype3.html#collation>
public struct CollationName: RawRepresentable, Hashable {
public struct CollationName: RawRepresentable, Hashable, Sendable {
public let rawValue: String

/// Creates a collation name.
Expand Down Expand Up @@ -1910,7 +1917,7 @@ extension Database {
///
/// For more information, see
/// [Datatypes In SQLite](https://www.sqlite.org/datatype3.html).
public struct ColumnType: RawRepresentable, Hashable {
public struct ColumnType: RawRepresentable, Hashable, Sendable {
/// The SQL for the column type (`"TEXT"`, `"BLOB"`, etc.)
public let rawValue: String

Expand Down Expand Up @@ -1962,7 +1969,7 @@ extension Database {
/// An SQLite conflict resolution.
///
/// Related SQLite documentation: <https://www.sqlite.org/lang_conflict.html>
public enum ConflictResolution: String {
public enum ConflictResolution: String, Sendable {
/// The `ROLLBACK` conflict resolution.
case rollback = "ROLLBACK"

Expand All @@ -1982,7 +1989,7 @@ extension Database {
/// A foreign key action.
///
/// Related SQLite documentation: <https://www.sqlite.org/foreignkeys.html>
public enum ForeignKeyAction: String {
public enum ForeignKeyAction: String, Sendable {
/// The `CASCADE` foreign key action.
case cascade = "CASCADE"

Expand All @@ -1999,13 +2006,39 @@ extension Database {
/// An error log function that takes an error code and message.
public typealias LogErrorFunction = (_ resultCode: ResultCode, _ message: String) -> Void

/// An SQLite storage class.
///
/// For more information, see
/// [Datatypes In SQLite](https://www.sqlite.org/datatype3.html).
public struct StorageClass: RawRepresentable, Hashable, Sendable {
/// The SQL for the storage class (`"INTEGER"`, `"REAL"`, etc.)
public let rawValue: String

/// Creates an SQL storage class.
public init(rawValue: String) {
self.rawValue = rawValue
}

/// The `INTEGER` storage class.
public static let integer = StorageClass(rawValue: "INTEGER")

/// The `REAL` storage class.
public static let real = StorageClass(rawValue: "REAL")

/// The `TEXT` storage class.
public static let text = StorageClass(rawValue: "TEXT")

/// The `BLOB` storage class.
public static let blob = StorageClass(rawValue: "BLOB")
}

/// An option for the SQLite tracing feature.
///
/// You use `TracingOptions` with the `Database`
/// ``Database/trace(options:_:)`` method.
///
/// Related SQLite documentation: <https://www.sqlite.org/c3ref/c_trace.html>
public struct TracingOptions: OptionSet {
public struct TracingOptions: OptionSet, Sendable {
/// The raw trace event code.
public let rawValue: CInt

Expand Down Expand Up @@ -2138,15 +2171,15 @@ extension Database {
///
/// Related SQLite documentation: <https://www.sqlite.org/lang_transaction.html>.
@frozen
public enum TransactionCompletion {
public enum TransactionCompletion: Sendable {
case commit
case rollback
}

/// A transaction kind.
///
/// Related SQLite documentation: <https://www.sqlite.org/lang_transaction.html>.
public enum TransactionKind: String {
public enum TransactionKind: String, Sendable {
/// The `DEFERRED` transaction kind.
case deferred = "DEFERRED"

Expand Down Expand Up @@ -2179,3 +2212,13 @@ extension Database {
}
}
}

// Explicit non-conformance to Sendable: a trace event contains transient
// information.
@available(*, unavailable)
extension Database.TraceEvent: Sendable { }

// Explicit non-conformance to Sendable: a trace event contains transient
// information.
@available(*, unavailable)
extension Database.TraceEvent.Statement: Sendable { }
2 changes: 1 addition & 1 deletion GRDB/Core/DatabaseBackupProgress.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// Describe the progress of a database backup.
///
/// Related SQLite documentation: <https://www.sqlite.org/c3ref/backup_finish.html>
public struct DatabaseBackupProgress {
public struct DatabaseBackupProgress: Sendable {
/// The number of pages still to be backed up.
///
/// It is the result of the `sqlite3_backup_remaining` function.
Expand Down
1 change: 1 addition & 0 deletions GRDB/Core/DatabaseReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import Dispatch
///
/// - ``dumpContent(format:to:)``
/// - ``dumpRequest(_:format:to:)``
/// - ``dumpSchema(to:)``
/// - ``dumpSQL(_:format:to:)``
/// - ``dumpTables(_:format:tableHeader:stableOrder:to:)``
/// - ``DumpFormat``
Expand Down
2 changes: 1 addition & 1 deletion GRDB/Core/DatabaseRegion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
///
/// - ``isModified(byEventsOfKind:)``
/// - ``isModified(by:)``
public struct DatabaseRegion {
public struct DatabaseRegion: Sendable {
private let tableRegions: [CaseInsensitiveIdentifier: TableRegion]?

private init(tableRegions: [CaseInsensitiveIdentifier: TableRegion]?) {
Expand Down
5 changes: 5 additions & 0 deletions GRDB/Core/DatabaseValueConvertible.swift
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,11 @@ public final class DatabaseValueCursor<Value: DatabaseValueConvertible>: Databas
}
}

// Explicit non-conformance to Sendable: database cursors must be used from
// a serialized database access dispatch queue.
@available(*, unavailable)
extension DatabaseValueCursor: Sendable { }

/// DatabaseValueConvertible comes with built-in methods that allow to fetch
/// cursors, arrays, or single values:
///
Expand Down
Loading

0 comments on commit 77b85be

Please sign in to comment.