⌘+k ctrl+k
1.3 (稳定版)
搜索快捷键 cmd + k | ctrl + k
Swift 客户端

DuckDB 提供 Swift 客户端。详见发布公告

实例化 DuckDB

DuckDB 支持内存数据库和持久化数据库。要使用内存数据库,请运行

let database = try Database(store: .inMemory)

要使用持久化数据库,请运行

let database = try Database(store: .file(at: "test.db"))

查询可以通过数据库连接发出。

let connection = try database.connect()

DuckDB 支持每个数据库多个连接。

应用程序示例

页面的其余部分基于我们发布公告中的示例,该示例使用从NASA 系外行星档案直接加载到 DuckDB 的原始数据。

创建应用程序特定类型

我们首先创建一个应用程序特定类型,用于存储我们的数据库和连接,并通过它最终定义我们的应用程序特定查询。

import DuckDB

final class ExoplanetStore {

  let database: Database
  let connection: Connection

  init(database: Database, connection: Connection) {
    self.database = database
    self.connection = connection
  }
}

加载 CSV 文件

我们从NASA 系外行星档案加载数据

wget https://exoplanetarchive.ipac.caltech.edu/TAP/sync?query=select+pl_name+,+disc_year+from+pscomppars&format=csv -O downloaded_exoplanets.csv

将 CSV 文件下载到本地后,我们可以使用以下 SQL 命令将其作为新表加载到 DuckDB 中

CREATE TABLE exoplanets AS
    SELECT * FROM read_csv('downloaded_exoplanets.csv');

让我们将其封装为我们 ExoplanetStore 类型的一个新的异步工厂方法

import DuckDB
import Foundation

final class ExoplanetStore {

  // Factory method to create and prepare a new ExoplanetStore
  static func create() async throws -> ExoplanetStore {

  // Create our database and connection as described above
    let database = try Database(store: .inMemory)
    let connection = try database.connect()

  // Download the CSV from the exoplanet archive
  let (csvFileURL, _) = try await URLSession.shared.download(
    from: URL(string: "https://exoplanetarchive.ipac.caltech.edu/TAP/sync?query=select+pl_name+,+disc_year+from+pscomppars&format=csv")!)

  // Issue our first query to DuckDB
  try connection.execute("""
      CREATE TABLE exoplanets AS
          SELECT * FROM read_csv('\(csvFileURL.path)');
  """)

  // Create our pre-populated ExoplanetStore instance
    return ExoplanetStore(
    database: database,
      connection: connection
  )
  }

  // Let's make the initializer we defined previously
  // private. This prevents anyone accidentally instantiating
  // the store without having pre-loaded our Exoplanet CSV
  // into the database
  private init(database: Database, connection: Connection) {
  ...
  }
}

查询数据库

以下示例通过异步函数从 Swift 内部查询 DuckDB。这意味着在查询执行期间,调用者不会被阻塞。然后,我们将使用 DuckDB 的 ResultSet cast(to:) 系列方法将结果列转换为 Swift 原生类型,最后将其封装在 TabularData 框架的 DataFrame 中。

...

import TabularData

extension ExoplanetStore {

  // Retrieves the number of exoplanets discovered by year
  func groupedByDiscoveryYear() async throws -> DataFrame {

  // Issue the query we described above
    let result = try connection.query("""
      SELECT disc_year, count(disc_year) AS Count
        FROM exoplanets
        GROUP BY disc_year
        ORDER BY disc_year
      """)

    // Cast our DuckDB columns to their native Swift
    // equivalent types
    let discoveryYearColumn = result[0].cast(to: Int.self)
    let countColumn = result[1].cast(to: Int.self)

    // Use our DuckDB columns to instantiate TabularData
    // columns and populate a TabularData DataFrame
    return DataFrame(columns: [
      TabularData.Column(discoveryYearColumn).eraseToAnyColumn(),
      TabularData.Column(countColumn).eraseToAnyColumn(),
    ])
  }
}

完整项目

如需完整的示例项目,请克隆 DuckDB Swift 仓库并打开位于 Examples/SwiftUI/ExoplanetExplorer.xcodeproj 的可运行应用程序项目。