update.みなさんアプリのデータベースには何を使っていますか?周りをみてみると、「SQLite?今はやっぱRealmやろ!」って感じで最近はRealmが積極的に採用されていますね。僕もRealmを利用していて、SQLite+FMDBを使っていた頃に比べると生SQL書かんで済むわサーバー建てればデバイス間の同期が楽にできるわで爆速で開発が進むようになり、控えめに言って尊いです。「Swiftyに書けて」「比較的早くて」「イイ感じ」にSQLiteを操作できるライブラリ「GRDB.swift」を使ってみて、まだまだSQLiteでもいけそうだなーと感じたところがあったのでまとめてみました。他のライブラリではマイグレーション機能を標準でサポートされていないことが多く、別途ライブラリを追加する必要があったのでこれは嬉しいと思いますね。Performance流石にRealmには負けてしまいますが、他のSQLiteライブラリに比べるとInsert/Fetch共に早いですね。Swift4対応されている機能や仕様について細かく書かれています。Swift4にもきちんと対応しており、Codableを用いたモデル定義も可能です。コミュニティ(Issuesのみですが)も比較的活発です。Managerに対応しています。Carthageは未サポートのようです。'GRDB.swift'DBへの接続方法データベースへ接続するには、DatabaseQueueあるいはDatabasePoolを用意します。DatabaseQueueは、データベースへ直列アクセスします。Memoryになります。DatabasePoolは、データベースへの同時並行アクセスをサポートします。WALモードを有効にしたい場合、パフォーマンス重視の場合はこちらを使いましょう。どちらを使えばいいのかわからない場合は、DatabaseQueueを使ってください。"path")モデルの定義とテーブルの作成Userテーブルを作成する例を考えてみます。GRDBにはいくつかプロトコルが用意されており、使いたい機能に応じてプロトコルを継承する形です。わからない場合はすべての機能が使えるRecordクラスを使っておけばいいと思います。Deleteなどを行う際に必要となるプロトコルです。プロパティの変更を行いたい場合(idなど)、MutablePersistableを使ってください。TableMappingテーブル名の定義、クエリインターフェイスを利用する場合に必要となるプロトコルです。Recordの継承元でもあり、これ単体で必要になるパターンはあまりないと思います。必要に応じてRowConvertibleを継承します。fetchOneなど)。クエリインターフェイスを必要とする場合、TableMappingも一緒に継承する必要があります。Persistableを継承したクラスです。全ての機能が使えるようになるので、だいたいはこのクラスを継承してモデルを作成します。他のプロトコルとの違いは、プロパティの変更検知が効くことです。これにより、プロパティが変更されたかどうか、された場合は必要なカラムのみUpdateという処理が行えます。(*後述します)今回は、このRecordクラスを継承したモデルを作成します。}}プロパティの変更検知いらない、もっとすっきり書きたい!という場合はこういう書き方でもいけます。Codableサイコーですね。}}定義ができたところで、実際にテーブルを作成します。inDatabase(あるいはinTransaction)内でcreateメソッドを呼び出し、カラムの定義を行います。}}実際にプロジェクトで使う場合はマイグレーションの定義内でやるほうが良いです。fetchデータベースから行を取得する場合は、fetchメソッドを呼び出します。1行のみ欲しい場合はfetchOne、複数の行の場合はfetchAllを呼び出します。nil)selectSQLの"SELECT"にあたる部分です。取得したいカラムを指定することができます。カラムに合わせた型に変更する場合は、asRequestを呼び出します。.fetchOne(db)filterSQLの"WHERE"にあたる部分です。カラムを利用し条件を指定するか、直接SQLを記述することもできます。2).fetchAll(db)IN句の場合はcontainsを使用します。BY"にあたる部分です。降順(DESC)を指定したい場合はorderのあとにreversedメソッドを呼び出します。User.Columns.createdAt).fetchAll(db)limitSQLの"LIMIT"にあたる部分です。OFFSETの指定も可能です。BY"と"HAVING"にあたる部分です。.fetchOne(db)Insert/Update/Deleteデータを挿入する場合はモデルからinsertが生えているのでこれを呼び出します。今回の例ではUserのidにnilを指定していますが、didInsertを実装しているため、InsertされるとidにRowIDが割り当てられるようになっています。saveというメソッド使うとDBにまだ挿入されていない場合はInsert、挿入されていればUpdateしてくれます。user.save(db)UpdateとDeleteの場合も同様です。user.delete(db)注意点として、updateメソッドは、変更を加えていないカラムに対してもSETを行います。以下のSQLは実際にGRDBが発行するSQLです。"id"=1変更を加えていないカラムに対しても更新を行ってしまうのはよろしくないので、変更を加えたカラムのみ更新を行うようにします。Recordクラスを継承していれば、updateChangesを呼び出す方法が一番簡単です。user.updateChanges(db)update時にカラムを指定する方法もあります。writeメソッドを利用するとすっきり書けます。User.fetchOne(db)}複数、あるいは大量にInsertやUpdateを行う場合はwriteではなくwriteInTransactionを呼び出しトランザクション内で処理を行うようにしてください。.commit}また、データベースに書き込んだ直後にテーブルからデータを取得したい場合があると思います。以下の例は良くない例で、writeとreadの間に別スレッドから書き込みが行われた場合、fetchCountの値が正しい値になりません。以下の処理の流れは良くない例です。}}GRDBのreadmeには、同時並行性を保証するためにこういう実装をしてね。いう記載がありますので、詳しくはこちらを読んでください。GRDB.swift#ConcurrencyオブザーバGRDBでは、オブザーバを通して全てのデータベース上のInsert/Update/Deleteおよびcommit/rollbackのイベントを受け取ることができます。利用するには、TrsansactionObserverプロトコルを継承したクラスを作成し、DatabasePool/DatabaseQueueにaddします。inTransaction(inDatabase)内でもaddできます。observesメソッドでtrueを返すとdatabaseDidChangeが呼ばれるようになります。引数にeventKindがあり、これを参照して呼ぶか呼ばないか判断することができます。eventKind.tableNameをみてイベント通知するかしないかといった処理が行えます。...}マイグレーションGRDBは単体でマイグレーション機能がついています。DatabaseMigratorのregisterMigrationでテーブルの定義や処理を記述し、migrateを呼び出すだけでイイ感じにやってくれます。"v2")RxGRDBGRDBはRx向けにRxGRDBを別途用意されています。RxSwiftでアプリを作ることが多いので感謝感激雨あられですね。})changesを使うとオブザーバーと同じようにデータベースの変更にも対応できます。requestStockLike47@owenFollow株式会社Azit"乗りたい"と"乗せたい"を繋げるモビリティプラットフォーム「CREW(クルー)」を運営しています。upLoginユーザーは見つかりませんでした。