Parse Server Swift SDKの使い方（データストアのクエリー操作）

[ニフクラ mobile backendは3月末で終了します](https://mbaas.nifcloud.com/info/2023/12/post-171.html)。

ニフクラ mobile backendからの移行先として、お勧めしているのが[Parse Server](https://parseplatform.org/)です。設計思想が近く、変更するコード量が少なく済むのではないかと思います。

Parse ServerではiOS向けにSDKを提供していますが、Swift SDKについてはあまりドキュメントが充実していません。そこで、各機能の使い方を解説します。今回はデータストアのクエリー（データ抽出）の使い方を解説します。

## Swift SDKとObjective-C SDKのどちらを使うべきか

Parse ServerにはSwift SDKと[Objective-C SDK](https://docs.parseplatform.org/ios/guide/)が用意されています。機能的にいうと、Objective-C SDKの方が多いようです。しかし、公式メッセージとしてはSwift SDKを使っていくのを奨励しています。

## Parse Server Swift SDKのインストール

Swift SDKのインストールは、CocoaPodsやCarthageなどが使えます。しかし、一番簡単なのはXcodeのPackage Dependenciesを使う方法でしょう。

XcodeのFileメニューより、Add Package Dependenciesを選択して、出てきたダイアログで以下のURLを指定します。

```
https://github.com/parse-community/Parse-Swift.git
```

そして、利用するファイルでSDKをインポートします。

```swift
import ParseSwift
```

## 初期化

SwiftUIの例です。初期化は `(アプリ名)App.swift` にて行います。そして、初期化は `ParseSwift.initialize` にて行います。指定するアプリケーションID、クライアントキー、サーバーURLはそれぞれParse Serverを立ち上げる際に指定したものを使います。

マスターキーも指定できるようですが、アプリ側では使わない方が良いかと思います。

```swift
import SwiftUI
import ParseSwift

@main
struct ParseDemoApp: App {
    init() {
        ParseSwift.initialize(applicationId: "YOUR_APP_ID", clientKey: "YOUR_CLIENT_KEY", serverURL: URL(string: "https://example.com/parse")!)
    }
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
```

## クエリーの使い方

クエリーは、ParseObjectを継承した構造体を利用します。たとえば以下のような構造体を定義します。

```swift
import ParseSwift

struct Item: ParseObject {
    // 以下は必須です
    var objectId: String?
    var createdAt: Date?
    var updatedAt: Date?
    var ACL: ParseACL?
    var originalData: Data?

    // 以下は自分で定義したフィールドです
    var name: String?
    var file: ParseFile?
}
```

この構造体の `query` メソッドで、クエリーが実行できます。

### 非同期処理

非同期でクエリーを実行する例です。

```swift
let query = Item.query()
query.find { result in
		switch result {
		case .success(let items):
				print(items)
		case .failure(let error):
				print(error)
		}
}
```

### 同期処理

同期の場合は `try` を使います。

```swift
do {
	let items = try? query.find()
	print(items)
} catch {
	print("エラー")
}
```

## 条件指定

クエリー時に検索条件を付ける場合、NCMBとは大きく異なるので注意してください。 `query` メソッドに `QueryConstraint` を渡すことで条件指定になります。

```swift
let constraint: QueryConstraint = "numberOfFriends" == 2
let query = Item.query(constraint)
// 直接指定も可能
let query = Item.query("name" == "Test")
let items = try? query.find()
```

### AND条件

AND条件は、複数のクエリーを作り、それを `and` メソッドで指定します。

```swift
let query1 = Profile.query("numberOfFriends" > 10)
let query2 = Profile.query("numberOfFriends" < 50)

let query = Profile.query(and(queries: query1, query2))
```

## 複雑な条件付け

たとえば配列の中を検索する場合には、 `containedIn` を使います。

```swift
let constraint: QueryConstraint = containedIn(key: "luckyNumbers", array: [2, 7])
```

位置情報の場合です。

```swift
guard let geopoint = try? ParseGeoPoint(latitude: 37.38412167489413, longitude: -122.01268034622319) else {
  return
}
let query = Profile.query(near(key: "lastLoginLocation", geoPoint: geopoint))
```

## 結果から、特定のフィールドを除外する

`exclude` メソッドを使うと、特定のフィールドを検索結果から除外できます。

```swift
let query = Profile.query().exclude("name", "numberOfFriends")
```

## 並び順

`order` で並び順を指定できます。

```swift
let query = Profile.query().order([.ascending("numberOfFriends")])
```

## 取得件数の指定

取得件数は `limit` で指定します。最大は1,000です。

```swift
let query = Profile.query().limit(2)
```

## まとめ

Parse ServerとNCMBでは、クエリーの使い方が大きく異なります。慣れれば直感的かも知れませんが、どういった関数が用意されているのかが分かりづらいのが難点です。

Parse ServerとNCMBのデータストア操作は、SDKの仕組みで異なる部分が多いです。載せ替える際には、コードの修正が必要になるでしょう。

とはいえ、データの管理方法などはParse ServerとNCMBで似ています。他のmBaaSと比べると、修正量はそこまで多くないと思われます。載せ替え先として検討に挙げてください。

[parse\-community/Parse\-Swift: The Swift SDK for Parse Platform \(iOS, macOS, watchOS, tvOS, Linux, Android, Windows\)](https://github.com/parse-community/Parse-Swift)