Skip to content

基本的な使い方

DuckDB WASM アダプターの基本的な使い方を学びます。

接続の作成

最初のステップは、DuckDBへの接続を作成することです。

React

jsx
import { DuckDBProvider } from '@northprint/duckdb-wasm-adapter-react';

function App() {
  return (
    <DuckDBProvider 
      autoConnect={true}
      config={{
        worker: true,
        logLevel: 'warning'
      }}
    >
      <YourApp />
    </DuckDBProvider>
  );
}

Vue

javascript
// main.js
import { createApp } from 'vue';
import { DuckDBPlugin } from '@northprint/duckdb-wasm-adapter-vue';

const app = createApp(App);
app.use(DuckDBPlugin, {
  autoConnect: true,
  config: {
    worker: true
  }
});

Svelte

javascript
import { createDuckDB } from '@northprint/duckdb-wasm-adapter-svelte';

const db = createDuckDB({
  autoConnect: true,
  config: {
    worker: true
  }
});

Vanilla JavaScript

javascript
import { createConnection } from '@northprint/duckdb-wasm-adapter-core';

const connection = await createConnection({
  worker: true,
  logLevel: 'warning'
});

テーブルの作成

SQLのCREATE TABLE文を使用してテーブルを作成します:

javascript
await connection.execute(`
  CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name VARCHAR NOT NULL,
    email VARCHAR UNIQUE,
    age INTEGER,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  )
`);

データ型

DuckDBは以下のデータ型をサポートしています:

説明
BOOLEAN真偽値true, false
INTEGER32ビット整数42
BIGINT64ビット整数9223372036854775807
DOUBLE倍精度浮動小数点3.14159
DECIMAL(p,s)固定小数点DECIMAL(10,2)
VARCHAR可変長文字列'Hello'
DATE日付'2024-01-01'
TIMESTAMPタイムスタンプ'2024-01-01 12:00:00'

データの挿入

単一行の挿入

javascript
await connection.execute(
  'INSERT INTO users (name, email, age) VALUES (?, ?, ?)',
  ['田中太郎', 'tanaka@example.com', 30]
);

複数行の挿入

javascript
const users = [
  ['佐藤花子', 'sato@example.com', 25],
  ['鈴木一郎', 'suzuki@example.com', 35],
  ['高橋美咲', 'takahashi@example.com', 28]
];

for (const user of users) {
  await connection.execute(
    'INSERT INTO users (name, email, age) VALUES (?, ?, ?)',
    user
  );
}

バルクインサート(CSV)

javascript
const csvData = `name,email,age
田中太郎,tanaka@example.com,30
佐藤花子,sato@example.com,25
鈴木一郎,suzuki@example.com,35`;

const blob = new Blob([csvData], { type: 'text/csv' });
const file = new File([blob], 'users.csv');

await connection.importCSV(file, 'users', {
  header: true,
  delimiter: ','
});

データの取得

すべての行を取得

javascript
const result = await connection.execute('SELECT * FROM users');
const users = result.toArray();

users.forEach(user => {
  console.log(`${user.name} (${user.age}歳)`);
});

条件付き検索

javascript
// WHERE句
const adults = await connection.execute(
  'SELECT * FROM users WHERE age >= ?',
  [20]
);

// 複数条件
const result = await connection.execute(
  'SELECT * FROM users WHERE age >= ? AND email LIKE ?',
  [20, '%@example.com']
);

// ソート
const sorted = await connection.execute(
  'SELECT * FROM users ORDER BY age DESC'
);

// 件数制限
const top10 = await connection.execute(
  'SELECT * FROM users LIMIT 10'
);

集計関数

javascript
// カウント
const count = await connection.execute(
  'SELECT COUNT(*) as total FROM users'
);
console.log(`ユーザー数: ${count.toArray()[0].total}`);

// 平均
const avgAge = await connection.execute(
  'SELECT AVG(age) as average_age FROM users'
);

// グループ化
const byAge = await connection.execute(`
  SELECT 
    CASE 
      WHEN age < 20 THEN '20歳未満'
      WHEN age < 30 THEN '20代'
      WHEN age < 40 THEN '30代'
      ELSE '40歳以上'
    END as age_group,
    COUNT(*) as count
  FROM users
  GROUP BY age_group
`);

データの更新

単一行の更新

javascript
await connection.execute(
  'UPDATE users SET age = ? WHERE id = ?',
  [31, 1]
);

複数行の更新

javascript
// 条件に一致するすべての行を更新
await connection.execute(
  'UPDATE users SET status = ? WHERE age >= ?',
  ['adult', 20]
);

データの削除

単一行の削除

javascript
await connection.execute(
  'DELETE FROM users WHERE id = ?',
  [1]
);

条件付き削除

