[
  {
    "path": ".ci/gemfiles/Gemfile.travis",
    "content": "source 'https://rubygems.org'\n\ngem 'xcpretty'\ngem 'xcpretty-travis-formatter'\ngem 'cocoapods', '~> 1.7'\n"
  },
  {
    "path": ".gitignore",
    "content": "## https://github.com/github/gitignore/blob/master/Global/macOS.gitignore\n\n*.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n\n## https://github.com/github/gitignore/blob/master/Swift.gitignore\n\n# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## Build generated\nbuild/\nDerivedData/\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata/\n\n## Other\n*.moved-aside\n*.xccheckout\n*.xcscmblueprint\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n*.dSYM.zip\n*.dSYM\n\n## Playgrounds\ntimeline.xctimeline\nplayground.xcworkspace\n\n# Swift Package Manager\n#\n# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.\n# Packages/\n# Package.pins\n.build/\nPackage.resolved\n\n##\nPods/"
  },
  {
    "path": ".swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": ".swiftpm/xcode/xcshareddata/xcschemes/RxGRDB.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1230\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"RxGRDB\"\n               BuildableName = \"RxGRDB\"\n               BlueprintName = \"RxGRDB\"\n               ReferencedContainer = \"container:\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"RxGRDBTests\"\n               BuildableName = \"RxGRDBTests\"\n               BlueprintName = \"RxGRDBTests\"\n               ReferencedContainer = \"container:\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      codeCoverageEnabled = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"RxGRDBTests\"\n               BuildableName = \"RxGRDBTests\"\n               BlueprintName = \"RxGRDBTests\"\n               ReferencedContainer = \"container:\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"RxGRDB\"\n            BuildableName = \"RxGRDB\"\n            BlueprintName = \"RxGRDB\"\n            ReferencedContainer = \"container:\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": ".swiftpm/xcode/xcshareddata/xcschemes/RxGRDBTests.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1230\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"RxGRDBTests\"\n               BuildableName = \"RxGRDBTests\"\n               BlueprintName = \"RxGRDBTests\"\n               ReferencedContainer = \"container:\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": ".travis.yml",
    "content": "# The OS X Build Environment\n# https://docs.travis-ci.com/user/reference/osx/#Xcode-version\n\nlanguage: objective-c\nxcode_project: RxGRDB.xcodeproj\n\n# Caches\ncache:\n    - bundler\n    - cocoapods\n\n# Custom CocoaPods installation\ninstall:\n    - bundle install\n    - bundle exec pod repo update\n  \n# Disable the default Travis-CI submodule logic\n# The various make commands ensure that the appropriate submodules are retrieved\ngit:\n  submodules: false\n\njobs:\n  include:\n\n    - stage: Test Xcode 11.4\n      gemfile: .ci/gemfiles/Gemfile.travis\n      osx_image: xcode11.4\n      env:\n        - TID=RxGRDB [SPM] (macOS)\n      script: make test_SPM\n    \n    - stage: Test Xcode 11.4\n      gemfile: .ci/gemfiles/Gemfile.travis\n      osx_image: xcode11.4\n      env:\n        - TID=CocoaPods Lint\n      script: make test_CocoaPodsLint\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "Release Notes\n=============\n\n## 4.0.1\n\nReleased September 28, 2025\n\n- Replace deprecated API methods by [@1Consumption](https://github.com/1Consumption)\n\n## 4.0.0\n\nReleased March 15, 2025 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v3.0.0...v4.0.0)\n\n- **New**: Support for GRDB 7\n- **Breaking Change**: Swift 6+ and Xcode 16+ are required.\n- **Breaking Change**: iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 7.0+\n- **Breaking Change**: This version is not available on CocoaPods.\n\n## 3.0.0\n\nReleased September 9, 2022 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v2.1.0...v3.0.0)\n\n- **New**: Support for GRDB 6\n- **Breaking Change**: Swift 5.7+ and Xcode 14+ are required.\n- **Breaking Change**: iOS 11.0+ / macOS 10.13+ / tvOS 11.0+ / watchOS 4.0+\n\n## 2.1.0\n\nReleased October 17, 2021 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v2.0.0...v2.1.0)\n\n- **Breaking Change**: Minimum iOS version is now iOS 11.0, and 32-bits devices are no longer supported. This brings compatibility with GRDB v5.12.0 and Xcode 13.\n- **Breaking Change**: Minimum Swift version is now Swift 5.3.\n\n## 2.0.0\n\nReleased January 3, 2021 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v1.0.0...v2.0.0)\n\n- **New**: Support for RxSwift 6 \n\n## 1.0.0\n\nReleased September 20, 2020 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v1.0.0-beta.3...v1.0.0)\n\n\n## 1.0.0-beta.3\n\nReleased June 7, 2020 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v1.0.0-beta.2...v1.0.0-beta.3)\n\n- Fixed CocoaPods integration (fix [#65](https://github.com/RxSwiftCommunity/RxGRDB/issues/65))\n\n\n## 1.0.0-beta.2\n\nReleased June 6, 2020 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v1.0.0-beta...v1.0.0-beta.2)\n\n- **Breaking**: The ValueObservation scheduler is now an argument of the `rx.observe(in:scheduler:)` method, which returns a regular Observable.\n\n\n## 1.0.0-beta\n\nReleased May 3, 2020 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.18.0...v1.0.0-beta)\n\nCheck out the [Migration Guide](Documentation/RxGRDB1MigrationGuide.md).\n\n- [#63](https://github.com/RxSwiftCommunity/RxGRDB/pull/63): RxGRDB 1.0\n\n\n## 0.18.0\n\nReleased December 11, 2019 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.17.0...v0.18.0)\n\n- [#60](https://github.com/RxSwiftCommunity/RxGRDB/pull/60) by [@sammygutierrez](https://github.com/sammygutierrez): Add SwiftPM support\n- [#61](https://github.com/RxSwiftCommunity/RxGRDB/pull/61): Fix error handling of asynchronous writes\n- [#62](https://github.com/RxSwiftCommunity/RxGRDB/pull/62): Test Xcode 11.2 and SPM on Travis\n\n\n## 0.17.0\n\nReleased June 28, 2019 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.16.0...v0.17.0)\n\n- [#58](https://github.com/RxSwiftCommunity/RxGRDB/pull/58): Expose `rx` joiner on database existentials\n\n\n## 0.16.0\n\nReleased June 27, 2019 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.15.0...v0.16.0)\n\n- [#57](https://github.com/RxSwiftCommunity/RxGRDB/pull/57): Deprecate PrimaryKeyScanner\n\nThe [demo app](Documentation/RxGRDBDemo/README.md) has been refactored with the latest GRDB good practices, MVVM architecture, and some tests of the database layer\n\n\n## 0.15.0\n\nReleased June 20, 2019 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.14.0...v0.15.0)\n\n- [#55](https://github.com/RxSwiftCommunity/RxGRDB/pull/55): Asynchronous database access\n    \n    ```swift\n    let dbQueue: DatabaseQueue = ...\n    \n    // Async write\n    let write: Completable = dbQueue.rx.write { db in\n        try Player(...).insert(db)\n    }\n    \n    let newPlayerCount: Single<Int> = dbQueue.rx.writeAndReturn { db in\n        try Player(...).insert(db)\n        return try Player.fetchCount(db)\n    }\n    \n    // Async read\n    let players: Single<[Player]> = dbQueue.rx.read { db in\n        try Player.fetchAll(db)\n    }\n    ```\n\n### Breaking Changes\n\n- Observation methods have been renamed from `fetch...` to `observe...`:\n    \n    ```diff\n    -Player.all().rx.fetchOne(in: dbQueue)\n    -Player.all().rx.fetchAll(in: dbQueue)\n    -Player.all().rx.fetchCount(in: dbQueue)\n    +Player.all().rx.observeFirst(in: dbQueue)\n    +Player.all().rx.observeAll(in: dbQueue)\n    +Player.all().rx.observeCount(in: dbQueue)\n    ```\n\n- The way to provide a specific scheduler to a value observable has changed:\n    \n    ```diff\n    -Player.all().rx.fetchAll(in: dbQueue, scheduler: MainScheduler.asyncInstance)\n    +Player.all().rx.observeAll(in: dbQueue, observeOn: MainScheduler.asyncInstance)\n    ```\n\n\n## 0.14.0\n\nReleased May 24, 2019 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.13.0...v0.14.0)\n\n### New\n\n- Support for Swift 5, GRDB 4.0, and RxSwift 5.0.\n- Reactive extension on DatabaseRegionObservation:\n    \n    ```swift\n    let players = Player.all()\n    let teams = Team.all()\n    let observation = DatabaseRegionObservation(tracking: players, teams)\n    observation.rx.changes(in: dbQueue)\n        .subscribe(onNext: { db: Database in\n            print(\"Players or teams have changed.\")\n        })\n    ```\n\n### Breaking Changes\n\n- Swift 4.0 and Swift 4.1 are no longer supported.\n- GRDB 3 and RxSwift 4 are no longer supported.\n- iOS 8 is no longer supported. Minimum deployment target is now iOS 9.0.\n- Deprecated APIs are no longer available.\n- `DatabaseWriter.rx.changes` is removed, replaced with `DatabaseRegionObservation.rx.changes`.\n- SQLCipher support is now available under the CocoaPods `RxGRDB/SQLCipher` name.\n\n\n## 0.13.0\n\nReleased November 2, 2018 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.12.1...v0.13.0)\n\n- [#46](https://github.com/RxSwiftCommunity/RxGRDB/pull/46): Implement RxGRDB on top GRDB.ValueObservation\n\n\n### Breaking Changes\n\n- The `DatabaseWriter.rx.fetch` method has been removed. Instead, use [`ValueObservation.rx.fetch`](README.md#valueobservationrxfetchinstartimmediatelyscheduler).\n- The `distinctUntilChanged` parameter is no longer available when one creates an RxGRDB observable. Filtering of consecutive identical database values is now the default behavior.\n\n\n### New\n\n- One can now create a [values observable](README.md#values-observables) from a [DatabaseReader](https://groue.github.io/GRDB.swift/docs/3.5/Protocols/DatabaseReader.html).\n\n\n## 0.12.1\n\nReleased October 25, 2018 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.12.0...v0.12.1)\n\n- Fixed GRDB Cocoapods dependency.\n\n\n## 0.12.0\n\nReleased Septembre 17, 2018 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.11.0...v0.12.0)\n\n- [#39](https://github.com/RxSwiftCommunity/RxGRDB/pull/39): Xcode 10 & GRDB 3.3.0\n\n\n## 0.11.0\n\nReleased June 7, 2018 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.10.0...v0.11.0)\n\n### New\n\n- Support for GRDB 3.0\n- The new DatabaseRegionConvertible protocol allows better request encapsulation ([documentation](README.md#databaseregionconvertible-protocol))\n\n### Breaking Changes\n\n- \"Fetch tokens\" and the `mapFetch` operator were ill-advised, and have been removed. Now please use the new `DatabaseWriter.fetch(from:startImmediately:scheduler:values:)` method instead, which produces exactly the same observable:\n    \n    ```diff\n     // Old way\n    -let values = dbQueue.rx\n    -    .fetchTokens(in: [request, ...])\n    -    .mapFetch { db in\n    -        try fetchResults(db)\n    -    }\n     \n     // New way\n    +let values = dbQueue.rx.fetch(from: [request, ...]) { db in\n    +    try fetchResults(db)\n    +}\n    ```\n\n\n## 0.10.0\n\nReleased March 26, 2018 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.9.0...v0.10.0)\n\n\n### New\n\n- Unless they are provided an explicit scheduler, [values observables](https://github.com/RxSwiftCommunity/RxGRDB/blob/master/README.md#values-observables) subscribed from the main queue are now guaranteed a synchronous emission of their initial value ([#28](https://github.com/RxSwiftCommunity/RxGRDB/pull/28)).\n\n- The RxGRDB repository now uses CocoaPods for its inner dependencies GRBD and RxSwift. After you have downloaded the RxGRDB repository, run `pod repo update; pod install` in order to download all dependencies, build targets, or run tests ([#29](https://github.com/RxSwiftCommunity/RxGRDB/pull/29)).\n\n\n### Documentation Diff\n\n- The [Values Observables](https://github.com/RxSwiftCommunity/RxGRDB/blob/master/README.md#values-observables) chapter now describes the scheduling of fetched values.\n\n\n## 0.9.0\n\nReleased February 25, 2018 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.8.1...v0.9.0)\n\n\n### New\n\n- [Values observables](https://github.com/RxSwiftCommunity/RxGRDB/blob/master/README.md#values-observables) can now be scheduled on any RxSwift scheduler (fixes [#22](https://github.com/RxSwiftCommunity/RxGRDB/issues/22)).\n\n\n### Breaking Changees\n\n- \"Change Tokens\" have been renamed \"Fetch Tokens\" in order to better reflect their purpose, and to enhance the distinction between observables that emit values on any schedulers (\"values observables\") and have \"fetch\" in their definition, from observables that emit database connections on a GRDB dispatch queue (\"changes observables\") and have \"changes\" in their definition).\n\n\n### Documentation Diff\n\n- The [Scheduling Guide](https://github.com/RxSwiftCommunity/RxGRDB/blob/master/README.md#scheduling) has been augmented with a chapter on data consistency.\n\n\n### API diff\n\n```diff\n+struct FetchToken { }\n-struct ChangeToken { }\n\n extension Reactive where Base: DatabaseWriter {\n+    func fetchTokens(in requests: [Request], startImmediately: Bool = true, scheduler: ImmediateSchedulerType = MainScheduler.instance) -> Observable<FetchToken>\n-    func changeTokens(in requests: [Request], startImmediately: Bool = true, scheduler: ImmediateSchedulerType = MainScheduler.instance) -> Observable<ChangeToken>\n }\n```\n\n\n## 0.8.1\n\nReleased February 20, 2018 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.8.0...v0.8.1)\n\n- Fixes a bug that would have [values observables](https://github.com/RxSwiftCommunity/RxGRDB/blob/master/README.md#values-observables) fail to observe some database changes.\n\n\n## 0.8.0\n\nReleased January 18, 2018 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.7.0...v0.8.0)\n\nThis version enhances the scheduling of database notifications, and the tracking of specific database rows.\n\n\n## New\n\n- The tracking of requests that target specific rows, identified by their row ids, has been enhanced:\n    \n    In previous version of RxGRDB, tracking `Player.filter(key: 1)` would trigger change notifications for all changes to the players table.\n    \n    Now RxGRDB is able to precisely track the player of ID 1, and won't emit any notification for changes performed on other players.\n\n\n## Fixed\n\n- RxGRDB observables used to require subscription and observation to happen on the same dispatch queue. It was easy to fail this precondition, and misuse the library. This has been fixed.\n- The [demo application](https://github.com/RxSwiftCommunity/RxGRDB/tree/master/Documentation/RxGRDBDemo) used to misuse MKMapView by converting database changes into annotation coordinate updates on the wrong dispatch queue. This has been fixed.\n\n\n### Breaking Changes\n\n- GRDB dependency has been bumped to v2.6.\n- Database observation scheduling used to be managed through raw dispatch queues. One now uses regular [RxSwift schedulers](https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Schedulers.md). The `synchronizedStart` parameter has been renamed to `startImmediately` in order to reflect the fact that not all schedulers can start synchronously. See the updated [documentation](https://github.com/RxSwiftCommunity/RxGRDB/blob/master/README.md#documentation) of RxGRDB reactive methods.\n- The `Diffable` protocol was ill-advised, and has been removed.\n- The `primaryKeySortedDiff` operator has been replaced by `PrimaryKeyDiffScanner` ([documentation](https://github.com/RxSwiftCommunity/RxGRDB/blob/master/README.md#primarykeydiffscanner))\n\n\n### API diff\n\n```diff\n extension Reactive where Base: Request {\n-    func changes(\n-        in writer: DatabaseWriter,\n-        synchronizedStart: Bool = true)\n-        -> Observable<Database>\n+    func changes(\n+        in writer: DatabaseWriter,\n+        startImmediately: Bool = true)\n+        -> Observable<Database>\n \n-    func fetchCount(\n-        in writer: DatabaseWriter,\n-        synchronizedStart: Bool = true,\n-        resultQueue: DispatchQueue = DispatchQueue.main)\n-        -> Observable<Int>\n+    func fetchCount(\n+        in writer: DatabaseWriter,\n+        startImmediately: Bool = true,\n+        scheduler: SerialDispatchQueueScheduler = MainScheduler.instance)\n+        -> Observable<Int>\n }\n\n extension Reactive where Base: TypedRequest {\n-    func fetchAll(\n-        in writer: DatabaseWriter,\n-        synchronizedStart: Bool = true,\n-        resultQueue: DispatchQueue = DispatchQueue.main,\n-        distinctUntilChanged: Bool = false)\n-        -> Observable<[Base.RowDecoder]>\n+    func fetchAll(\n+        in writer: DatabaseWriter,\n+        startImmediately: Bool = true,\n+        scheduler: SerialDispatchQueueScheduler = MainScheduler.instance,\n+        distinctUntilChanged: Bool = false)\n+        -> Observable<[Base.RowDecoder]>\n \n-    func fetchOne(\n-        in writer: DatabaseWriter,\n-        synchronizedStart: Bool = true,\n-        resultQueue: DispatchQueue = DispatchQueue.main,\n-        distinctUntilChanged: Bool = false)\n-        -> Observable<Base.RowDecoder?>\n+    func fetchOne(\n+        in writer: DatabaseWriter,\n+        startImmediately: Bool = true,\n+        scheduler: SerialDispatchQueueScheduler = MainScheduler.instance,\n+        distinctUntilChanged: Bool = false)\n+        -> Observable<Base.RowDecoder?>\n }\n\n extension ObservableType where E == ChangeToken {\n-    func mapFetch<R>(\n-        resultQueue: DispatchQueue = DispatchQueue.main,\n-        _ fetch: @escaping (Database) throws -> R)\n-        -> Observable<R>\n+    func mapFetch<R>(_ fetch: @escaping (Database) throws -> R) -> Observable<R>\n }\n\n extension Reactive where Base: DatabaseWriter {\n-    public func changes(\n-        in requests: [Request],\n-        synchronizedStart: Bool = true)\n-        -> Observable<Database>\n+    public func changes(\n+        in requests: [Request],\n+        startImmediately: Bool = true)\n+        -> Observable<Database>\n \n-    func changeTokens(\n-        in requests: [Request],\n-        synchronizedStart: Bool = true)\n-        -> Observable<ChangeToken>\n+    func changeTokens(\n+        in requests: [Request],\n+        startImmediately: Bool = true,\n+        scheduler: SerialDispatchQueueScheduler = MainScheduler.instance)\n+        -> Observable<ChangeToken>\n }\n\n-protocol Diffable {\n-    func updated(with row: Row) -> Self\n-}\n-extension Reactive where Base: TypedRequest, Base.RowDecoder: RowConvertible & MutablePersistable & Diffable {\n-    func primaryKeySortedDiff(\n-        in writer: DatabaseWriter,\n-        initialElements: [Base.RowDecoder] = [])\n-        -> Observable<PrimaryKeySortedDiff<Base.RowDecoder>>\n-}\n-struct PrimaryKeySortedDiff<Element> { ... }\n+struct PrimaryKeyDiffScanner<Record: RowConvertible & MutablePersistable> {\n+    let diff: PrimaryKeyDiff<Record>\n+    init<Request>(\n+            database: Database,\n+            request: Request,\n+            initialRecords: [Record],\n+            updateRecord: ((Record, Row) -> Record)? = nil)\n+            throws\n+            where Request: TypedRequest, Request.RowDecoder == Record\n+    func diffed(from rows: [Row]) -> PrimaryKeyDiffScanner\n+}\n+struct PrimaryKeyDiff<Record> {\n+    let inserted: [Record]\n+    let updated: [Record]\n+    let deleted: [Record]\n+    var isEmpty: Bool\n+}\n```\n\n## 0.7.0\n\nReleased October 18, 2017 &bull; [diff](https://github.com/RxSwiftCommunity/RxGRDB/compare/v0.6.0...v0.7.0)\n\n### New\n\n- Support for Swift 4\n- Support for various diff algorithms ([Documentation](https://github.com/RxSwiftCommunity/RxGRDB/blob/master/README.md#diffs))\n- New [demo application](https://github.com/RxSwiftCommunity/RxGRDB/tree/master/Documentation/RxGRDBDemo) for various diff algorithms.\n\n### Fixed\n\n- Observables that emit fetched values used to emit their first element on the wrong dispatch queue when their `synchronizedStart` option is true. That first element is now correctly emitted on the subscription dispatch queue.\n\n### Breaking Changes\n\n- Requirements have changed: Xcode 9+, Swift 4, GRDB 2.0\n\n\n## 0.6.0\n\nReleased July 13, 2017\n\n- **Fixed**: Support for macOS, broken in v0.5.0\n- **New**: GRDB dependency bumped to v1.2\n\n\n## 0.5.0\n\nReleased July 8, 2017\n\n### New\n\nRxGRDB has learned how to observe multiple requests and fetch from other requests. [Documentation](https://github.com/RxSwiftCommunity/RxGRDB/blob/master/README.md#observing-multiple-requests)\n\nTo get a single notification when a transaction has modified several requests, use `DatabaseWriter.rx.changes`:\n\n```swift\n// Observable<Database>\ndbQueue.rx.changes(in: [request, ...])\n```\n\nTo turn a change notification into consistent results fetched from multiple requests, use `DatabaseWriter.rx.changeTokens` and the `mapFetch` operator:\n\n```swift\ndbQueue.rx\n    .changeTokens(in: [request, ...])\n    .mapFetch { (db: Database) in\n        return ...\n    }\n```\n\n### API diff\n\n```diff\n+extension Reactive where Base: DatabaseWriter {\n+    func changes(in requests: [Request], synchronizedStart: Bool = true) -> Observable<Database>\n+    func changeTokens(in requests: [Request], synchronizedStart: Bool = true) -> Observable<ChangeToken>\n+}\n\n+struct ChangeToken {\n+    var database: Database { get }\n+}\n\n+extension ObservableType where E == ChangeToken {\n+    func func mapFetch<R>(resultQueue: DispatchQueue = DispatchQueue.main, _ fetch: @escaping (Database) throws -> R) -> Observable<R>\n+}\n```\n\n\n## 0.4.1\n\nReleased June 20, 2017\n\n### Fixed\n\n- Podspec requirement for RxSwift changed to `~> 3.3`\n- Added missing support for new AdaptedRequest and AdaptedTypedRequest of GRDB 1.0\n\n\n## 0.4.0\n\nReleased June 20, 2017\n\n### Breaking Changes\n\n- RxGRDB now requires GRDB v1.0\n\n\n## 0.3.0\n\nReleased May 22, 2017\n\n### New\n\n- The new `distinctUntilChanged` parameter has RxGRDB avoid notifying consecutive identical values.\n\n    ```swift\n    request.rx.fetchAll(in: dbQueue, distinctUntilChanged: true)...\n    ```\n\n- Tracking of requests that fetch an array of optional values:\n    \n    ```swift\n    // Email column may be NULL:\n    let request = Person.select(email).bound(to: Optional<String>.self)\n    request.rx.fetchAll(in: dbQueue)\n        .subscribe(onNext: { emails: [String?] in\n            ...\n        })\n    ```\n\n\n## 0.2.0\n\nReleased May 17, 2017\n\n### New\n\n- Support for SQLCipher.\n\n\n## 0.1.2\n\nReleased April 6, 2017\n\n### Fixed\n\n- RxGRDB observables now support the `retry` operator, and no longer crash when disposed on a database queue.\n\n\n## 0.1.1\n\nReleased April 5, 2017\n\n### New\n\n- `synchronizedStart` option\n- `Request.rx.fetchCount(in:synchronizedStart)`\n\n\n## 0.1.0\n\nReleased April 5, 2017\n\nInitial release\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/README.md",
    "content": "RxGRDBDemo\n==========\n\n<img align=\"right\" src=\"https://raw.githubusercontent.com/RxSwiftCommunity/RxGRDB/master/Documentation/RxGRDBDemo/Documentation/Demo1.png\" width=\"50%\">\n\nThis demo application uses [Action], [RxDataSources], [RxGRDB], and [RxSwift] to synchronize its view with the content of the database.\n\nTo play with it:\n\n1. Download the RxGRDB repository\n2. Run `pod install`\n3. Open `RxGRDB.xcworkspace` at the root of the repository\n4. Run the RxGRDBDemo application.\n\nThe rows of the players table view animate as you change the players ordering, delete all players, or refresh them (refreshing applies random transformations to the database)\n\n## Models\n\n- [AppDatabase.swift](RxGRDBDemo/AppDatabase.swift)\n    \n    AppDatabase defines the database for the whole application. It uses [DatabaseMigrator](https://github.com/groue/GRDB.swift/blob/master/README.md#migrations) in order to setup the database schema.\n\n- [Player.swift](RxGRDBDemo/Models/Player.swift)\n    \n    Player is a [Record](https://github.com/groue/GRDB.swift/blob/master/README.md#records) type, able to read and write in the database. It conforms to the standard Codable protocol in order to gain all advantages of [Codable Records](https://github.com/groue/GRDB.swift/blob/master/README.md#codable-records).\n    \n    ```swift\n    struct Player: Codable, Equatable {\n        var id: Int64?\n        var name: String\n        var score: Int\n    }\n    ```\n\n- [Players.swift](RxGRDBDemo/Models/Players.swift)\n    \n    Players defines read and write operations on the players database.\n\n\n## User Interface\n\n- [PlayersViewModel.swift](RxGRDBDemo/UI/PlayersViewModel.swift)\n    \n    PlayersViewModel defines the content displayed on screen, and a bunch of available actions of players.\n\n- [PlayersViewController.swift](RxGRDBDemo/UI/PlayersViewController.swift)\n    \n    PlayersViewController feeds from PlayersViewModel and displays it on screen.\n\n\n[Action]: https://github.com/RxSwiftCommunity/Action\n[RxDataSources]: https://github.com/RxSwiftCommunity/RxDataSources\n[RxGRDB]: http://github.com/RxSwiftCommunity/RxGRDB\n[RxSwift]: https://github.com/ReactiveX/RxSwift\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/AppDatabase.swift",
    "content": "import GRDB\n\n/// A type responsible for initializing an application database.\nstruct AppDatabase {\n    \n    /// Prepares a fully initialized database at path\n    func setup(_ database: DatabaseWriter) throws {\n        // Use DatabaseMigrator to define the database schema\n        // See https://github.com/groue/GRDB.swift/#migrations\n        try migrator.migrate(database)\n        \n        // Other possible setup include: custom functions, collations,\n        // full-text tokenizers, etc.\n    }\n    \n    /// The DatabaseMigrator that defines the database schema.\n    // See https://github.com/groue/GRDB.swift/#migrations\n    private var migrator: DatabaseMigrator {\n        var migrator = DatabaseMigrator()\n        \n        #if DEBUG\n        // Speed up development by nuking the database when migrations change\n        migrator.eraseDatabaseOnSchemaChange = true\n        #endif\n        \n        migrator.registerMigration(\"v1.0\") { db in\n            try db.create(table: \"player\") { t in\n                t.autoIncrementedPrimaryKey(\"id\")\n                t.column(\"name\", .text).notNull().collate(.localizedCaseInsensitiveCompare)\n                t.column(\"score\", .integer).notNull()\n            }\n            \n            try db.create(table: \"place\") { t in\n                t.autoIncrementedPrimaryKey(\"id\")\n                t.column(\"latitude\", .double).notNull()\n                t.column(\"longitude\", .double).notNull()\n            }\n        }\n        \n        return migrator\n    }\n}\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/AppDelegate.swift",
    "content": "import UIKit\nimport GRDB\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n    var window: UIWindow?\n    \n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        \n        // Setup the Current World\n        let dbPool = try! setupDatabase(application)\n        Current = World(database: { dbPool })\n        \n        // Application is nicer looking if it starts populated\n        try! Current.players().populateIfEmpty()\n        \n        return true\n    }\n    \n    private func setupDatabase(_ application: UIApplication) throws -> DatabasePool {\n        // Create a DatabasePool for efficient multi-threading\n        let databaseURL = try FileManager.default\n            .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)\n            .appendingPathComponent(\"db.sqlite\")\n        let dbPool = try DatabasePool(path: databaseURL.path)\n        \n        // Setup the database\n        try AppDatabase().setup(dbPool)\n        \n        return dbPool\n    }\n}\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/Models/Player.swift",
    "content": "import GRDB\n\n// A player\nstruct Player: Codable, Equatable {\n    var id: Int64?\n    var name: String\n    var score: Int\n}\n\n// Adopt FetchableRecord so that we can fetch players from the database.\n// Implementation is automatically derived from Codable.\nextension Player: FetchableRecord { }\n\n// Adopt MutablePersistable so that we can create/update/delete players in the\n// database. Implementation is partially derived from Codable.\nextension Player: MutablePersistableRecord {\n    // Update auto-incremented id upon successful insertion\n    mutating func didInsert(with rowID: Int64, for column: String?) {\n        id = rowID\n    }\n}\n\n// Define columns that we can use for our database requests.\n// They are derived from the CodingKeys enum for extra safety.\nextension Player {\n    fileprivate enum Columns {\n        static let id = Column(CodingKeys.id)\n        static let name = Column(CodingKeys.name)\n        static let score = Column(CodingKeys.score)\n    }\n}\n\n// Define requests of players in a constrained extension to the\n// DerivableRequest protocol.\nextension DerivableRequest where RowDecoder == Player {\n    func orderByScore() -> Self {\n        return order(Player.Columns.score.desc, Player.Columns.name)\n    }\n    \n    func orderByName() -> Self {\n        return order(Player.Columns.name, Player.Columns.score.desc)\n    }\n}\n\n// Player randomization\nextension Player {\n    private static let names = [\n        \"Arthur\", \"Anita\", \"Barbara\", \"Bernard\", \"Clément\", \"Chiara\", \"David\",\n        \"Dean\", \"Éric\", \"Elena\", \"Fatima\", \"Frederik\", \"Gilbert\", \"Georgette\",\n        \"Henriette\", \"Hassan\", \"Ignacio\", \"Irene\", \"Julie\", \"Jack\", \"Karl\",\n        \"Kristel\", \"Louis\", \"Liz\", \"Masashi\", \"Mary\", \"Noam\", \"Nolwenn\",\n        \"Ophelie\", \"Oleg\", \"Pascal\", \"Patricia\", \"Quentin\", \"Quinn\", \"Raoul\",\n        \"Rachel\", \"Stephan\", \"Susie\", \"Tristan\", \"Tatiana\", \"Ursule\", \"Urbain\",\n        \"Victor\", \"Violette\", \"Wilfried\", \"Wilhelmina\", \"Yvon\", \"Yann\",\n        \"Zazie\", \"Zoé\"]\n    \n    static func randomName() -> String {\n        return names.randomElement()!\n    }\n    \n    static func randomScore() -> Int {\n        return 10 * Int.random(in: 0...100)\n    }\n}\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/Models/Players.swift",
    "content": "import GRDB\nimport RxGRDB\nimport RxSwift\n\n/// Players is responsible for high-level operations on the players database.\nstruct Players {\n    private let database: DatabaseWriter\n    \n    init(database: DatabaseWriter) {\n        self.database = database\n    }\n    \n    // MARK: - Modify Players\n    \n    /// Creates random players if needed, and returns whether the database\n    /// was empty.\n    @discardableResult\n    func populateIfEmpty() throws -> Bool {\n        try database.write(_populateIfEmpty)\n    }\n    \n    func deleteAll() -> Single<Void> {\n        database.rx.write(updates: _deleteAll)\n    }\n    \n    func deleteOne(_ player: Player) -> Single<Void> {\n        database.rx.write(updates: { db in try self._deleteOne(db, player: player) })\n    }\n    \n    func refresh() -> Single<Void> {\n        database.rx.write(updates: _refresh)\n    }\n    \n    func stressTest() -> Single<Void> {\n        Single.zip(repeatElement(refresh(), count: 50)).map { _ in }\n    }\n    \n    // MARK: - Access Players\n    \n    /// An observable that tracks changes in the players\n    func playersOrderedByScore() -> Observable<[Player]> {\n        ValueObservation\n            .tracking(Player.all().orderByScore().fetchAll)\n            .rx.observe(in: database)\n    }\n    \n    /// An observable that tracks changes in the players\n    func playersOrderedByName() -> Observable<[Player]> {\n        ValueObservation\n            .tracking(Player.all().orderByName().fetchAll)\n            .rx.observe(in: database)\n    }\n    \n    // MARK: - Implementation\n    //\n    // ⭐️ Good practice: when we want to update the database, we define methods\n    // that accept a Database connection, because they can easily be composed.\n    \n    /// Creates random players if needed, and returns whether the database\n    /// was empty.\n    private func _populateIfEmpty(_ db: Database) throws -> Bool {\n        if try Player.fetchCount(db) > 0 {\n            return false\n        }\n        \n        // Insert new random players\n        for _ in 0..<8 {\n            var player = Player(id: nil, name: Player.randomName(), score: Player.randomScore())\n            try player.insert(db)\n        }\n        return true\n    }\n    \n    private func _deleteAll(_ db: Database) throws {\n        try Player.deleteAll(db)\n    }\n    \n    private func _deleteOne(_ db: Database, player: Player) throws {\n        try player.delete(db)\n    }\n    \n    private func _refresh(_ db: Database) throws {\n        if try _populateIfEmpty(db) {\n            return\n        }\n        \n        // Insert a player\n        if Bool.random() {\n            var player = Player(id: nil, name: Player.randomName(), score: Player.randomScore())\n            try player.insert(db)\n        }\n        // Delete a random player\n        if Bool.random() {\n            try Player.order(sql: \"RANDOM()\").limit(1).deleteAll(db)\n        }\n        // Update some players\n        for var player in try Player.fetchAll(db) where Bool.random() {\n            try player.updateChanges(db) {\n                $0.score = Player.randomScore()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/Resources/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" systemVersion=\"17A277\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/Resources/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14490.70\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"xTj-0J-jag\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14490.49\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Hall of Fame-->\n        <scene sceneID=\"dn1-UJ-DYy\">\n            <objects>\n                <viewController id=\"GLL-Xk-ypD\" customClass=\"PlayersViewController\" customModule=\"RxGRDBDemo\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"t9e-5y-1YT\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <tableView clipsSubviews=\"YES\" contentMode=\"scaleToFill\" alwaysBounceVertical=\"YES\" dataMode=\"prototypes\" style=\"plain\" separatorStyle=\"default\" rowHeight=\"-1\" estimatedRowHeight=\"-1\" sectionHeaderHeight=\"28\" sectionFooterHeight=\"28\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bXR-pQ-fFV\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                                <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <prototypes>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" selectionStyle=\"none\" indentationWidth=\"10\" reuseIdentifier=\"Player\" textLabel=\"q0A-CX-hct\" detailTextLabel=\"ZU9-MH-ADf\" style=\"IBUITableViewCellStyleValue1\" id=\"O5b-qw-AuB\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"28\" width=\"375\" height=\"44\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" insetsLayoutMarginsFromSafeArea=\"NO\" tableViewCell=\"O5b-qw-AuB\" id=\"GIv-EG-2oT\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"43.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"Title\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"q0A-CX-hct\">\n                                                    <rect key=\"frame\" x=\"15\" y=\"12\" width=\"33.5\" height=\"20.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <nil key=\"textColor\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"Detail\" textAlignment=\"right\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"ZU9-MH-ADf\">\n                                                    <rect key=\"frame\" x=\"316\" y=\"12\" width=\"44\" height=\"20.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <nil key=\"textColor\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                            </subviews>\n                                        </tableViewCellContentView>\n                                    </tableViewCell>\n                                </prototypes>\n                            </tableView>\n                            <visualEffectView opaque=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"d2C-E5-vHW\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"64\" width=\"375\" height=\"559\"/>\n                                <view key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"jHw-6h-iUF\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"559\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"No Player\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontForContentSizeCategory=\"YES\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rZc-LE-xF6\">\n                                            <rect key=\"frame\" x=\"151\" y=\"269\" width=\"73.5\" height=\"21\"/>\n                                            <fontDescription key=\"fontDescription\" style=\"UICTFontTextStyleBody\"/>\n                                            <color key=\"textColor\" white=\"0.66666666666666663\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                            <nil key=\"highlightedColor\"/>\n                                        </label>\n                                    </subviews>\n                                    <constraints>\n                                        <constraint firstItem=\"rZc-LE-xF6\" firstAttribute=\"centerY\" secondItem=\"jHw-6h-iUF\" secondAttribute=\"centerY\" id=\"QUf-R7-eRK\"/>\n                                        <constraint firstItem=\"rZc-LE-xF6\" firstAttribute=\"centerX\" secondItem=\"jHw-6h-iUF\" secondAttribute=\"centerX\" id=\"Vxw-R3-mxL\"/>\n                                    </constraints>\n                                </view>\n                                <blurEffect style=\"prominent\"/>\n                            </visualEffectView>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"J24-oS-fQn\" firstAttribute=\"bottom\" secondItem=\"d2C-E5-vHW\" secondAttribute=\"bottom\" id=\"3aY-JG-086\"/>\n                            <constraint firstItem=\"d2C-E5-vHW\" firstAttribute=\"leading\" secondItem=\"t9e-5y-1YT\" secondAttribute=\"leading\" id=\"3lh-10-DaJ\"/>\n                            <constraint firstItem=\"bXR-pQ-fFV\" firstAttribute=\"top\" secondItem=\"t9e-5y-1YT\" secondAttribute=\"top\" id=\"BrP-Nz-4ZZ\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"d2C-E5-vHW\" secondAttribute=\"trailing\" id=\"D7P-Zp-MgG\"/>\n                            <constraint firstItem=\"bXR-pQ-fFV\" firstAttribute=\"leading\" secondItem=\"t9e-5y-1YT\" secondAttribute=\"leading\" id=\"DqX-wI-Qjp\"/>\n                            <constraint firstItem=\"bXR-pQ-fFV\" firstAttribute=\"trailing\" secondItem=\"t9e-5y-1YT\" secondAttribute=\"trailing\" id=\"Q9v-wC-nwK\"/>\n                            <constraint firstItem=\"d2C-E5-vHW\" firstAttribute=\"top\" secondItem=\"J24-oS-fQn\" secondAttribute=\"top\" id=\"Umo-im-bz7\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"bXR-pQ-fFV\" secondAttribute=\"bottom\" id=\"dit-bQ-w2u\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"J24-oS-fQn\"/>\n                    </view>\n                    <navigationItem key=\"navigationItem\" title=\"Hall of Fame\" id=\"XOX-J3-Q9U\"/>\n                    <connections>\n                        <outlet property=\"emptyView\" destination=\"d2C-E5-vHW\" id=\"3xT-Hj-O9G\"/>\n                        <outlet property=\"tableView\" destination=\"bXR-pQ-fFV\" id=\"JFe-wC-Zyg\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"v2h-i8-h1r\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-783.20000000000005\" y=\"-153.37331334332833\"/>\n        </scene>\n        <!--Navigation Controller-->\n        <scene sceneID=\"K9r-My-Kvk\">\n            <objects>\n                <navigationController toolbarHidden=\"NO\" id=\"xTj-0J-jag\" sceneMemberID=\"viewController\">\n                    <navigationBar key=\"navigationBar\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"7ys-OS-Gzd\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"20\" width=\"375\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </navigationBar>\n                    <toolbar key=\"toolbar\" opaque=\"NO\" clearsContextBeforeDrawing=\"NO\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"R8l-dN-zJb\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"623\" width=\"375\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </toolbar>\n                    <connections>\n                        <segue destination=\"GLL-Xk-ypD\" kind=\"relationship\" relationship=\"rootViewController\" id=\"N8i-92-38f\"/>\n                    </connections>\n                </navigationController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"KA4-WL-wIo\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-1636\" y=\"-153\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/UI/PlayersViewController.swift",
    "content": "import UIKit\nimport RxDataSources\nimport RxSwift\nimport RxCocoa\n\n/// An MVVM ViewController that displays PlayersViewModel\nclass PlayersViewController: UIViewController {\n    @IBOutlet private weak var tableView: UITableView!\n    @IBOutlet private weak var emptyView: UIView!\n    private let viewModel = PlayersViewModel()\n    private let disposeBag = DisposeBag()\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        setupNavigationItem()\n        setupToolbar()\n        setupTableView()\n        setupEmptyView()\n    }\n    \n    private func setupNavigationItem() {\n        viewModel\n            .orderingButtonTitle\n            .subscribe(onNext: updateRightBarButtonItem)\n            .disposed(by: disposeBag)\n    }\n    \n    private func updateRightBarButtonItem(title: String?) {\n        guard let title = title else {\n            navigationItem.rightBarButtonItem = nil\n            return\n        }\n        \n        var barButtonItem = UIBarButtonItem(title: title, style: .plain, target: nil, action: nil)\n        barButtonItem.rx.action = viewModel.toggleOrdering\n        navigationItem.rightBarButtonItem = barButtonItem\n    }\n    \n    private func setupToolbar() {\n        var deleteAllButtonItem = UIBarButtonItem(barButtonSystemItem: .trash, target: nil, action: nil)\n        deleteAllButtonItem.rx.action = viewModel.deleteAll\n        \n        var refreshButtonItem = UIBarButtonItem(barButtonSystemItem: .refresh, target: nil, action: nil)\n        refreshButtonItem.rx.action = viewModel.refresh\n        \n        var stressTestButtonItem = UIBarButtonItem(title: \"💣\", style: .plain, target: nil, action: nil)\n        stressTestButtonItem.rx.action = viewModel.stressTest\n        \n        toolbarItems = [\n            deleteAllButtonItem,\n            UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),\n            refreshButtonItem,\n            UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),\n            stressTestButtonItem,\n        ]\n    }\n    \n    private func setupTableView() {\n        let dataSource = RxTableViewSectionedAnimatedDataSource<Section>(configureCell: { (dataSource, tableView, indexPath, _) in\n            let section = dataSource.sectionModels[indexPath.section]\n            let player = section.items[indexPath.row]\n            let cell = tableView.dequeueReusableCell(withIdentifier: \"Player\", for: indexPath)\n            cell.textLabel?.text = player.name\n            cell.detailTextLabel?.text = \"\\(player.score)\"\n            return cell\n        })\n        \n        dataSource.animationConfiguration = AnimationConfiguration(\n            insertAnimation: .fade,\n            reloadAnimation: .fade,\n            deleteAnimation: .fade)\n        \n        dataSource.canEditRowAtIndexPath = { _, _ in true }\n        \n        viewModel\n            .players\n            .asDriver(onErrorJustReturn: [])\n            .map { [Section(items: $0)] }\n            .drive(tableView.rx.items(dataSource: dataSource))\n            .disposed(by: disposeBag)\n        \n        tableView.rx\n            .itemDeleted\n            .subscribe(onNext: { indexPath in\n                let player = dataSource[indexPath]\n                self.viewModel.deleteOne.execute(player)\n            })\n            .disposed(by: disposeBag)\n    }\n    \n    private func setupEmptyView() {\n        viewModel\n            .players\n            .map { !$0.isEmpty }\n            .asDriver(onErrorJustReturn: false)\n            .drive(emptyView.rx.isHidden)\n            .disposed(by: disposeBag)\n    }\n}\n\nprivate struct Section {\n    var items: [Player]\n}\n\nextension Section: AnimatableSectionModelType {\n    var identity: Int { return 1 }\n    init(original: Section, items: [Player]) {\n        self.items = items\n    }\n}\n\nextension Player: IdentifiableType {\n    var identity: Int64 { return id! }\n}\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/UI/PlayersViewModel.swift",
    "content": "import Action\nimport Foundation\nimport GRDB\nimport RxCocoa\nimport RxGRDB\nimport RxSwift\n\n/// An MVVM ViewModel for PlayersViewController\nclass PlayersViewModel {\n    // MARK: - Values Displayed on Screen\n    \n    var orderingButtonTitle: Observable<String?>\n    var players: Observable<[Player]>\n    \n    // MARK: - Actions\n    \n    var toggleOrdering: CocoaAction\n    var deleteAll: CocoaAction\n    var deleteOne: CompletableAction<Player>\n    var refresh: CocoaAction\n    var stressTest: CocoaAction\n    \n    // MARK: - Implementation\n    \n    private enum Ordering: Equatable {\n        case byScore\n        case byName\n    }\n    private var ordering = BehaviorRelay<Ordering>(value: .byScore)\n    \n    init() {\n        // The root of everything\n        let ordering = BehaviorRelay<Ordering>(value: .byScore)\n        \n        // Values Displayed on Screen\n        players = ordering\n            .distinctUntilChanged()\n            .flatMapLatest { ordering -> Observable<[Player]> in\n                switch ordering {\n                case .byScore:\n                    return Current.players().playersOrderedByScore()\n                case .byName:\n                    return Current.players().playersOrderedByName()\n                }\n            }\n            .share(replay: 1)\n        \n        orderingButtonTitle = Observable\n            .combineLatest(players, ordering)\n            .map { players, ordering -> String? in\n                if players.isEmpty {\n                    return nil\n                }\n                switch ordering {\n                case .byScore:\n                    return NSLocalizedString(\"Score ⬇︎\", comment: \"\")\n                case .byName:\n                    return NSLocalizedString(\"Name ⬆︎\", comment: \"\")\n                }\n        }\n        \n        // Actions\n        deleteAll = CocoaAction {\n            Current.players().deleteAll()\n        }\n        \n        deleteOne = CompletableAction { player in\n            Current.players().deleteOne(player).asCompletable()\n        }\n        \n        refresh = CocoaAction {\n            Current.players().refresh()\n        }\n        \n        stressTest = CocoaAction {\n            Current.players().stressTest()\n        }\n        \n        toggleOrdering = CocoaAction {\n            switch ordering.value {\n            case .byName:\n                ordering.accept(.byScore)\n            case .byScore:\n                ordering.accept(.byName)\n            }\n            return Observable.just(())\n        }\n    }\n}\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo/World.swift",
    "content": "import GRDB\n\n/// Dependency Injection based on the \"How to Control the World\" article:\n/// https://www.pointfree.co/blog/posts/21-how-to-control-the-world\nstruct World {\n    /// Access to the players database\n    func players() -> Players { return Players(database: database()) }\n    \n    /// The database, private so that only high-level operations exposed by\n    /// `players` are available to the rest of the application.\n    private var database: () -> DatabaseWriter\n    \n    /// Creates a World with a database\n    init(database: @escaping () -> DatabaseWriter) {\n        self.database = database\n    }\n}\n\nvar Current = World(database: { fatalError(\"Database is uninitialized\") })\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 52;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t565BD7C522C3F8D600BB9B5A /* AppDatabaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 565BD7C422C3F8D600BB9B5A /* AppDatabaseTests.swift */; };\n\t\t565BD7C622C3F92F00BB9B5A /* AppDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E1F9931F81021300793BFA /* AppDatabase.swift */; };\n\t\t565BD7C722C3F97900BB9B5A /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E1F9951F81033200793BFA /* Player.swift */; };\n\t\t565BD7C922C3FA8B00BB9B5A /* PlayersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 565BD7C822C3FA8B00BB9B5A /* PlayersTests.swift */; };\n\t\t565BD7CA22C3FAA700BB9B5A /* Players.swift in Sources */ = {isa = PBXBuildFile; fileRef = 567515A322C3A9BC00A6FF66 /* Players.swift */; };\n\t\t565BD7D022C49D2100BB9B5A /* PlayersViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 565BD7CF22C49D2100BB9B5A /* PlayersViewModelTests.swift */; };\n\t\t565BD7D122C49D9800BB9B5A /* PlayersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 567515A722C3B1F100A6FF66 /* PlayersViewModel.swift */; };\n\t\t565BD7D222C49E6600BB9B5A /* World.swift in Sources */ = {isa = PBXBuildFile; fileRef = 567515A122C3A7DC00A6FF66 /* World.swift */; };\n\t\t565BD7D922C5DEE800BB9B5A /* PlayerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 565BD7D822C5DEE800BB9B5A /* PlayerTests.swift */; };\n\t\t567515A222C3A7DC00A6FF66 /* World.swift in Sources */ = {isa = PBXBuildFile; fileRef = 567515A122C3A7DC00A6FF66 /* World.swift */; };\n\t\t567515A422C3A9BC00A6FF66 /* Players.swift in Sources */ = {isa = PBXBuildFile; fileRef = 567515A322C3A9BC00A6FF66 /* Players.swift */; };\n\t\t567515A822C3B1F100A6FF66 /* PlayersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 567515A722C3B1F100A6FF66 /* PlayersViewModel.swift */; };\n\t\t567CE94228CB747200A95C34 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 567CE94128CB747200A95C34 /* RxCocoa */; };\n\t\t567E66D02438A6F80091B5D8 /* RxGRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 567E66CF2438A6F80091B5D8 /* RxGRDB */; };\n\t\t56D6EA2F2438AB77000D55EF /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 56D6EA2E2438AB77000D55EF /* RxSwift */; };\n\t\t56D6EA322438ABAE000D55EF /* RxDataSources in Frameworks */ = {isa = PBXBuildFile; productRef = 56D6EA312438ABAE000D55EF /* RxDataSources */; };\n\t\t56D6EA352438ABD7000D55EF /* Action in Frameworks */ = {isa = PBXBuildFile; productRef = 56D6EA342438ABD7000D55EF /* Action */; };\n\t\t56D6EA442438AF90000D55EF /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 56D6EA432438AF90000D55EF /* GRDB */; };\n\t\t56E1F97D1F8101EE00793BFA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E1F97C1F8101EE00793BFA /* AppDelegate.swift */; };\n\t\t56E1F97F1F8101EE00793BFA /* PlayersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E1F97E1F8101EE00793BFA /* PlayersViewController.swift */; };\n\t\t56E1F9821F8101EE00793BFA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 56E1F9801F8101EE00793BFA /* Main.storyboard */; };\n\t\t56E1F9841F8101EE00793BFA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 56E1F9831F8101EE00793BFA /* Assets.xcassets */; };\n\t\t56E1F9871F8101EE00793BFA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 56E1F9851F8101EE00793BFA /* LaunchScreen.storyboard */; };\n\t\t56E1F9941F81021300793BFA /* AppDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E1F9931F81021300793BFA /* AppDatabase.swift */; };\n\t\t56E1F9961F81033200793BFA /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E1F9951F81033200793BFA /* Player.swift */; };\n\t\t56E549F72438B4770060D2DC /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 56E549F62438B4770060D2DC /* GRDB */; };\n\t\t56E549F92438B49A0060D2DC /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 56E549F82438B49A0060D2DC /* RxSwift */; };\n\t\t56E549FB2438B4A40060D2DC /* RxBlocking in Frameworks */ = {isa = PBXBuildFile; productRef = 56E549FA2438B4A40060D2DC /* RxBlocking */; };\n\t\t56E549FD2438B5510060D2DC /* RxGRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 56E549FC2438B5510060D2DC /* RxGRDB */; };\n\t\t56E549FF2438B5670060D2DC /* Action in Frameworks */ = {isa = PBXBuildFile; productRef = 56E549FE2438B5670060D2DC /* Action */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t565BD7BB22C3F84A00BB9B5A /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 56E1F9711F8101EE00793BFA /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 56E1F9781F8101EE00793BFA;\n\t\t\tremoteInfo = RxGRDBDemo;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t569E8501200A5C720028D1EC /* Embed Frameworks */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tname = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t565BD7B622C3F84A00BB9B5A /* RxGRDBDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RxGRDBDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t565BD7BA22C3F84A00BB9B5A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t565BD7C422C3F8D600BB9B5A /* AppDatabaseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDatabaseTests.swift; sourceTree = \"<group>\"; };\n\t\t565BD7C822C3FA8B00BB9B5A /* PlayersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayersTests.swift; sourceTree = \"<group>\"; };\n\t\t565BD7CF22C49D2100BB9B5A /* PlayersViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayersViewModelTests.swift; sourceTree = \"<group>\"; };\n\t\t565BD7D822C5DEE800BB9B5A /* PlayerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTests.swift; sourceTree = \"<group>\"; };\n\t\t567515A122C3A7DC00A6FF66 /* World.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = World.swift; sourceTree = \"<group>\"; };\n\t\t567515A322C3A9BC00A6FF66 /* Players.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Players.swift; sourceTree = \"<group>\"; };\n\t\t567515A722C3B1F100A6FF66 /* PlayersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayersViewModel.swift; sourceTree = \"<group>\"; };\n\t\t567E66CD2438A6730091B5D8 /* RxGRDB */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RxGRDB; path = ../..; sourceTree = \"<group>\"; };\n\t\t56E1F9791F8101EE00793BFA /* RxGRDBDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RxGRDBDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t56E1F97C1F8101EE00793BFA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t56E1F97E1F8101EE00793BFA /* PlayersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayersViewController.swift; sourceTree = \"<group>\"; };\n\t\t56E1F9811F8101EE00793BFA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t56E1F9831F8101EE00793BFA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t56E1F9861F8101EE00793BFA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t56E1F9881F8101EE00793BFA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t56E1F9931F81021300793BFA /* AppDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDatabase.swift; sourceTree = \"<group>\"; };\n\t\t56E1F9951F81033200793BFA /* Player.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Player.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t565BD7B322C3F84A00BB9B5A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t56E549FF2438B5670060D2DC /* Action in Frameworks */,\n\t\t\t\t56E549F92438B49A0060D2DC /* RxSwift in Frameworks */,\n\t\t\t\t56E549FB2438B4A40060D2DC /* RxBlocking in Frameworks */,\n\t\t\t\t56E549F72438B4770060D2DC /* GRDB in Frameworks */,\n\t\t\t\t56E549FD2438B5510060D2DC /* RxGRDB in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t56E1F9761F8101EE00793BFA /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t567CE94228CB747200A95C34 /* RxCocoa in Frameworks */,\n\t\t\t\t56D6EA352438ABD7000D55EF /* Action in Frameworks */,\n\t\t\t\t56D6EA442438AF90000D55EF /* GRDB in Frameworks */,\n\t\t\t\t56D6EA322438ABAE000D55EF /* RxDataSources in Frameworks */,\n\t\t\t\t56D6EA2F2438AB77000D55EF /* RxSwift in Frameworks */,\n\t\t\t\t567E66D02438A6F80091B5D8 /* RxGRDB in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t565BD7B722C3F84A00BB9B5A /* RxGRDBDemoTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t565BD7BA22C3F84A00BB9B5A /* Info.plist */,\n\t\t\t\t565BD7C422C3F8D600BB9B5A /* AppDatabaseTests.swift */,\n\t\t\t\t565BD7C822C3FA8B00BB9B5A /* PlayersTests.swift */,\n\t\t\t\t565BD7CF22C49D2100BB9B5A /* PlayersViewModelTests.swift */,\n\t\t\t\t565BD7D822C5DEE800BB9B5A /* PlayerTests.swift */,\n\t\t\t);\n\t\t\tpath = RxGRDBDemoTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5675159E22C3A77800A6FF66 /* Models */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t56E1F9951F81033200793BFA /* Player.swift */,\n\t\t\t\t567515A322C3A9BC00A6FF66 /* Players.swift */,\n\t\t\t);\n\t\t\tpath = Models;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5675159F22C3A7AE00A6FF66 /* UI */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t56E1F97E1F8101EE00793BFA /* PlayersViewController.swift */,\n\t\t\t\t567515A722C3B1F100A6FF66 /* PlayersViewModel.swift */,\n\t\t\t);\n\t\t\tpath = UI;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t567515A022C3A7BA00A6FF66 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t56E1F9831F8101EE00793BFA /* Assets.xcassets */,\n\t\t\t\t56E1F9851F8101EE00793BFA /* LaunchScreen.storyboard */,\n\t\t\t\t56E1F9801F8101EE00793BFA /* Main.storyboard */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t567E66CE2438A6F80091B5D8 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t56E1F9701F8101EE00793BFA = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t56E1F97B1F8101EE00793BFA /* RxGRDBDemo */,\n\t\t\t\t565BD7B722C3F84A00BB9B5A /* RxGRDBDemoTests */,\n\t\t\t\t56E1F97A1F8101EE00793BFA /* Products */,\n\t\t\t\t567E66CD2438A6730091B5D8 /* RxGRDB */,\n\t\t\t\t567E66CE2438A6F80091B5D8 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t56E1F97A1F8101EE00793BFA /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t56E1F9791F8101EE00793BFA /* RxGRDBDemo.app */,\n\t\t\t\t565BD7B622C3F84A00BB9B5A /* RxGRDBDemoTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t56E1F97B1F8101EE00793BFA /* RxGRDBDemo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t56E1F9881F8101EE00793BFA /* Info.plist */,\n\t\t\t\t56E1F9931F81021300793BFA /* AppDatabase.swift */,\n\t\t\t\t56E1F97C1F8101EE00793BFA /* AppDelegate.swift */,\n\t\t\t\t567515A122C3A7DC00A6FF66 /* World.swift */,\n\t\t\t\t5675159E22C3A77800A6FF66 /* Models */,\n\t\t\t\t5675159F22C3A7AE00A6FF66 /* UI */,\n\t\t\t\t567515A022C3A7BA00A6FF66 /* Resources */,\n\t\t\t);\n\t\t\tpath = RxGRDBDemo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t565BD7B522C3F84A00BB9B5A /* RxGRDBDemoTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 565BD7BD22C3F84A00BB9B5A /* Build configuration list for PBXNativeTarget \"RxGRDBDemoTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t565BD7B222C3F84A00BB9B5A /* Sources */,\n\t\t\t\t565BD7B322C3F84A00BB9B5A /* Frameworks */,\n\t\t\t\t565BD7B422C3F84A00BB9B5A /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t565BD7BC22C3F84A00BB9B5A /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = RxGRDBDemoTests;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t56E549F62438B4770060D2DC /* GRDB */,\n\t\t\t\t56E549F82438B49A0060D2DC /* RxSwift */,\n\t\t\t\t56E549FA2438B4A40060D2DC /* RxBlocking */,\n\t\t\t\t56E549FC2438B5510060D2DC /* RxGRDB */,\n\t\t\t\t56E549FE2438B5670060D2DC /* Action */,\n\t\t\t);\n\t\t\tproductName = RxGRDBDemoTests;\n\t\t\tproductReference = 565BD7B622C3F84A00BB9B5A /* RxGRDBDemoTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t56E1F9781F8101EE00793BFA /* RxGRDBDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 56E1F98B1F8101EE00793BFA /* Build configuration list for PBXNativeTarget \"RxGRDBDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t56E1F9751F8101EE00793BFA /* Sources */,\n\t\t\t\t56E1F9761F8101EE00793BFA /* Frameworks */,\n\t\t\t\t56E1F9771F8101EE00793BFA /* Resources */,\n\t\t\t\t569E8501200A5C720028D1EC /* Embed Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = RxGRDBDemo;\n\t\t\tpackageProductDependencies = (\n\t\t\t\t567E66CF2438A6F80091B5D8 /* RxGRDB */,\n\t\t\t\t56D6EA2E2438AB77000D55EF /* RxSwift */,\n\t\t\t\t56D6EA312438ABAE000D55EF /* RxDataSources */,\n\t\t\t\t56D6EA342438ABD7000D55EF /* Action */,\n\t\t\t\t56D6EA432438AF90000D55EF /* GRDB */,\n\t\t\t\t567CE94128CB747200A95C34 /* RxCocoa */,\n\t\t\t);\n\t\t\tproductName = RxGRDBDemo;\n\t\t\tproductReference = 56E1F9791F8101EE00793BFA /* RxGRDBDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t56E1F9711F8101EE00793BFA /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1020;\n\t\t\t\tLastUpgradeCheck = 1230;\n\t\t\t\tORGANIZATIONNAME = \"Gwendal Roué\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t565BD7B522C3F84A00BB9B5A = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.2.1;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tTestTargetID = 56E1F9781F8101EE00793BFA;\n\t\t\t\t\t};\n\t\t\t\t\t56E1F9781F8101EE00793BFA = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.0;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 56E1F9741F8101EE00793BFA /* Build configuration list for PBXProject \"RxGRDBDemo\" */;\n\t\t\tcompatibilityVersion = \"Xcode 8.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 56E1F9701F8101EE00793BFA;\n\t\t\tpackageReferences = (\n\t\t\t\t56D6EA2D2438AB77000D55EF /* XCRemoteSwiftPackageReference \"RxSwift\" */,\n\t\t\t\t56D6EA302438ABAE000D55EF /* XCRemoteSwiftPackageReference \"RxDataSources\" */,\n\t\t\t\t56D6EA332438ABD7000D55EF /* XCRemoteSwiftPackageReference \"Action\" */,\n\t\t\t\t56D6EA422438AF90000D55EF /* XCRemoteSwiftPackageReference \"GRDB.swift\" */,\n\t\t\t);\n\t\t\tproductRefGroup = 56E1F97A1F8101EE00793BFA /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t56E1F9781F8101EE00793BFA /* RxGRDBDemo */,\n\t\t\t\t565BD7B522C3F84A00BB9B5A /* RxGRDBDemoTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t565BD7B422C3F84A00BB9B5A /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t56E1F9771F8101EE00793BFA /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t56E1F9871F8101EE00793BFA /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t56E1F9841F8101EE00793BFA /* Assets.xcassets in Resources */,\n\t\t\t\t56E1F9821F8101EE00793BFA /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t565BD7B222C3F84A00BB9B5A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t565BD7D922C5DEE800BB9B5A /* PlayerTests.swift in Sources */,\n\t\t\t\t565BD7D122C49D9800BB9B5A /* PlayersViewModel.swift in Sources */,\n\t\t\t\t565BD7C922C3FA8B00BB9B5A /* PlayersTests.swift in Sources */,\n\t\t\t\t565BD7CA22C3FAA700BB9B5A /* Players.swift in Sources */,\n\t\t\t\t565BD7C622C3F92F00BB9B5A /* AppDatabase.swift in Sources */,\n\t\t\t\t565BD7D022C49D2100BB9B5A /* PlayersViewModelTests.swift in Sources */,\n\t\t\t\t565BD7C722C3F97900BB9B5A /* Player.swift in Sources */,\n\t\t\t\t565BD7D222C49E6600BB9B5A /* World.swift in Sources */,\n\t\t\t\t565BD7C522C3F8D600BB9B5A /* AppDatabaseTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t56E1F9751F8101EE00793BFA /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t567515A422C3A9BC00A6FF66 /* Players.swift in Sources */,\n\t\t\t\t56E1F9961F81033200793BFA /* Player.swift in Sources */,\n\t\t\t\t56E1F9941F81021300793BFA /* AppDatabase.swift in Sources */,\n\t\t\t\t567515A822C3B1F100A6FF66 /* PlayersViewModel.swift in Sources */,\n\t\t\t\t56E1F97F1F8101EE00793BFA /* PlayersViewController.swift in Sources */,\n\t\t\t\t56E1F97D1F8101EE00793BFA /* AppDelegate.swift in Sources */,\n\t\t\t\t567515A222C3A7DC00A6FF66 /* World.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t565BD7BC22C3F84A00BB9B5A /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 56E1F9781F8101EE00793BFA /* RxGRDBDemo */;\n\t\t\ttargetProxy = 565BD7BB22C3F84A00BB9B5A /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t56E1F9801F8101EE00793BFA /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t56E1F9811F8101EE00793BFA /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t56E1F9851F8101EE00793BFA /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t56E1F9861F8101EE00793BFA /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t565BD7BE22C3F84A00BB9B5A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = AMD8W895CT;\n\t\t\t\tINFOPLIST_FILE = RxGRDBDemoTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.2;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tOTHER_SWIFT_FLAGS = \"-Xcc -fmodule-map-file=$(PROJECT_TEMP_ROOT)/GeneratedModuleMaps-$(PLATFORM_NAME)/RxCocoaRuntime.modulemap\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.github.groue.RxGRDBDemoTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/RxGRDBDemo.app/RxGRDBDemo\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t565BD7BF22C3F84A00BB9B5A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = AMD8W895CT;\n\t\t\t\tINFOPLIST_FILE = RxGRDBDemoTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.2;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tOTHER_SWIFT_FLAGS = \"-Xcc -fmodule-map-file=$(PROJECT_TEMP_ROOT)/GeneratedModuleMaps-$(PLATFORM_NAME)/RxCocoaRuntime.modulemap\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.github.groue.RxGRDBDemoTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/RxGRDBDemo.app/RxGRDBDemo\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t56E1F9891F8101EE00793BFA /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t56E1F98A1F8101EE00793BFA /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t56E1F98C1F8101EE00793BFA /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = AMD8W895CT;\n\t\t\t\tINFOPLIST_FILE = RxGRDBDemo/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.github.groue.RxGRDBDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t56E1F98D1F8101EE00793BFA /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = AMD8W895CT;\n\t\t\t\tINFOPLIST_FILE = RxGRDBDemo/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.github.groue.RxGRDBDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t565BD7BD22C3F84A00BB9B5A /* Build configuration list for PBXNativeTarget \"RxGRDBDemoTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t565BD7BE22C3F84A00BB9B5A /* Debug */,\n\t\t\t\t565BD7BF22C3F84A00BB9B5A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t56E1F9741F8101EE00793BFA /* Build configuration list for PBXProject \"RxGRDBDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t56E1F9891F8101EE00793BFA /* Debug */,\n\t\t\t\t56E1F98A1F8101EE00793BFA /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t56E1F98B1F8101EE00793BFA /* Build configuration list for PBXNativeTarget \"RxGRDBDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t56E1F98C1F8101EE00793BFA /* Debug */,\n\t\t\t\t56E1F98D1F8101EE00793BFA /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t56D6EA2D2438AB77000D55EF /* XCRemoteSwiftPackageReference \"RxSwift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/ReactiveX/RxSwift.git\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 6.0.0;\n\t\t\t};\n\t\t};\n\t\t56D6EA302438ABAE000D55EF /* XCRemoteSwiftPackageReference \"RxDataSources\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/RxSwiftCommunity/RxDataSources.git\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 5.0.0;\n\t\t\t};\n\t\t};\n\t\t56D6EA332438ABD7000D55EF /* XCRemoteSwiftPackageReference \"Action\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/RxSwiftCommunity/Action.git\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 4.0.1;\n\t\t\t};\n\t\t};\n\t\t56D6EA422438AF90000D55EF /* XCRemoteSwiftPackageReference \"GRDB.swift\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/groue/GRDB.swift.git\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 6.0.0;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t567CE94128CB747200A95C34 /* RxCocoa */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 56D6EA2D2438AB77000D55EF /* XCRemoteSwiftPackageReference \"RxSwift\" */;\n\t\t\tproductName = RxCocoa;\n\t\t};\n\t\t567E66CF2438A6F80091B5D8 /* RxGRDB */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = RxGRDB;\n\t\t};\n\t\t56D6EA2E2438AB77000D55EF /* RxSwift */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 56D6EA2D2438AB77000D55EF /* XCRemoteSwiftPackageReference \"RxSwift\" */;\n\t\t\tproductName = RxSwift;\n\t\t};\n\t\t56D6EA312438ABAE000D55EF /* RxDataSources */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 56D6EA302438ABAE000D55EF /* XCRemoteSwiftPackageReference \"RxDataSources\" */;\n\t\t\tproductName = RxDataSources;\n\t\t};\n\t\t56D6EA342438ABD7000D55EF /* Action */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 56D6EA332438ABD7000D55EF /* XCRemoteSwiftPackageReference \"Action\" */;\n\t\t\tproductName = Action;\n\t\t};\n\t\t56D6EA432438AF90000D55EF /* GRDB */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 56D6EA422438AF90000D55EF /* XCRemoteSwiftPackageReference \"GRDB.swift\" */;\n\t\t\tproductName = GRDB;\n\t\t};\n\t\t56E549F62438B4770060D2DC /* GRDB */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 56D6EA422438AF90000D55EF /* XCRemoteSwiftPackageReference \"GRDB.swift\" */;\n\t\t\tproductName = GRDB;\n\t\t};\n\t\t56E549F82438B49A0060D2DC /* RxSwift */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 56D6EA2D2438AB77000D55EF /* XCRemoteSwiftPackageReference \"RxSwift\" */;\n\t\t\tproductName = RxSwift;\n\t\t};\n\t\t56E549FA2438B4A40060D2DC /* RxBlocking */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 56D6EA2D2438AB77000D55EF /* XCRemoteSwiftPackageReference \"RxSwift\" */;\n\t\t\tproductName = RxBlocking;\n\t\t};\n\t\t56E549FC2438B5510060D2DC /* RxGRDB */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = RxGRDB;\n\t\t};\n\t\t56E549FE2438B5670060D2DC /* Action */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 56D6EA332438ABD7000D55EF /* XCRemoteSwiftPackageReference \"Action\" */;\n\t\t\tproductName = Action;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = 56E1F9711F8101EE00793BFA /* Project object */;\n}\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemo.xcodeproj/xcshareddata/xcschemes/RxGRDBDemo.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1230\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"56E1F9781F8101EE00793BFA\"\n               BuildableName = \"RxGRDBDemo.app\"\n               BlueprintName = \"RxGRDBDemo\"\n               ReferencedContainer = \"container:RxGRDBDemo.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"565BD7B522C3F84A00BB9B5A\"\n               BuildableName = \"RxGRDBDemoTests.xctest\"\n               BlueprintName = \"RxGRDBDemoTests\"\n               ReferencedContainer = \"container:RxGRDBDemo.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"56E1F9781F8101EE00793BFA\"\n            BuildableName = \"RxGRDBDemo.app\"\n            BlueprintName = \"RxGRDBDemo\"\n            ReferencedContainer = \"container:RxGRDBDemo.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"565BD7B522C3F84A00BB9B5A\"\n               BuildableName = \"RxGRDBDemoTests.xctest\"\n               BlueprintName = \"RxGRDBDemoTests\"\n               ReferencedContainer = \"container:RxGRDBDemo.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"56E1F9781F8101EE00793BFA\"\n            BuildableName = \"RxGRDBDemo.app\"\n            BlueprintName = \"RxGRDBDemo\"\n            ReferencedContainer = \"container:RxGRDBDemo.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"56E1F9781F8101EE00793BFA\"\n            BuildableName = \"RxGRDBDemo.app\"\n            BlueprintName = \"RxGRDBDemo\"\n            ReferencedContainer = \"container:RxGRDBDemo.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemoTests/AppDatabaseTests.swift",
    "content": "import XCTest\nimport GRDB\n\nclass AppDatabaseTests: XCTestCase {\n    \n    func testDatabaseSchemaContainsPlayerTable() throws {\n        let dbQueue = try DatabaseQueue()\n        try AppDatabase().setup(dbQueue)\n        try dbQueue.read { db in\n            try XCTAssert(db.tableExists(\"player\"))\n            let columns = try db.columns(in: \"player\")\n            let columnNames = Set(columns.map { $0.name })\n            XCTAssertEqual(columnNames, [\"id\", \"name\", \"score\"])\n        }\n    }\n}\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemoTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemoTests/PlayerTests.swift",
    "content": "import XCTest\nimport GRDB\n\nclass PlayerTests: XCTestCase {\n    \n    func testInsert() throws {\n        let dbQueue = try DatabaseQueue()\n        try AppDatabase().setup(dbQueue)\n        try dbQueue.write { db in\n            var player = Player(id: nil, name: \"Arthur\", score: 100)\n            try player.insert(db)\n            XCTAssertNotNil(player.id)\n        }\n    }\n    \n    func testRoundtrip() throws {\n        let dbQueue = try DatabaseQueue()\n        try AppDatabase().setup(dbQueue)\n        try dbQueue.write { db in\n            var insertedPlayer = Player(id: 1, name: \"Arthur\", score: 100)\n            try insertedPlayer.insert(db)\n            let fetchedPlayer = try Player.fetchOne(db, key: 1)\n            XCTAssertEqual(insertedPlayer, fetchedPlayer)\n        }\n    }\n    \n    func testOrderByScore() throws {\n        let dbQueue = try DatabaseQueue()\n        try AppDatabase().setup(dbQueue)\n        var player1 = Player(id: 1, name: \"Arthur\", score: 100)\n        var player2 = Player(id: 2, name: \"Barbara\", score: 200)\n        var player3 = Player(id: 3, name: \"Craig\", score: 150)\n        var player4 = Player(id: 4, name: \"David\", score: 150)\n        try dbQueue.write { db in\n            try player1.insert(db)\n            try player2.insert(db)\n            try player3.insert(db)\n            try player4.insert(db)\n        }\n        \n        let request = Player.all().orderByScore()\n        \n        try XCTAssertEqual(\n            dbQueue.read(request.fetchAll),\n            [player2, player3, player4, player1])\n        \n        try dbQueue.write { db in\n            _ = try player1.updateChanges(db) { $0.score = 300 }\n        }\n        \n        try XCTAssertEqual(\n            dbQueue.read(request.fetchAll),\n            [player1, player2, player3, player4])\n    }\n    \n    func testOrderByName() throws {\n        let dbQueue = try DatabaseQueue()\n        try AppDatabase().setup(dbQueue)\n        var player1 = Player(id: 1, name: \"Arthur\", score: 100)\n        var player2 = Player(id: 2, name: \"Barbara\", score: 200)\n        var player3 = Player(id: 3, name: \"Craig\", score: 150)\n        var player4 = Player(id: 4, name: \"David\", score: 150)\n        try dbQueue.write { db in\n            try player1.insert(db)\n            try player2.insert(db)\n            try player3.insert(db)\n            try player4.insert(db)\n        }\n        \n        let request = Player.all().orderByName()\n        \n        try XCTAssertEqual(\n            dbQueue.read(request.fetchAll),\n            [player1, player2, player3, player4])\n        \n        try dbQueue.write { db in\n            _ = try player1.updateChanges(db) { $0.name = \"Craig\" }\n        }\n        \n        try XCTAssertEqual(\n            dbQueue.read(request.fetchAll),\n            [player2, player3, player1, player4])\n    }\n}\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemoTests/PlayersTests.swift",
    "content": "import GRDB\nimport RxBlocking\nimport RxSwift\nimport XCTest\n\nclass PlayersTests: XCTestCase {\n    \n    private func makeDatabase() throws -> DatabaseQueue {\n        // Players needs a database.\n        // Setup an in-memory database, for fast access.\n        let database = try DatabaseQueue()\n        try AppDatabase().setup(database)\n        return database\n    }\n    \n    func testPopulateIfEmptyFromEmptyDatabase() throws {\n        let database = try makeDatabase()\n        let players = Players(database: database)\n        \n        try XCTAssertEqual(database.read(Player.fetchCount), 0)\n        try XCTAssertTrue(players.populateIfEmpty())\n        try XCTAssertGreaterThan(database.read(Player.fetchCount), 0)\n    }\n    \n    func testPopulateIfEmptyFromNonEmptyDatabase() throws {\n        let database = try makeDatabase()\n        let players = Players(database: database)\n        \n        var player = Player(id: 1, name: \"Arthur\", score: 100)\n        try database.write { db in\n            try player.insert(db)\n        }\n        \n        try XCTAssertFalse(players.populateIfEmpty())\n        try XCTAssertEqual(database.read(Player.fetchAll), [player])\n    }\n    \n    func testDeleteAll() throws {\n        let database = try makeDatabase()\n        let players = Players(database: database)\n        \n        try database.write { db in\n            var player = Player(id: 1, name: \"Arthur\", score: 100)\n            try player.insert(db)\n        }\n        \n        _ = players.deleteAll().toBlocking().materialize()\n        try XCTAssertEqual(database.read(Player.fetchCount), 0)\n    }\n    \n    func testDeleteOne() throws {\n        let database = try makeDatabase()\n        let players = Players(database: database)\n        \n        var player1 = Player(id: 1, name: \"Arthur\", score: 100)\n        var player2 = Player(id: 2, name: \"Barbara\", score: 200)\n        try database.write { db in\n            try player1.insert(db)\n            try player2.insert(db)\n        }\n        \n        _ = players.deleteOne(player1).toBlocking().materialize()\n        try XCTAssertEqual(database.read(Player.fetchAll), [player2])\n    }\n    \n    func testRefreshPopulatesEmptyDatabase() throws {\n        let database = try makeDatabase()\n        let players = Players(database: database)\n        \n        try XCTAssertEqual(database.read(Player.fetchCount), 0)\n        _ = players.refresh().toBlocking().materialize()\n        try XCTAssertGreaterThan(database.read(Player.fetchCount), 0)\n    }\n    \n    func testPlayersOrderedByName() throws {\n        let database = try makeDatabase()\n        let players = Players(database: database)\n        \n        let disposeBag = DisposeBag()\n        let testSubject = ReplaySubject<[Player]>.createUnbounded()\n        players\n            .playersOrderedByName()\n            .subscribe(testSubject)\n            .disposed(by: disposeBag)\n        \n        var player1 = Player(id: 1, name: \"Barbara\", score: 100)\n        var player2 = Player(id: 2, name: \"Arthur\", score: 300)\n        var player3 = Player(id: 3, name: \"Craig\", score: 200)\n        try database.write { db in\n            try player1.insert(db)\n            try player2.insert(db)\n        }\n        try database.write { db in\n            try player2.delete(db)\n            try player3.insert(db)\n        }\n        \n        let expectedElements: [[Player]] = [\n            [],\n            [player2, player1],\n            [player1, player3],\n        ]\n        try XCTAssertEqual(\n            testSubject\n                .take(expectedElements.count)\n                .toBlocking()\n                .toArray(),\n            expectedElements)\n    }\n    \n    func testPlayersOrderedByScore() throws {\n        let database = try makeDatabase()\n        let players = Players(database: database)\n        \n        let disposeBag = DisposeBag()\n        let testSubject = ReplaySubject<[Player]>.createUnbounded()\n        players\n            .playersOrderedByScore()\n            .subscribe(testSubject)\n            .disposed(by: disposeBag)\n        \n        var player1 = Player(id: 1, name: \"Barbara\", score: 100)\n        var player2 = Player(id: 2, name: \"Arthur\", score: 300)\n        var player3 = Player(id: 3, name: \"Craig\", score: 200)\n        try database.write { db in\n            try player1.insert(db)\n            try player2.insert(db)\n        }\n        try database.write { db in\n            try player2.delete(db)\n            try player3.insert(db)\n        }\n        \n        let expectedElements: [[Player]] = [\n            [],\n            [player2, player1],\n            [player3, player1],\n        ]\n        try XCTAssertEqual(\n            testSubject\n                .take(expectedElements.count)\n                .toBlocking()\n                .toArray(),\n            expectedElements)\n    }\n}\n"
  },
  {
    "path": "Documentation/RxGRDBDemo/RxGRDBDemoTests/PlayersViewModelTests.swift",
    "content": "import Action\nimport GRDB\nimport RxBlocking\nimport RxSwift\nimport XCTest\n\nclass PlayersViewModelTests: XCTestCase {\n    override func setUp() {\n        // PlayerViewModel needs a Current World.\n        // Setup one with an in-memory database, for fast access.\n        let dbQueue = try! DatabaseQueue()\n        try! AppDatabase().setup(dbQueue)\n        Current = World(database: { dbQueue })\n    }\n    \n    func testInitialStateFromEmptyDatabase() throws {\n        let viewModel = PlayersViewModel()\n        let orderingButtonTitle = try viewModel.orderingButtonTitle.take(1).toBlocking().single()\n        let players = try viewModel.players.take(1).toBlocking().single()\n        XCTAssertNil(orderingButtonTitle)\n        XCTAssert(players.isEmpty)\n    }\n    \n    func testInitialStateFromNonEmptyDatabase() throws {\n        try Current.players().populateIfEmpty()\n        let viewModel = PlayersViewModel()\n        let orderingButtonTitle = try viewModel.orderingButtonTitle.take(1).toBlocking().single()\n        let players = try viewModel.players.take(1).toBlocking().single()\n        XCTAssertEqual(orderingButtonTitle, \"Score ⬇︎\")\n        XCTAssert(!players.isEmpty)\n    }\n    \n    func testToggleOrdering() throws {\n        try Current.players().populateIfEmpty()\n        let viewModel = PlayersViewModel()\n        _ = viewModel.toggleOrdering.execute().toBlocking().materialize()\n        let orderingButtonTitle = try viewModel.orderingButtonTitle.take(1).toBlocking().single()\n        XCTAssertEqual(orderingButtonTitle, \"Name ⬆︎\")\n    }\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (C) 2018 RxSwiftCommunity\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "# Rules\n# =====\n#\n# make test - Run all tests but performance tests\n# make distclean - Restore repository to a pristine state\n\ndefault: test\n\n\n# Configuration\n# =============\n\nGIT := $(shell command -v git)\nPOD := $(shell command -v pod)\nXCRUN := $(shell command -v xcrun)\nSWIFT = $(shell $(XCRUN) --find swift 2> /dev/null)\n\n# Used to determine if xcpretty is available\nXCPRETTY_PATH := $(shell command -v xcpretty 2> /dev/null)\n\n\n# Tests\n# =====\n\n# If xcpretty is available, use it for xcodebuild output\nXCPRETTY = \nifdef XCPRETTY_PATH\n  XCPRETTY = | xcpretty -c\n  \n  # On Travis-CI, use xcpretty-travis-formatter\n  ifeq ($(TRAVIS),true)\n    XCPRETTY += -f `xcpretty-travis-formatter`\n  endif\nendif\n\ntest: test_SPM\n\ntest_SPM:\n\t$(SWIFT) package clean\n\t$(SWIFT) build\n\t$(SWIFT) build -c release\n\tset -o pipefail && $(SWIFT) test $(XCPRETTY)\n\n# Cleanup\n# =======\n\ndistclean:\n\t$(GIT) reset --hard\n\t$(GIT) clean -dffx .\n\n.PHONY: distclean test\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:6.0\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"RxGRDB\",\n    platforms: [\n        .iOS(.v13),\n        .macOS(.v10_15),\n        .tvOS(.v13),\n        .watchOS(.v7),\n    ],\n    products: [\n        .library(name: \"RxGRDB\", targets: [\"RxGRDB\"]),\n    ],\n    dependencies: [\n        .package(url: \"https://github.com/groue/GRDB.swift.git\", .upToNextMajor(from: \"7.1.0\")),\n        .package(url: \"https://github.com/ReactiveX/RxSwift.git\", .upToNextMajor(from: \"6.0.0\"))\n    ],\n    targets: [\n        .target(\n            name: \"RxGRDB\",\n            dependencies: [\n                .product(name: \"GRDB\", package: \"GRDB.swift\"),\n                .product(name: \"RxSwift\", package: \"RxSwift\"),\n            ]),\n        .testTarget(\n            name: \"RxGRDBTests\",\n            dependencies: [\n                \"RxGRDB\",\n                .product(name: \"GRDB\", package: \"GRDB.swift\"),\n                .product(name: \"RxBlocking\", package: \"RxSwift\"),\n            ])\n    ],\n    swiftLanguageModes: [.v5]\n)\n"
  },
  {
    "path": "README.md",
    "content": "RxGRDB [![Swift 6](https://img.shields.io/badge/swift-6-orange.svg?style=flat)](https://developer.apple.com/swift/)  [![License](https://img.shields.io/github/license/RxSwiftCommunity/RxGRDB.svg?maxAge=2592000)](/LICENSE)\n======\n\n### A set of extensions for [SQLite], [GRDB.swift], and [RxSwift]\n\n**Latest release**: September 28, 2025 • [version 4.0.1](https://github.com/RxSwiftCommunity/RxGRDB/tree/v4.0.1) • [Release Notes]\n\n**Requirements**: iOS 11.0+ / macOS 10.13+ / tvOS 11.0+ / watchOS 4.0+ • Swift 6+ / Xcode 16+\n\n---\n\n## Usage\n\nTo connect to the database, please refer to [GRDB](https://github.com/groue/GRDB.swift), the database library that supports RxGRDB.\n\n<details>\n  <summary><strong>Asynchronously read from the database</strong></summary>\n\nThis observable reads a single value and delivers it.\n\n```swift\n// Single<[Player]>\nlet players = dbQueue.rx.read { db in\n    try Player.fetchAll(db)\n}\n\nplayers.subscribe(\n    onSuccess: { (players: [Player]) in\n        print(\"Players: \\(players)\")\n    },\n    onError: { error in ... })\n```\n\n</details>\n\n<details>\n  <summary><strong>Asynchronously write in the database</strong></summary>\n\nThis observable completes after the database has been updated.\n\n```swift\n// Single<Void>\nlet write = dbQueue.rx.write { db in \n    try Player(...).insert(db)\n}\n\nwrite.subscribe(\n    onSuccess: { _ in\n        print(\"Updates completed\")\n    },\n    onError: { error in ... })\n\n// Single<Int>\nlet newPlayerCount = dbQueue.rx.write { db -> Int in\n    try Player(...).insert(db)\n    return try Player.fetchCount(db)\n}\n\nnewPlayerCount.subscribe(\n    onSuccess: { (playerCount: Int) in\n        print(\"New players count: \\(playerCount)\")\n    },\n    onError: { error in ... })\n```\n\n</details>\n\n<details>\n  <summary><strong>Observe changes in database values</strong></summary>\n\nThis observable delivers fresh values whenever the database changes:\n\n```swift\n// Observable<[Player]>\nlet observable = ValueObservation\n    .tracking { db in try Player.fetchAll(db) }\n    .rx.observe(in: dbQueue)\n\nobservable.subscribe(\n    onNext: { (players: [Player]) in\n        print(\"Fresh players: \\(players)\")\n    },\n    onError: { error in ... })\n\n// Observable<Int?>\nlet observable = ValueObservation\n    .tracking { db in try Int.fetchOne(db, sql: \"SELECT MAX(score) FROM player\") }\n    .rx.observe(in: dbQueue)\n\nobservable.subscribe(\n    onNext: { (maxScore: Int?) in\n        print(\"Fresh maximum score: \\(maxScore)\")\n    },\n    onError: { error in ... })\n```\n\n</details>\n\n<details>\n  <summary><strong>Observe database transactions</strong></summary>\n\nThis observable delivers database connections whenever a database transaction has impacted an observed region:\n\n```swift\n// Observable<Database>\nlet observable = DatabaseRegionObservation\n    .tracking(Player.all())\n    .rx.changes(in: dbQueue)\n\nobservable.subscribe(\n    onNext: { (db: Database) in\n        print(\"Exclusive write access to the database after players have been impacted\")\n    },\n    onError: { error in ... })\n\n// Observable<Database>\nlet observable = DatabaseRegionObservation\n    .tracking(SQLRequest<Int>(sql: \"SELECT MAX(score) FROM player\"))\n    .rx.changes(in: dbQueue)\n\nobservable.subscribe(\n    onNext: { (db: Database) in\n        print(\"Exclusive write access to the database after maximum score has been impacted\")\n    },\n    onError: { error in ... })\n```\n\n</details>\n\nDocumentation\n=============\n\n- [Installation]\n- [Demo Application]\n- [Asynchronous Database Access]\n- [Database Observation]\n\n## Installation\n\nTo use RxGRDB with the [Swift Package Manager], add a dependency to your `Package.swift` file:\n\n```swift\nlet package = Package(\n    dependencies: [\n        .package(url: \"https://github.com/RxSwiftCommunity/RxGRDB.git\", ...)\n    ]\n)\n```\n\nTo use RxGRDB with [CocoaPods](http://cocoapods.org/), specify in your `Podfile`:\n\n```ruby\n# Pick only one\npod 'RxGRDB'\npod 'RxGRDB/SQLCipher'\n```\n\n\n# Asynchronous Database Access\n\nRxGRDB provide observables that perform asynchronous database accesses.\n\n- [`rx.read(observeOn:value:)`]\n- [`rx.write(observeOn:updates:)`]\n- [`rx.write(observeOn:updates:thenRead:)`]\n\n\n#### `DatabaseReader.rx.read(observeOn:value:)`\n\nThis methods returns a [Single] that completes after database values have been asynchronously fetched.\n\n```swift\n// Single<[Player]>\nlet players = dbQueue.rx.read { db in\n    try Player.fetchAll(db)\n}\n```\n\nAny attempt at modifying the database completes subscriptions with an error.\n\nWhen you use a [database queue] or a [database snapshot], the read has to wait for any eventual concurrent database access performed by this queue or snapshot to complete.\n\nWhen you use a [database pool], reads are generally non-blocking, unless the maximum number of concurrent reads has been reached. In this case, a read has to wait for another read to complete. That maximum number can be [configured].\n\nThis observable can be subscribed from any thread. A new database access starts on every subscription.\n\nThe fetched value is published on the main queue, unless you provide a specific scheduler to the `observeOn` argument.\n\n\n#### `DatabaseWriter.rx.write(observeOn:updates:)`\n\nThis method returns a [Single] that completes after database updates have been successfully executed inside a database transaction.\n\n```swift\n// Single<Void>\nlet write = dbQueue.rx.write { db in\n    try Player(...).insert(db)\n}\n\n// Single<Int>\nlet newPlayerCount = dbQueue.rx.write { db -> Int in\n    try Player(...).insert(db)\n    return try Player.fetchCount(db)\n}\n```\n\nThis observable can be subscribed from any thread. A new database access starts on every subscription.\n\nIt completes on the main queue, unless you provide a specific [scheduler] to the `observeOn` argument.\n\nYou can ignore its value and turn it into a [Completable] with the `asCompletable` operator:\n\n```swift\n// Completable\nlet write = dbQueue.rx\n    .write { db in try Player(...).insert(db) }\n    .asCompletable()\n```\n\nWhen you use a [database pool], and your app executes some database updates followed by some slow fetches, you may profit from optimized scheduling with [`rx.write(observeOn:updates:thenRead:)`]. See below.\n\n\n#### `DatabaseWriter.rx.write(observeOn:updates:thenRead:)`\n\nThis method returns a [Single] that completes after database updates have been successfully executed inside a database transaction, and values have been subsequently fetched:\n\n```swift\n// Single<Int>\nlet newPlayerCount = dbQueue.rx.write(\n    updates: { db in try Player(...).insert(db) }\n    thenRead: { db, _ in try Player.fetchCount(db) })\n}\n```\n\nIt publishes exactly the same values as [`rx.write(observeOn:updates:)`]:\n\n```swift\n// Single<Int>\nlet newPlayerCount = dbQueue.rx.write { db -> Int in\n    try Player(...).insert(db)\n    return try Player.fetchCount(db)\n}\n```\n\nThe difference is that the last fetches are performed in the `thenRead` function. This function accepts two arguments: a readonly database connection, and the result of the `updates` function. This allows you to pass information from a function to the other (it is ignored in the sample code above).\n\nWhen you use a [database pool], this method applies a scheduling optimization: the `thenRead` function sees the database in the state left by the `updates` function, and yet does not block any concurrent writes. This can reduce database write contention. See [Advanced DatabasePool](https://github.com/groue/GRDB.swift/blob/master/README.md#advanced-databasepool) for more information.\n\nWhen you use a [database queue], the results are guaranteed to be identical, but no scheduling optimization is applied.\n\nThis observable can be subscribed from any thread. A new database access starts on every subscription.\n\nIt completes on the main queue, unless you provide a specific [scheduler] to the `observeOn` argument.\n\n\n# Database Observation\n\nDatabase Observation observables are based on GRDB's [ValueObservation] and [DatabaseRegionObservation]. Please refer to their documentation for more information. If your application needs change notifications that are not built in RxGRDB, check the general [Database Changes Observation] chapter.\n\n- [`ValueObservation.rx.observe(in:scheduling:)`]\n- [`DatabaseRegionObservation.rx.changes(in:)`]\n\n\n#### `ValueObservation.rx.observe(in:scheduling:)`\n\nGRDB's [ValueObservation] tracks changes in database values. You can turn it into an RxSwift observable:\n\n```swift\nlet observation = ValueObservation.tracking { db in\n    try Player.fetchAll(db)\n}\n\n// Observable<[Player]>\nlet observable = observation.rx.observe(in: dbQueue)\n```\n\nThis observable has the same behavior as ValueObservation:\n\n- It notifies an initial value before the eventual changes.\n- It may coalesce subsequent changes into a single notification.\n- It may notify consecutive identical values. You can filter out the undesired duplicates with the `distinctUntilChanged()` RxSwift operator, but we suggest you have a look at the [removeDuplicates()](https://github.com/groue/GRDB.swift/blob/master/README.md#valueobservationremoveduplicates) GRDB operator also.\n- It stops emitting any value after the database connection is closed. But it never completes.\n- By default, it notifies the initial value, as well as eventual changes and errors, on the main thread, asynchronously.\n    \n    This can be configured with the `scheduling` argument. It does not accept an RxSwift scheduler, but a [GRDB scheduler](https://github.com/groue/GRDB.swift/blob/master/README.md#valueobservation-scheduling).\n    \n    For example, the `.immediate` scheduler makes sure the initial value is notified immediately when the observable is subscribed. It can help your application update the user interface without having to wait for any asynchronous notifications:\n    \n    ```swift\n    // Immediate notification of the initial value\n    let disposable = observation.rx\n        .observe(\n            in: dbQueue,\n            scheduling: .immediate) // <-\n        .subscribe(\n            onNext: { players: [Player] in print(\"fresh players: \\(players)\") },\n            onError: { error in ... })\n    // <- here \"fresh players\" is already printed.\n    ```\n    \n    Note that the `.immediate` scheduler requires that the observable is subscribed from the main thread. It raises a fatal error otherwise.\n\nSee [ValueObservation Scheduling](https://github.com/groue/GRDB.swift/blob/master/README.md#valueobservation-scheduling) for more information.\n\n:warning: **ValueObservation and Data Consistency**\n\nWhen you compose ValueObservation observables together with the [combineLatest](http://reactivex.io/documentation/operators/combinelatest.html) operator, you lose all guarantees of [data consistency](https://en.wikipedia.org/wiki/Consistency_(database_systems)).\n\nInstead, compose requests together into **one single** ValueObservation, as below:\n\n```swift\n// DATA CONSISTENCY GUARANTEED\nlet hallOfFameObservable = ValueObservation\n    .tracking { db -> HallOfFame in\n        let playerCount = try Player.fetchCount(db)\n        let bestPlayers = try Player.limit(10).orderedByScore().fetchAll(db)\n        return HallOfFame(playerCount:playerCount, bestPlayers:bestPlayers)\n    }\n    .rx.observe(in: dbQueue)\n```\n\nSee [ValueObservation] for more information.\n\n\n#### `DatabaseRegionObservation.rx.changes(in:)`\n\nGRDB's [DatabaseRegionObservation] notifies all transactions that impact a tracked database region. You can turn it into an RxSwift observable:\n\n```swift\nlet request = Player.all()\nlet observation = DatabaseRegionObservation.tracking(request)\n\n// Observable<Database>\nlet observable = observation.rx.changes(in: dbQueue)\n```\n\nThis observable can be created and subscribed from any thread. It delivers database connections in a \"protected dispatch queue\", serialized with all database updates. It only completes when a database error happens.\n\n```swift\nlet request = Player.all()\nlet disposable = DatabaseRegionObservation\n    .tracking(request)\n    .rx.changes(in: dbQueue)\n    .subscribe(\n        onNext: { (db: Database) in\n            print(\"Players have changed.\")\n        },\n        onError: { error in ... })\n\ntry dbQueue.write { db in\n    try Player(name: \"Arthur\").insert(db)\n    try Player(name: \"Barbara\").insert(db)\n} \n// Prints \"Players have changed.\"\n\ntry dbQueue.write { db in\n    try Player.deleteAll(db)\n}\n// Prints \"Players have changed.\"\n```\n\nSee [DatabaseRegionObservation] for more information.\n\n\n[Asynchronous Database Access]: #asynchronous-database-access\n[RxSwift]: https://github.com/ReactiveX/RxSwift\n[Database Changes Observation]: https://github.com/groue/GRDB.swift/blob/master/README.md#database-changes-observation\n[Database Observation]: #database-observation\n[DatabaseRegionObservation]: https://github.com/groue/GRDB.swift/blob/master/README.md#databaseregionobservation\n[Demo Application]: Documentation/RxGRDBDemo/README.md\n[GRDB.swift]: https://github.com/groue/GRDB.swift\n[Installation]: #installation\n[Release Notes]: CHANGELOG.md\n[SQLite]: http://sqlite.org\n[Swift Package Manager]: https://swift.org/package-manager/\n[ValueObservation]: https://github.com/groue/GRDB.swift/blob/master/README.md#valueobservation\n[`DatabaseRegionObservation.rx.changes(in:)`]: #databaseregionobservationrxchangesin\n[`ValueObservation.rx.observe(in:scheduling:)`]: #valueobservationrxobserveinscheduling\n[`rx.read(observeOn:value:)`]: #databasereaderrxreadobserveonvalue\n[`rx.write(observeOn:updates:)`]: #databasewriterrxwriteobserveonupdates\n[`rx.write(observeOn:updates:thenRead:)`]: #databasewriterrxwriteobserveonupdatesthenread\n[configured]: https://github.com/groue/GRDB.swift/blob/master/README.md#databasepool-configuration\n[database pool]: https://github.com/groue/GRDB.swift/blob/master/README.md#database-pools\n[database queue]: https://github.com/groue/GRDB.swift/blob/master/README.md#database-queues\n[database snapshot]: https://github.com/groue/GRDB.swift/blob/master/README.md#database-snapshots\n[scheduler]: https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Schedulers.md\n[Single]: https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Traits.md#single\n[Completable]: https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Traits.md#completable\n"
  },
  {
    "path": "Sources/RxGRDB/DatabaseReader+Rx.swift",
    "content": "import GRDB\nimport RxSwift\n\n/// We want the `rx` joiner on DatabaseReader.\n/// Normally we'd use ReactiveCompatible. But ReactiveCompatible is unable to\n/// define `rx` on existentials as well:\n///\n///     let reader: DatabaseReader\n///     reader.rx...\n///\n/// :nodoc:\nextension DatabaseReader {\n    /// Reactive extensions.\n    public var rx: Reactive<AnyDatabaseReader> { Reactive(AnyDatabaseReader(self)) }\n}\n\nextension Reactive where Base: DatabaseReader {\n    /// Returns a Single that asynchronously emits the fetched value.\n    ///\n    ///     let dbQueue = try DatabaseQueue()\n    ///     let players: Single<[Player]> = dbQueue.rx.read { db in\n    ///         try Player.fetchAll(db)\n    ///     }\n    ///\n    /// By default, returned values are emitted on the main dispatch queue. If\n    /// you give a *scheduler*, values are emitted on that scheduler.\n    ///\n    /// - parameter value: A closure which accesses the database.\n    /// - parameter scheduler: The scheduler on which the single completes.\n    ///   Defaults to MainScheduler.instance.\n    public func read<T>(\n        observeOn scheduler: ImmediateSchedulerType = MainScheduler.instance,\n        value: @escaping (Database) throws -> T)\n    -> Single<T>\n    {\n        Single\n            .create(subscribe: { observer in\n                self.base.asyncRead { db in\n                    do {\n                        try observer(.success(value(db.get())))\n                    } catch {\n                        observer(.failure(error))\n                    }\n                }\n                return Disposables.create { }\n            })\n            .observe(on: scheduler)\n    }\n}\n"
  },
  {
    "path": "Sources/RxGRDB/DatabaseRegionObservation+Rx.swift",
    "content": "import GRDB\nimport RxSwift\n\nextension DatabaseRegionObservation {\n    /// Reactive extensions.\n    public var rx: GRDBReactive<Self> { GRDBReactive(self) }\n}\n\nextension GRDBReactive where Base == DatabaseRegionObservation {\n    /// Returns an Observable that emits the same elements as\n    /// a DatabaseRegionObservation.\n    ///\n    /// All elements are emitted in a protected database dispatch queue,\n    /// serialized with all database updates. If you set *startImmediately* to\n    /// true (the default value), the first element is emitted synchronously\n    /// upon subscription. See [GRDB Concurrency Guide](https://github.com/groue/GRDB.swift/blob/master/README.md#concurrency)\n    /// for more information.\n    ///\n    ///     let dbQueue = try DatabaseQueue()\n    ///     try dbQueue.write { db in\n    ///         try db.create(table: \"player\") { t in\n    ///             t.column(\"id\", .integer).primaryKey()\n    ///             t.column(\"name\", .text)\n    ///         }\n    ///     }\n    ///\n    ///     struct Player: Encodable, PersistableRecord {\n    ///         var id: Int64\n    ///         var name: String\n    ///     }\n    ///\n    ///     let request = Player.all()\n    ///     let observation = DatabaseRegionObservation(tracking: request)\n    ///     observation.rx\n    ///         .changes(in: dbQueue)\n    ///         .subscribe(onNext: { db in\n    ///             let count = try! Player.fetchCount(db)\n    ///             print(\"Number of players: \\(count)\")\n    ///         })\n    ///     // Prints \"Number of players: 0\"\n    ///\n    ///     try dbQueue.write { db in\n    ///         try Player(id: 1, name: \"Arthur\").insert(db)\n    ///         try Player(id: 2, name: \"Barbara\").insert(db)\n    ///     }\n    ///     // Prints \"Number of players: 2\"\n    ///\n    ///     try dbQueue.inDatabase { db in\n    ///         try Player(id: 3, name: \"Craig\").insert(db)\n    ///         // Prints \"Number of players: 3\"\n    ///         try Player(id: 4, name: \"David\").insert(db)\n    ///         // Prints \"Number of players: 4\"\n    ///     }\n    ///\n    /// - parameter writer: A DatabaseWriter (DatabaseQueue or DatabasePool).\n    public func changes(in writer: DatabaseWriter) -> Observable<Database> {\n        Observable.create { observer in\n            let cancellable = self.base.start(\n                in: writer,\n                onError: observer.onError,\n                onChange: observer.onNext)\n            return Disposables.create(with: cancellable.cancel)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/RxGRDB/DatabaseWriter+Rx.swift",
    "content": "import GRDB\nimport RxSwift\n\n/// We want the `rx` joiner on DatabaseWriter.\n/// Normally we'd use ReactiveCompatible. But ReactiveCompatible is unable to\n/// define `rx` on existentials as well:\n///\n///     let writer: DatabaseWriter\n///     writer.rx...\n///\n/// :nodoc:\nextension DatabaseWriter {\n    /// Reactive extensions.\n    public var rx: Reactive<AnyDatabaseWriter> {\n        Reactive(AnyDatabaseWriter(self))\n    }\n}\n\nextension Reactive where Base: DatabaseWriter {\n    /// Returns a Single that asynchronously writes into the database.\n    ///\n    ///     let newPlayerCount: Single<Int> = dbQueue.rx.write { db in\n    ///         try Player(...).insert(db)\n    ///         return try Player.fetchCount(db)\n    ///     }\n    ///\n    /// By default, the single completes on the main dispatch queue. If\n    /// you give a *scheduler*, is completes on that scheduler.\n    ///\n    /// - parameter scheduler: The scheduler on which the observable completes.\n    ///   Defaults to MainScheduler.instance.\n    /// - parameter updates: A closure which writes in the database.\n    public func write<T>(\n        observeOn scheduler: ImmediateSchedulerType = MainScheduler.instance,\n        updates: @escaping @Sendable (Database) throws -> T)\n    -> Single<T>\n    {\n        Single\n            .create(subscribe: { observer in\n                self.base.asyncWrite(updates, completion: { _, result in\n                    switch result {\n                    case let .success(value):\n                        observer(.success(value))\n                    case let .failure(error):\n                        observer(.failure(error))\n                    }\n                })\n                return Disposables.create()\n            })\n            // We don't want users to process emitted values on a\n            // database dispatch queue.\n            .observe(on: scheduler)\n    }\n    \n    /// Returns a Single that asynchronously writes into the database.\n    ///\n    ///     let newPlayerCount: Single<Int> = dbQueue.rx.write(\n    ///         updates: { db in try Player(...).insert(db) },\n    ///         thenRead: { db, _ in try Player.fetchCount(db) })\n    ///\n    /// By default, the single completes on the main dispatch queue. If\n    /// you give a *scheduler*, is completes on that scheduler.\n    ///\n    /// - parameter scheduler: The scheduler on which the observable completes.\n    ///   Defaults to MainScheduler.instance.\n    /// - parameter updates: A closure which writes in the database.\n    /// - parameter value: A closure which reads from the database.\n    public func write<T, U>(\n        observeOn scheduler: ImmediateSchedulerType = MainScheduler.instance,\n        updates: @escaping @Sendable (Database) throws -> T,\n        thenRead value: @escaping @Sendable (Database, T) throws -> U)\n    -> Single<U>\n    {\n        Single\n            .create(subscribe: { observer in\n                self.base.asyncWriteWithoutTransaction { db in\n                    var updatesValue: T?\n                    do {\n                        try db.inTransaction {\n                            updatesValue = try updates(db)\n                            return .commit\n                        }\n                    } catch {\n                        observer(.failure(error))\n                        return\n                    }\n                    \n                    // Non-mutable copy so that compiler does not raise any warning.\n                    let updatesValue2 = updatesValue\n                    self.base.spawnConcurrentRead { dbResult in\n                        do {\n                            try observer(.success(value(dbResult.get(), updatesValue2!)))\n                        } catch {\n                            observer(.failure(error))\n                        }\n                    }\n                }\n                return Disposables.create()\n            })\n            // We don't want users to process emitted values on a\n            // database dispatch queue.\n            .observe(on: scheduler)\n    }\n}\n"
  },
  {
    "path": "Sources/RxGRDB/GRDBReactive.swift",
    "content": "// Workaround https://github.com/ReactiveX/RxSwift/issues/2270\n/// :nodoc:\npublic struct GRDBReactive<Base> {\n    /// Base object to extend.\n    let base: Base\n    \n    /// Creates extensions with base object.\n    ///\n    /// - parameter base: Base object.\n    init(_ base: Base) {\n        self.base = base\n    }\n}\n"
  },
  {
    "path": "Sources/RxGRDB/ValueObservation+Rx.swift",
    "content": "import Dispatch\nimport GRDB\nimport RxSwift\n\nextension ValueObservation {\n    /// Reactive extensions.\n    public var rx: GRDBReactive<Self> { GRDBReactive(self) }\n}\n\n/// :nodoc:\npublic protocol _ValueObservationProtocol {\n    associatedtype Reducer: _ValueReducer\n    func _start(\n        in reader: GRDB.DatabaseReader,\n        scheduling scheduler: GRDB.ValueObservationScheduler,\n        onError: @escaping (Error) -> Void,\n        onChange: @escaping (Reducer.Value) -> Void)\n    -> GRDB.DatabaseCancellable\n}\n\n/// :nodoc:\nextension ValueObservation: _ValueObservationProtocol where Reducer: ValueReducer {\n    public func _start(in reader: GRDB.DatabaseReader, scheduling scheduler: GRDB.ValueObservationScheduler, onError: @escaping (Error) -> Void, onChange: @escaping (Reducer.Value) -> Void) -> GRDB.DatabaseCancellable {\n        start(in: reader, scheduling: scheduler, onError: onError, onChange: onChange)\n    }\n}\n\nextension GRDBReactive where Base: _ValueObservationProtocol {\n    /// Creates an Observable which tracks changes in database values.\n    ///\n    /// For example:\n    ///\n    ///     let observation = ValueObservation.tracking { db in\n    ///         try Player.fetchAll(db)\n    ///     }\n    ///     let disposable = observation.rx\n    ///         .observe(in: dbQueue)\n    ///         .subscribe(\n    ///             onNext: { players: [Player] in\n    ///                 print(\"fresh players: \\(players)\")\n    ///             },\n    ///             onError: { error in ... })\n    ///\n    /// By default, fresh values are dispatched asynchronously on the\n    /// main queue. You can change this behavior by by providing a scheduler.\n    ///\n    /// For example, `.immediate` notifies all values on the main queue as well,\n    /// and the first one is immediately notified when the observable\n    /// is subscribed:\n    ///\n    ///     // on the main queue\n    ///     observation.rx\n    ///         .observe(\n    ///             in: dbQueue,\n    ///             scheduling: .immediate) // <-\n    ///         .subscribe(onNext: { (players: [Player]) in\n    ///             // on the main queue\n    ///             print(\"Fresh players: \\(players)\")\n    ///         })\n    ///     // <- here \"Fresh players\" has been printed\n    ///\n    /// Note that the `.immediate` scheduler requires that the observable is\n    /// subscribed from the main thread. It raises a fatal error otherwise.\n    ///\n    /// - parameter reader: A DatabaseReader (DatabaseQueue or DatabasePool).\n    ///   are emitted.\n    /// - parameter scheduler: A Scheduler. By default, fresh values are\n    ///   dispatched asynchronously on the main queue.\n    /// - returns: An Observable of fresh values.\n    public func observe(\n        in reader: DatabaseReader,\n        scheduling scheduler: ValueObservationScheduler = .async(onQueue: .main))\n    -> Observable<Base.Reducer.Value>\n    {\n        Observable.create { observer in\n            let cancellable = self.base._start(\n                in: reader,\n                scheduling: scheduler,\n                onError: observer.onError,\n                onChange: observer.onNext)\n            return Disposables.create(with: cancellable.cancel)\n        }\n    }\n}\n"
  },
  {
    "path": "TODO.md",
    "content": "\n"
  },
  {
    "path": "Tests/RxGRDBTests/DatabaseReaderReadTests.swift",
    "content": "import GRDB\nimport RxBlocking\nimport RxGRDB\nimport RxSwift\nimport XCTest\n\nprivate struct Player: Codable, FetchableRecord, PersistableRecord {\n    var id: Int64\n    var name: String\n    var score: Int?\n    \n    static func createTable(_ db: Database) throws {\n        try db.create(table: \"player\") { t in\n            t.autoIncrementedPrimaryKey(\"id\")\n            t.column(\"name\", .text).notNull()\n            t.column(\"score\", .integer)\n        }\n    }\n}\n\nclass DatabaseReaderReadTests : XCTestCase {\n    func testRxJoiner() {\n        // Make sure `rx` joiner is available in various contexts\n        func f1(_ reader: DatabasePool) {\n            _ = reader.rx.read(value: { db in })\n        }\n        func f2(_ reader: DatabaseQueue) {\n            _ = reader.rx.read(value: { db in })\n        }\n        func f3(_ reader: DatabaseSnapshot) {\n            _ = reader.rx.read(value: { db in })\n        }\n        func f4<Reader: DatabaseReader>(_ reader: Reader) {\n            _ = reader.rx.read(value: { db in })\n        }\n        func f5(_ reader: DatabaseReader) {\n            _ = reader.rx.read(value: { db in })\n        }\n    }\n    \n    // MARK: -\n    \n    func testReadObservable() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(reader: DatabaseReader) throws {\n            let single = reader.rx.read(value: { db in\n                try Player.fetchCount(db)\n            })\n            let value = try single.toBlocking(timeout: 1).single()\n            XCTAssertEqual(value, 0)\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)).makeSnapshot() }\n    }\n    \n    // MARK: -\n    \n    func testReadObservableError() throws {\n        func test(reader: DatabaseReader) throws {\n            let single = reader.rx.read(value: { db in\n                try Row.fetchAll(db, sql: \"THIS IS NOT SQL\")\n            })\n            do {\n                _ = try single.toBlocking(timeout: 1).single()\n                XCTFail(\"Expected error\")\n            } catch let error as DatabaseError {\n                XCTAssertEqual(error.resultCode, .SQLITE_ERROR)\n                XCTAssertEqual(error.sql, \"THIS IS NOT SQL\")\n            }\n        }\n        \n        try Test(test)\n            .run { try DatabaseQueue() }\n            .runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }\n            .runAtTemporaryDatabasePath { try DatabasePool(path: $0) }\n            .runAtTemporaryDatabasePath { try DatabasePool(path: $0).makeSnapshot() }\n    }\n    \n    // MARK: -\n    \n    func testReadObservableIsAsynchronous() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(reader: DatabaseReader) throws {\n            let disposeBag = DisposeBag()\n            withExtendedLifetime(disposeBag) {\n                let expectation = self.expectation(description: \"\")\n                let semaphore = DispatchSemaphore(value: 0)\n                reader.rx\n                    .read(value: { db in\n                        try Player.fetchCount(db)\n                    })\n                    .subscribe(\n                        onSuccess: { _ in\n                            semaphore.wait()\n                            expectation.fulfill()\n                        },\n                        onFailure: { error in XCTFail(\"Unexpected error \\(error)\") })\n                    .disposed(by: disposeBag)\n                \n                semaphore.signal()\n                waitForExpectations(timeout: 1, handler: nil)\n            }\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)).makeSnapshot() }\n    }\n    \n    // MARK: -\n    \n    func testReadObservableDefaultScheduler() throws {\n        if #available(OSX 10.12, iOS 10.0, watchOS 3.0, *) {\n            func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n                try writer.write(Player.createTable)\n                return writer\n            }\n            \n            func test(reader: DatabaseReader) {\n                let disposeBag = DisposeBag()\n                withExtendedLifetime(disposeBag) {\n                    let expectation = self.expectation(description: \"\")\n                    reader.rx\n                        .read(value: { db in\n                            try Player.fetchCount(db)\n                        })\n                        .subscribe(\n                            onSuccess: { _ in\n                                dispatchPrecondition(condition: .onQueue(.main))\n                                expectation.fulfill()\n                            },\n                            onFailure: { error in XCTFail(\"Unexpected error \\(error)\") })\n                        .disposed(by: disposeBag)\n                    \n                    waitForExpectations(timeout: 1, handler: nil)\n                }\n            }\n            \n            try Test(test)\n                .run { try setUp(DatabaseQueue()) }\n                .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n                .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n                .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)).makeSnapshot() }\n        }\n    }\n    \n    // MARK: -\n    \n    func testReadObservableCustomScheduler() throws {\n        if #available(OSX 10.12, iOS 10.0, watchOS 3.0, *) {\n            func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n                try writer.write(Player.createTable)\n                return writer\n            }\n            \n            func test(reader: DatabaseReader) {\n                let disposeBag = DisposeBag()\n                withExtendedLifetime(disposeBag) {\n                    let queue = DispatchQueue(label: \"test\")\n                    let expectation = self.expectation(description: \"\")\n                    reader.rx\n                        .read(\n                            observeOn: SerialDispatchQueueScheduler(queue: queue, internalSerialQueueName: \"test\"),\n                            value: { db in\n                                try Player.fetchCount(db)\n                            })\n                        .subscribe(\n                            onSuccess: { _ in\n                                dispatchPrecondition(condition: .onQueue(queue))\n                                expectation.fulfill()\n                            },\n                            onFailure: { error in XCTFail(\"Unexpected error \\(error)\") })\n                        .disposed(by: disposeBag)\n                    \n                    waitForExpectations(timeout: 1, handler: nil)\n                }\n            }\n            \n            try Test(test)\n                .run { try setUp(DatabaseQueue()) }\n                .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n                .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n                .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)).makeSnapshot() }\n        }\n    }\n    \n    // MARK: -\n    \n    func testReadObservableIsReadonly() throws {\n        func test(reader: DatabaseReader) throws {\n            let single = reader.rx.read(value: { db in\n                try Player.createTable(db)\n            })\n            do {\n                _ = try single.toBlocking(timeout: 1).single()\n                XCTFail(\"Expected error\")\n            } catch let error as DatabaseError {\n                XCTAssertEqual(error.resultCode, .SQLITE_READONLY)\n            }\n        }\n        \n        try Test(test)\n            .run { try DatabaseQueue() }\n            .runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }\n            .runAtTemporaryDatabasePath { try DatabasePool(path: $0) }\n            .runAtTemporaryDatabasePath { try DatabasePool(path: $0).makeSnapshot() }\n    }\n}\n"
  },
  {
    "path": "Tests/RxGRDBTests/DatabaseRegionObservationTests.swift",
    "content": "import XCTest\nimport GRDB\nimport RxSwift\nimport RxGRDB\n\nprivate struct Player: Codable, FetchableRecord, PersistableRecord {\n    var id: Int64\n    var name: String\n    var score: Int?\n    \n    static func createTable(_ db: Database) throws {\n        try db.create(table: \"player\") { t in\n            t.autoIncrementedPrimaryKey(\"id\")\n            t.column(\"name\", .text).notNull()\n            t.column(\"score\", .integer)\n        }\n    }\n}\n\nclass DatabaseRegionObservationTests : XCTestCase {\n    \n    func testChangesNotifications() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let disposeBag = DisposeBag()\n            try withExtendedLifetime(disposeBag) {\n                let testSubject = ReplaySubject<Int>.createUnbounded()\n                DatabaseRegionObservation(tracking: Player.all())\n                    .rx.changes(in: writer)\n                    .map(Player.fetchCount)\n                    .subscribe(testSubject)\n                    .disposed(by: disposeBag)\n                \n                try writer.writeWithoutTransaction { db in\n                    try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                    \n                    try db.inTransaction {\n                        try Player(id: 2, name: \"Barbara\", score: 750).insert(db)\n                        try Player(id: 3, name: \"Craig\", score: 500).insert(db)\n                        return .commit\n                    }\n                }\n                \n                let expectedElements = [1, 3]\n                let elements = try testSubject\n                    .take(expectedElements.count)\n                    .toBlocking(timeout: 1)\n                    .toArray()\n                XCTAssertEqual(elements, expectedElements)\n            }\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    // This is an usage test. Do the available APIs allow to prepend a\n    // database connection synchronously, with the guarantee that no race can\n    // have the subscriber miss an impactful change?\n    //\n    // TODO: do the same, but asynchronously. If this is too hard, update the\n    // public API so that users can easily do it.\n    func testPrependInitialDatabaseSync() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let disposeBag = DisposeBag()\n            try withExtendedLifetime(disposeBag) {\n                let expectation = self.expectation(description: \"\")\n                let testSubject = ReplaySubject<Database>.createUnbounded()\n                testSubject\n                    .map(Player.fetchCount)\n                    .take(3)\n                    .toArray()\n                    .subscribe(\n                        onSuccess: { value in\n                            XCTAssertEqual(value, [0, 1, 3])\n                            expectation.fulfill()\n                        },\n                        onFailure: { error in XCTFail(\"Unexpected error \\(error)\") })\n                    .disposed(by: disposeBag)\n                \n                try writer\n                    .write({ db in\n                        DatabaseRegionObservation(tracking: Player.all())\n                            .rx.changes(in: writer)\n                            .startWith(db)\n                            .subscribe(testSubject)\n                    })\n                    .disposed(by: disposeBag)\n                \n                try writer.writeWithoutTransaction { db in\n                    try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                    \n                    try db.inTransaction {\n                        try Player(id: 2, name: \"Barbara\", score: 750).insert(db)\n                        try Player(id: 3, name: \"Craig\", score: 500).insert(db)\n                        return .commit\n                    }\n                }\n                \n                waitForExpectations(timeout: 1, handler: nil)\n            }\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n}\n"
  },
  {
    "path": "Tests/RxGRDBTests/DatabaseWriterWriteTests.swift",
    "content": "import GRDB\nimport RxBlocking\nimport RxGRDB\nimport RxSwift\nimport XCTest\n\nprivate struct Player: Codable, FetchableRecord, PersistableRecord {\n    var id: Int64\n    var name: String\n    var score: Int?\n    \n    static func createTable(_ db: Database) throws {\n        try db.create(table: \"player\") { t in\n            t.autoIncrementedPrimaryKey(\"id\")\n            t.column(\"name\", .text).notNull()\n            t.column(\"score\", .integer)\n        }\n    }\n}\n\nclass DatabaseWriterWriteTests : XCTestCase {\n    func testRxJoiner() {\n        // Make sure `rx` joiner is available in various contexts\n        func f1(_ writer: DatabasePool) {\n            _ = writer.rx.write(updates: { db in })\n        }\n        func f2(_ writer: DatabaseQueue) {\n            _ = writer.rx.write(updates: { db in })\n        }\n        func f4<Writer: DatabaseWriter>(_ writer: Writer) {\n            _ = writer.rx.write(updates: { db in })\n        }\n        func f5(_ writer: DatabaseWriter) {\n            _ = writer.rx.write(updates: { db in })\n        }\n    }\n    \n    // MARK: - Write\n    \n    func testWriteObservable() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let single = writer.rx.write(updates: { db -> Int in\n                try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                return try Player.fetchCount(db)\n            })\n            let count = try single.toBlocking(timeout: 1).single()\n            XCTAssertEqual(count, 1)\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    // MARK: -\n    \n    func testWriteObservableAsCompletable() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let completable = writer.rx\n                .write(updates: { db -> Int in\n                    try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                    return try Player.fetchCount(db)\n                })\n                .asCompletable()\n            _ = try completable.toBlocking(timeout: 1).last()\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    // MARK: -\n    \n    func testWriteObservableError() throws {\n        func test(writer: DatabaseWriter) throws {\n            let single = writer.rx.write(updates: { db in\n                try db.execute(sql: \"THIS IS NOT SQL\")\n            })\n            do {\n                _ = try single.toBlocking(timeout: 1).single()\n                XCTFail(\"Expected error\")\n            } catch let error as DatabaseError {\n                XCTAssertEqual(error.resultCode, .SQLITE_ERROR)\n                XCTAssertEqual(error.sql, \"THIS IS NOT SQL\")\n            }\n        }\n        \n        try Test(test)\n            .run { try DatabaseQueue() }\n            .runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }\n            .runAtTemporaryDatabasePath { try DatabasePool(path: $0) }\n    }\n    \n    func testWriteObservableErrorRollbacksTransaction() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let single = writer.rx.write(updates: { db in\n                try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                try db.execute(sql: \"THIS IS NOT SQL\")\n            })\n            do {\n                _ = try single.toBlocking(timeout: 1).single()\n                XCTFail(\"Expected error\")\n            } catch let error as DatabaseError {\n                XCTAssertEqual(error.resultCode, .SQLITE_ERROR)\n                XCTAssertEqual(error.sql, \"THIS IS NOT SQL\")\n            }\n            let count = try writer.read(Player.fetchCount)\n            XCTAssertEqual(count, 0)\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    // MARK: -\n    \n    func testWriteObservableIsAsynchronous() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let disposeBag = DisposeBag()\n            withExtendedLifetime(disposeBag) {\n                let expectation = self.expectation(description: \"\")\n                let semaphore = DispatchSemaphore(value: 0)\n                writer.rx\n                    .write(updates: { db in\n                        try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                    })\n                    .subscribe(\n                        onSuccess: {\n                            semaphore.wait()\n                            expectation.fulfill()\n                        },\n                        onFailure: { error in XCTFail(\"Unexpected error \\(error)\") })\n                    .disposed(by: disposeBag)\n                \n                semaphore.signal()\n                waitForExpectations(timeout: 1, handler: nil)\n            }\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    func testWriteObservableDefaultScheduler() throws {\n        if #available(OSX 10.12, iOS 10.0, watchOS 3.0, *) {\n            func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n                try writer.write(Player.createTable)\n                return writer\n            }\n            \n            func test(writer: DatabaseWriter) {\n                let disposeBag = DisposeBag()\n                withExtendedLifetime(disposeBag) {\n                    let expectation = self.expectation(description: \"\")\n                    writer.rx\n                        .write(updates: { db in\n                            try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                        })\n                        .subscribe(\n                            onSuccess: { _ in\n                                dispatchPrecondition(condition: .onQueue(.main))\n                                expectation.fulfill()\n                            },\n                            onFailure: { error in XCTFail(\"Unexpected error \\(error)\") })\n                        .disposed(by: disposeBag)\n                    \n                    waitForExpectations(timeout: 1, handler: nil)\n                }\n            }\n            \n            try Test(test)\n                .run { try setUp(DatabaseQueue()) }\n                .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n                .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n        }\n    }\n    \n    // MARK: -\n    \n    func testWriteObservableCustomScheduler() throws {\n        if #available(OSX 10.12, iOS 10.0, watchOS 3.0, *) {\n            func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n                try writer.write(Player.createTable)\n                return writer\n            }\n            \n            func test(writer: DatabaseWriter) {\n                let disposeBag = DisposeBag()\n                withExtendedLifetime(disposeBag) {\n                    let queue = DispatchQueue(label: \"test\")\n                    let expectation = self.expectation(description: \"\")\n                    writer.rx\n                        .write(\n                            observeOn: SerialDispatchQueueScheduler(queue: queue, internalSerialQueueName: \"test\"),\n                            updates: { db in\n                                try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                            })\n                        .subscribe(\n                            onSuccess: { _ in\n                                dispatchPrecondition(condition: .onQueue(queue))\n                                expectation.fulfill()\n                            },\n                            onFailure: { error in XCTFail(\"Unexpected error \\(error)\") })\n                        .disposed(by: disposeBag)\n                    \n                    waitForExpectations(timeout: 1, handler: nil)\n                }\n            }\n            \n            try Test(test)\n                .run { try setUp(DatabaseQueue()) }\n                .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n                .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n        }\n    }\n    \n    // MARK: - WriteThenRead\n    \n    func testWriteThenReadObservable() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let single = writer.rx.write(\n                updates: { db in try Player(id: 1, name: \"Arthur\", score: 1000).insert(db) },\n                thenRead: { db, _ in try Player.fetchCount(db) })\n            let count = try single.toBlocking(timeout: 1).single()\n            XCTAssertEqual(count, 1)\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    // MARK: -\n    \n    func testWriteThenReadObservableIsReadonly() throws {\n        func test(writer: DatabaseWriter) throws {\n            let single = writer.rx.write(\n                updates: { _ in },\n                thenRead: { db, _ in try Player.createTable(db) })\n            do {\n                _ = try single.toBlocking(timeout: 1).single()\n                XCTFail(\"Expected error\")\n            } catch let error as DatabaseError {\n                XCTAssertEqual(error.resultCode, .SQLITE_READONLY)\n            }\n        }\n        \n        try Test(test)\n            .run { try DatabaseQueue() }\n            .runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }\n            .runAtTemporaryDatabasePath { try DatabasePool(path: $0) }\n    }\n    \n    // MARK: -\n    \n    func testWriteThenReadObservableWriteError() throws {\n        func test(writer: DatabaseWriter) throws {\n            let single = writer.rx.write(\n                updates: { db in try db.execute(sql: \"THIS IS NOT SQL\") },\n                thenRead: { _, _ in })\n            do {\n                _ = try single.toBlocking(timeout: 1).single()\n                XCTFail(\"Expected error\")\n            } catch let error as DatabaseError {\n                XCTAssertEqual(error.resultCode, .SQLITE_ERROR)\n                XCTAssertEqual(error.sql, \"THIS IS NOT SQL\")\n            }\n        }\n        \n        try Test(test)\n            .run { try DatabaseQueue() }\n            .runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }\n            .runAtTemporaryDatabasePath { try DatabasePool(path: $0) }\n    }\n    \n    func testWriteThenReadObservableWriteErrorRollbacksTransaction() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let single = writer.rx.write(\n                updates: { db in\n                    try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                    try db.execute(sql: \"THIS IS NOT SQL\")\n                },\n                thenRead: { _, _ in })\n            do {\n                _ = try single.toBlocking(timeout: 1).single()\n                XCTFail(\"Expected error\")\n            } catch let error as DatabaseError {\n                XCTAssertEqual(error.resultCode, .SQLITE_ERROR)\n                XCTAssertEqual(error.sql, \"THIS IS NOT SQL\")\n            }\n            let count = try writer.read(Player.fetchCount)\n            XCTAssertEqual(count, 0)\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    // MARK: -\n    \n    func testWriteThenReadObservableReadError() throws {\n        func test(writer: DatabaseWriter) throws {\n            let single = writer.rx.write(\n                updates: { _ in },\n                thenRead: { db, _ in try Row.fetchAll(db, sql: \"THIS IS NOT SQL\") })\n            do {\n                _ = try single.toBlocking(timeout: 1).single()\n                XCTFail(\"Expected error\")\n            } catch let error as DatabaseError {\n                XCTAssertEqual(error.resultCode, .SQLITE_ERROR)\n                XCTAssertEqual(error.sql, \"THIS IS NOT SQL\")\n            }\n        }\n        \n        try Test(test)\n            .run { try DatabaseQueue() }\n            .runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }\n            .runAtTemporaryDatabasePath { try DatabasePool(path: $0) }\n    }\n    \n    // MARK: -\n    \n    func testWriteThenReadObservableDefaultScheduler() throws {\n        if #available(OSX 10.12, iOS 10.0, watchOS 3.0, *) {\n            func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n                try writer.write(Player.createTable)\n                return writer\n            }\n            \n            func test(writer: DatabaseWriter) {\n                let disposeBag = DisposeBag()\n                withExtendedLifetime(disposeBag) {\n                    let expectation = self.expectation(description: \"\")\n                    writer.rx\n                        .write(\n                            updates: { _ in },\n                            thenRead: { _, _ in })\n                        .subscribe(\n                            onSuccess: { _ in\n                                dispatchPrecondition(condition: .onQueue(.main))\n                                expectation.fulfill()\n                            },\n                            onFailure: { error in XCTFail(\"Unexpected error \\(error)\") })\n                        .disposed(by: disposeBag)\n                    \n                    waitForExpectations(timeout: 1, handler: nil)\n                }\n            }\n            \n            try Test(test)\n                .run { try setUp(DatabaseQueue()) }\n                .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n                .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n        }\n    }\n    \n    // MARK: -\n    \n    func testWriteThenReadObservableCustomScheduler() throws {\n        if #available(OSX 10.12, iOS 10.0, watchOS 3.0, *) {\n            func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n                try writer.write(Player.createTable)\n                return writer\n            }\n            \n            func test(writer: DatabaseWriter) {\n                let disposeBag = DisposeBag()\n                withExtendedLifetime(disposeBag) {\n                    let queue = DispatchQueue(label: \"test\")\n                    let expectation = self.expectation(description: \"\")\n                    writer.rx\n                        .write(\n                            observeOn: SerialDispatchQueueScheduler(queue: queue, internalSerialQueueName: \"test\"),\n                            updates: { _ in },\n                            thenRead: { _, _ in })\n                        .subscribe(\n                            onSuccess: { _ in\n                                dispatchPrecondition(condition: .onQueue(queue))\n                                expectation.fulfill()\n                            },\n                            onFailure: { error in XCTFail(\"Unexpected error \\(error)\") })\n                        .disposed(by: disposeBag)\n                    \n                    waitForExpectations(timeout: 1, handler: nil)\n                }\n            }\n            \n            try Test(test)\n                .run { try setUp(DatabaseQueue()) }\n                .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n                .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/RxGRDBTests/Support.swift",
    "content": "import XCTest\nimport RxSwift\nimport GRDB\n\nfinal class Test<Context> {\n    // Raise the repeatCount in order to help spotting flaky tests.\n    private let repeatCount = 1\n    private let test: (Context) throws -> ()\n    \n    init(_ test: @escaping (Context) throws -> ()) {\n        self.test = test\n    }\n    \n    @discardableResult\n    func run(context: () throws -> Context) throws -> Self {\n        for _ in 1...repeatCount {\n            try test(context())\n        }\n        return self\n    }\n    \n    @discardableResult\n    func runInTemporaryDirectory(context: (_ directoryURL: URL) throws -> Context) throws -> Self {\n        for _ in 1...repeatCount {\n            let directoryURL = URL(fileURLWithPath: NSTemporaryDirectory())\n                .appendingPathComponent(\"GRDBCombine\", isDirectory: true)\n                .appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString, isDirectory: true)\n            \n            try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)\n            defer {\n                try! FileManager.default.removeItem(at: directoryURL)\n            }\n            \n            try test(context(directoryURL))\n        }\n        return self\n    }\n    \n    @discardableResult\n    func runAtTemporaryDatabasePath(context: (_ path: String) throws -> Context) throws -> Self {\n        try runInTemporaryDirectory { url in\n            try context(url.appendingPathComponent(\"db.sqlite\").path)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/RxGRDBTests/ValueObservationTests.swift",
    "content": "import XCTest\nimport GRDB\nimport RxSwift\nimport RxGRDB\n\nprivate struct Player: Codable, FetchableRecord, PersistableRecord {\n    var id: Int64\n    var name: String\n    var score: Int?\n    \n    static func createTable(_ db: Database) throws {\n        try db.create(table: \"player\") { t in\n            t.autoIncrementedPrimaryKey(\"id\")\n            t.column(\"name\", .text).notNull()\n            t.column(\"score\", .integer)\n        }\n    }\n}\n\nclass ValueObservationTests : XCTestCase {\n    \n    // MARK: - Default Scheduler\n    \n    func testDefaultSchedulerChangesNotifications() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let disposeBag = DisposeBag()\n            try withExtendedLifetime(disposeBag) {\n                let testSubject = ReplaySubject<Int>.createUnbounded()\n                ValueObservation\n                    .tracking(Player.fetchCount)\n                    .rx.observe(in: writer)\n                    .subscribe(testSubject)\n                    .disposed(by: disposeBag)\n                \n                try writer.writeWithoutTransaction { db in\n                    try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                    \n                    try db.inTransaction {\n                        try Player(id: 2, name: \"Barbara\", score: 750).insert(db)\n                        try Player(id: 3, name: \"Craig\", score: 500).insert(db)\n                        return .commit\n                    }\n                }\n                \n                let expectedElements = [0, 1, 3]\n                if writer is DatabaseQueue {\n                    let elements = try testSubject\n                        .take(expectedElements.count)\n                        .toBlocking(timeout: 1).toArray()\n                    XCTAssertEqual(elements, expectedElements)\n                } else {\n                    let elements = try testSubject\n                        .take(until: { $0 == expectedElements.last }, behavior: .inclusive)\n                        .toBlocking(timeout: 1).toArray()\n                    assertValueObservationRecordingMatch(recorded: elements, expected: expectedElements)\n                }\n            }\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    func testDefaultSchedulerFirstValueIsEmittedAsynchronously() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let disposeBag = DisposeBag()\n            withExtendedLifetime(disposeBag) {\n                let expectation = self.expectation(description: \"\")\n                let semaphore = DispatchSemaphore(value: 0)\n                ValueObservation\n                    .tracking(Player.fetchCount)\n                    .rx.observe(in: writer)\n                    .subscribe(onNext: { _ in\n                        semaphore.wait()\n                        expectation.fulfill()\n                    })\n                    .disposed(by: disposeBag)\n                \n                semaphore.signal()\n                waitForExpectations(timeout: 1, handler: nil)\n            }\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    func testDefaultSchedulerError() throws {\n        func test(writer: DatabaseWriter) throws {\n            let observable = ValueObservation\n                .tracking { try $0.execute(sql: \"THIS IS NOT SQL\") }\n                .rx.observe(in: writer)\n            let result = observable.toBlocking().materialize()\n            switch result {\n            case .completed:\n                XCTFail(\"Expected error\")\n            case let .failed(elements: _, error: error):\n                XCTAssertNotNil(error as? DatabaseError)\n            }\n        }\n        \n        try Test(test)\n            .run { try DatabaseQueue() }\n            .runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }\n            .runAtTemporaryDatabasePath { try DatabasePool(path: $0) }\n    }\n    \n    // MARK: - Immediate Scheduler\n    \n    func testImmediateSchedulerChangesNotifications() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let disposeBag = DisposeBag()\n            try withExtendedLifetime(disposeBag) {\n                let testSubject = ReplaySubject<Int>.createUnbounded()\n                ValueObservation\n                    .tracking(Player.fetchCount)\n                    .rx.observe(in: writer, scheduling: .immediate)\n                    .subscribe(testSubject)\n                    .disposed(by: disposeBag)\n                \n                try writer.writeWithoutTransaction { db in\n                    try Player(id: 1, name: \"Arthur\", score: 1000).insert(db)\n                    \n                    try db.inTransaction {\n                        try Player(id: 2, name: \"Barbara\", score: 750).insert(db)\n                        try Player(id: 3, name: \"Craig\", score: 500).insert(db)\n                        return .commit\n                    }\n                }\n                \n                let expectedElements = [0, 1, 3]\n                if writer is DatabaseQueue {\n                    let elements = try testSubject\n                        .take(expectedElements.count)\n                        .toBlocking(timeout: 1).toArray()\n                    XCTAssertEqual(elements, expectedElements)\n                } else {\n                    let elements = try testSubject\n                        .take(until: { $0 == expectedElements.last }, behavior: .inclusive)\n                        .toBlocking(timeout: 1).toArray()\n                    assertValueObservationRecordingMatch(recorded: elements, expected: expectedElements)\n                }\n            }\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    func testImmediateSchedulerEmitsFirstValueSynchronously() throws {\n        func setUp<Writer: DatabaseWriter>(_ writer: Writer) throws -> Writer {\n            try writer.write(Player.createTable)\n            return writer\n        }\n        \n        func test(writer: DatabaseWriter) throws {\n            let disposeBag = DisposeBag()\n            withExtendedLifetime(disposeBag) {\n                let semaphore = DispatchSemaphore(value: 0)\n                ValueObservation\n                    .tracking(Player.fetchCount)\n                    .rx.observe(in: writer, scheduling: .immediate)\n                    .subscribe(onNext: { _ in\n                        semaphore.signal()\n                    })\n                    .disposed(by: disposeBag)\n                \n                semaphore.wait()\n            }\n        }\n        \n        try Test(test)\n            .run { try setUp(DatabaseQueue()) }\n            .runAtTemporaryDatabasePath { try setUp(DatabaseQueue(path: $0)) }\n            .runAtTemporaryDatabasePath { try setUp(DatabasePool(path: $0)) }\n    }\n    \n    func testImmediateSchedulerError() throws {\n        func test(writer: DatabaseWriter) throws {\n            let observable = ValueObservation\n                .tracking { try $0.execute(sql: \"THIS IS NOT SQL\") }\n                .rx.observe(in: writer, scheduling: .immediate)\n            let result = observable.toBlocking().materialize()\n            switch result {\n            case .completed:\n                XCTFail(\"Expected error\")\n            case let .failed(elements: _, error: error):\n                XCTAssertNotNil(error as? DatabaseError)\n            }\n        }\n        \n        try Test(test)\n            .run { try DatabaseQueue() }\n            .runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }\n            .runAtTemporaryDatabasePath { try DatabasePool(path: $0) }\n    }\n    \n    func testIssue780() throws {\n        func test(dbPool: DatabasePool) throws {\n            struct Entity: Codable, FetchableRecord, PersistableRecord, Equatable {\n                var id: Int64\n                var name: String\n            }\n            try dbPool.write { db in\n                try db.create(table: \"entity\") { t in\n                    t.autoIncrementedPrimaryKey(\"id\")\n                    t.column(\"name\", .text)\n                }\n            }\n            let observation = ValueObservation.tracking(Entity.fetchAll)\n            let entities = try dbPool.rx\n                .write { db in try Entity(id: 1, name: \"foo\").insert(db) }\n                .asCompletable()\n                .andThen(observation.rx.observe(in: dbPool, scheduling: .immediate))\n                .take(1)\n                .toBlocking(timeout: 1)\n                .single()\n            XCTAssertEqual(entities, [Entity(id: 1, name: \"foo\")])\n        }\n        try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }\n    }\n    \n    // MARK: - Utils\n    \n    /// This test checks the fundamental promise of ValueObservation by\n    /// comparing recorded values with expected values.\n    ///\n    /// Recorded values match the expected values if and only if:\n    ///\n    /// - The last recorded value is the last expected value\n    /// - Recorded values are in the same order as expected values\n    ///\n    /// However, both missing and repeated values are allowed - with the only\n    /// exception of the last expected value which can not be missed.\n    ///\n    /// For example, if the expected values are [0, 1], then the following\n    /// recorded values match:\n    ///\n    /// - `[0, 1]` (identical values)\n    /// - `[1]` (missing value but the last one)\n    /// - `[0, 0, 1, 1]` (repeated value)\n    ///\n    /// However the following recorded values don't match, and fail the test:\n    ///\n    /// - `[1, 0]` (wrong order)\n    /// - `[0]` (missing last value)\n    /// - `[]` (missing last value)\n    /// - `[0, 1, 2]` (unexpected value)\n    /// - `[1, 0, 1]` (unexpected value)\n    func assertValueObservationRecordingMatch<Value>(\n        recorded recordedValues: [Value],\n        expected expectedValues: [Value],\n        _ message: @autoclosure () -> String = \"\",\n        file: StaticString = #file,\n        line: UInt = #line)\n    where Value: Equatable\n    {\n        _assertValueObservationRecordingMatch(\n            recorded: recordedValues,\n            expected: expectedValues,\n            // Last value can't be missed\n            allowMissingLastValue: false,\n            message(), file: file, line: line)\n    }\n    \n    private func _assertValueObservationRecordingMatch<R, E>(\n        recorded recordedValues: R,\n        expected expectedValues: E,\n        allowMissingLastValue: Bool,\n        _ message: @autoclosure () -> String = \"\",\n        file: StaticString = #file,\n        line: UInt = #line)\n    where\n        R: BidirectionalCollection,\n        E: BidirectionalCollection,\n        R.Element == E.Element,\n        R.Element: Equatable\n    {\n        guard let value = expectedValues.last else {\n            if !recordedValues.isEmpty {\n                XCTFail(\"unexpected recorded prefix \\(Array(recordedValues)) - \\(message())\", file: file, line: line)\n            }\n            return\n        }\n        \n        let recordedSuffix = recordedValues.reversed().prefix(while: { $0 == value })\n        let expectedSuffix = expectedValues.reversed().prefix(while: { $0 == value })\n        if !allowMissingLastValue {\n            // Both missing and repeated values are allowed in the recorded values.\n            // This is because of asynchronous DatabasePool observations.\n            if recordedSuffix.isEmpty {\n                XCTFail(\"missing expected value \\(value) - \\(message())\", file: file, line: line)\n            }\n        }\n        \n        let remainingRecordedValues = recordedValues.prefix(recordedValues.count - recordedSuffix.count)\n        let remainingExpectedValues = expectedValues.prefix(expectedValues.count - expectedSuffix.count)\n        _assertValueObservationRecordingMatch(\n            recorded: remainingRecordedValues,\n            expected: remainingExpectedValues,\n            // Other values can be missed\n            allowMissingLastValue: true,\n            message(), file: file, line: line)\n    }\n}\n"
  }
]