javascript
await connection.execute(
  'DELETE FROM users WHERE created_at < ?',
  ['2023-01-01']
);

すべての行を削除

javascript
// テーブル構造は残す
await connection.execute('DELETE FROM users');

// より高速(テーブル構造も削除)
await connection.execute('DROP TABLE users');

JOINの使用

内部結合(INNER JOIN)

javascript
await connection.execute(`
  CREATE TABLE orders (
    id INTEGER PRIMARY KEY,
    user_id INTEGER,
    product VARCHAR,
    amount DECIMAL(10,2)
  )
`);

const result = await connection.execute(`
  SELECT 
    u.name,
    o.product,
    o.amount
  FROM users u
  INNER JOIN orders o ON u.id = o.user_id
`);

左外部結合(LEFT JOIN)

javascript
const result = await connection.execute(`
  SELECT 
    u.name,
    COUNT(o.id) as order_count
  FROM users u
  LEFT JOIN orders o ON u.id = o.user_id
  GROUP BY u.id, u.name
`);

トランザクション

複数の操作をアトミックに実行:

javascript
try {
  await connection.execute('BEGIN TRANSACTION');
  
  // ユーザーを作成
  await connection.execute(
    'INSERT INTO users (name, email) VALUES (?, ?)',
    ['新規ユーザー', 'new@example.com']
  );
  
  // 注文を作成
  await connection.execute(
    'INSERT INTO orders (user_id, product, amount) VALUES (?, ?, ?)',
    [1, '商品A', 1000]
  );
  
  await connection.execute('COMMIT');
  console.log('トランザクション成功');
} catch (error) {
  await connection.execute('ROLLBACK');
  console.error('トランザクション失敗:', error);
}

フレームワーク別の使用例

React - useQueryフック

jsx
function UserList() {
  const { data, loading, error, refetch } = useQuery(
    'SELECT * FROM users ORDER BY name'
  );

  if (loading) return <div>読み込み中...</div>;
  if (error) return <div>エラー: {error.message}</div>;

  return (
    <div>
      <button onClick={refetch}>更新</button>
      <ul>
        {data?.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
}

Vue - useQuery コンポジション

vue
<template>
  <div>
    <button @click="refetch">更新</button>
    <ul>
      <li v-for="user in data" :key="user.id">
        {{ user.name }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { useQuery } from '@northprint/duckdb-wasm-adapter-vue';

const { data, loading, error, refetch } = useQuery(
  'SELECT * FROM users ORDER BY name'
);
</script>

Svelte - リアクティブクエリ

svelte
<script>
  import { createDuckDB } from '@northprint/duckdb-wasm-adapter-svelte';
  
  const db = createDuckDB({ autoConnect: true });
  $: users = db.query('SELECT * FROM users ORDER BY name');
  
  function refresh() {
    users.refresh();
  }
</script>

<button on:click={refresh}>更新</button>
<ul>
  {#each $users.data as user}
    <li>{user.name}</li>
  {/each}
</ul>

エラー処理

適切なエラー処理でアプリケーションの安定性を向上:

javascript
import { DuckDBError, ErrorCode } from '@northprint/duckdb-wasm-adapter-core';

async function safeQuery(sql, params) {
  try {
    const result = await connection.execute(sql, params);
    return { success: true, data: result.toArray() };
  } catch (error) {
    if (error instanceof DuckDBError) {
      switch (error.code) {
        case ErrorCode.QUERY_FAILED:
          console.error('クエリエラー:', error.message);
          return { success: false, error: 'クエリの実行に失敗しました' };
        
        case ErrorCode.NOT_CONNECTED:
          console.error('接続エラー');
          return { success: false, error: 'データベースに接続されていません' };
        
        default:
          console.error('不明なエラー:', error);
          return { success: false, error: '予期しないエラーが発生しました' };
      }
    }
    throw error;
  }
}

パフォーマンスの最適化

インデックスの作成

javascript
// インデックスを作成して検索を高速化
await connection.execute('CREATE INDEX idx_users_email ON users(email)');
await connection.execute('CREATE INDEX idx_users_age ON users(age)');

EXPLAIN文の使用

javascript
// クエリプランを確認
const plan = await connection.execute(
  'EXPLAIN SELECT * FROM users WHERE email = ?',
  ['test@example.com']
);
console.log(plan.toArray());

適切なデータ型の選択

javascript
// 効率的なテーブル設計
await connection.execute(`
  CREATE TABLE optimized_users (
    id INTEGER PRIMARY KEY,
    name VARCHAR(100),        -- 最大長を指定
    age TINYINT,             -- 小さい整数にはTINYINT
    is_active BOOLEAN,        -- フラグにはBOOLEAN
    created_at TIMESTAMP      -- 日時にはTIMESTAMP
  )
`);

次のステップ

Released under the MIT License.