> ## Documentation Index
> Fetch the complete documentation index at: https://docs.insforge.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 資料庫 SDK 參考

> 使用 InsForge TypeScript SDK 進行類型安全的資料庫操作

## 安裝

<CodeGroup>
  ```bash npm theme={null}
  npm install @insforge/sdk@latest
  ```

  ```bash yarn theme={null}
  yarn add @insforge/sdk@latest
  ```

  ```bash pnpm theme={null}
  pnpm add @insforge/sdk@latest
  ```
</CodeGroup>

```javascript theme={null}
import { createClient } from '@insforge/sdk';

const insforge = createClient({
  baseUrl: 'https://your-app.insforge.app',
  anonKey: 'your-anon-key'  // Optional: for public/unauthenticated requests
});
```

Find the anon key with `npx @insforge/cli secrets get ANON_KEY`, or in the dashboard: click **Install** and open **API Keys**.

## insert()

將新記錄插入表格中。

### 參數

* `values` (object | Array, required) - 要插入的資料。單個物件或陣列用於批量插入
* `options.count` ('exact' | 'planned' | 'estimated', optional) - 包含插入的列數

### 傳回

```typescript theme={null}
{
  data: Array<object> | null,
  error: Error | null,
  count?: number
}
```

<Note>
  在 `.insert()` 後鏈接 `.select()` 以傳回插入的資料
</Note>

### 範例

<CodeGroup>
  ```javascript Single insert theme={null}
  const { data, error } = await insforge.database
    .from('posts')
    .insert({ title: 'Hello World', content: 'My first post!' })
    .select()
  ```

  ```javascript Bulk insert theme={null}
  const { data, error } = await insforge.database
    .from('posts')
    .insert([
      { title: 'First Post', content: 'Hello everyone!' },
      { title: 'Second Post', content: 'Another update.' }
    ])
    .select()
  ```
</CodeGroup>

### 輸出範例

```json theme={null}
{
  "data": [
    { "id": "789", "title": "Hello World", "content": "My first post!", "created_at": "2024-01-15T10:30:00Z" }
  ],
  "error": null
}
```

***

## update()

更新表格中的現有記錄。必須使用篩選器來定位特定列。

### 參數

* `values` (object, required) - 要更新的欄位
* `options.count` ('exact' | 'planned' | 'estimated', optional) - 包含更新的列數

### 傳回

```typescript theme={null}
{
  data: Array<object> | null,
  error: Error | null,
  count?: number
}
```

<Warning>
  一律使用篩選器（如 `.eq()` 或 `.in()`）來指定要更新的列
</Warning>

### 範例

<CodeGroup>
  ```javascript Update by ID theme={null}
  const { data, error } = await insforge.database
    .from('posts')
    .update({ title: 'Updated Title' })
    .eq('id', postId)
    .select()
  ```

  ```javascript Update multiple theme={null}
  const { data, error } = await insforge.database
    .from('tasks')
    .update({ status: 'completed' })
    .in('id', ['task-1', 'task-2'])
    .select()
  ```
</CodeGroup>

### 輸出範例

```json theme={null}
{
  "data": [
    { "id": "123", "title": "Updated Title", "content": "My first post!", "updated_at": "2024-01-15T11:00:00Z" }
  ],
  "error": null
}
```

***

## delete()

從表格中刪除記錄。必須使用篩選器來定位特定列。

### 參數

* `options.count` ('exact' | 'planned' | 'estimated', optional) - 包含刪除的列數

### 傳回

```typescript theme={null}
{
  data: Array<object> | null,
  error: Error | null,
  count?: number
}
```

<Warning>
  一律使用篩選器來指定要刪除的列
</Warning>

### 範例

<CodeGroup>
  ```javascript Delete by ID theme={null}
  const { error } = await insforge.database
    .from('posts')
    .delete()
    .eq('id', postId)
  ```

  ```javascript Delete with filter theme={null}
  const { error } = await insforge.database
    .from('sessions')
    .delete()
    .lt('expires_at', new Date())
  ```
</CodeGroup>

### 輸出範例

```json theme={null}
{
  "data": null,
  "error": null
}
```

***

## select()

從表格或檢視中查詢記錄。

### 參數

* `columns` (string, optional) - 逗號分隔的欄位名稱。使用 `*` 表示所有欄位
* `options.count` ('exact' | 'planned' | 'estimated', optional) - 包含總列數
* `options.head` (boolean, optional) - 僅傳回計數，不傳回資料

### 傳回

```typescript theme={null}
{
  data: Array<object> | null,
  error: Error | null,
  count?: number
}
```

### 範例

<CodeGroup>
  ```javascript Get all theme={null}
  const { data, error } = await insforge.database
    .from('posts')
    .select()
  ```

  ```javascript Specific columns theme={null}
  const { data, error } = await insforge.database
    .from('posts')
    .select('id, title, content')
  ```

  ```javascript With relationships theme={null}
  const { data, error } = await insforge.database
    .from('posts')
    .select('*, comments(id, content)')
  ```
</CodeGroup>

### 輸出範例

```json theme={null}
{
  "data": [
    { "id": "123", "title": "Hello World", "content": "My first post!" },
    { "id": "456", "title": "Second Post", "content": "Another update." }
  ],
  "error": null
}
```

***

## rpc()

呼叫 PostgreSQL 預存函式（RPC - 遠端程序呼叫）。

### 參數

* `functionName` (string, required) - 要呼叫的 PostgreSQL 函數的名稱
* `args` (object, optional) - 傳遞給函數的引數

### 傳回

```typescript theme={null}
{
  data: T | T[] | null,
  error: Error | null
}
```

### 範例

<CodeGroup>
  ```javascript With parameters theme={null}
  const { data, error } = await insforge.database
    .rpc('get_user_stats', { user_id: '123' })
  ```

  ```javascript Without parameters theme={null}
  const { data, error } = await insforge.database
    .rpc('get_all_active_users')
  ```
</CodeGroup>

***

## 篩選器

鏈接篩選器以縮小查詢結果範圍。所有篩選器採用 `(column, value)` 作為參數。

| 篩選器                       | 描述                     | 範例                                     |
| ------------------------- | ---------------------- | -------------------------------------- |
| `.eq(column, value)`      | 等於                     | `.eq('status', 'active')`              |
| `.neq(column, value)`     | 不等於                    | `.neq('status', 'banned')`             |
| `.gt(column, value)`      | 大於                     | `.gt('age', 18)`                       |
| `.gte(column, value)`     | 大於或等於                  | `.gte('price', 100)`                   |
| `.lt(column, value)`      | 小於                     | `.lt('stock', 10)`                     |
| `.lte(column, value)`     | 小於或等於                  | `.lte('priority', 3)`                  |
| `.like(column, pattern)`  | 區分大小寫的模式（使用 `%` 萬用字元）  | `.like('name', '%Widget%')`            |
| `.ilike(column, pattern)` | 不區分大小寫的模式（使用 `%` 萬用字元） | `.ilike('email', '%@gmail.com')`       |
| `.in(column, array)`      | 值在陣列中                  | `.in('status', ['pending', 'active'])` |
| `.is(column, value)`      | 完全等於（用於 null 檢查）       | `.is('deleted_at', null)`              |

```javascript theme={null}
// Example: Chain multiple filters
const { data } = await insforge.database
  .from('products')
  .select()
  .eq('category', 'electronics')
  .gte('price', 50)
  .lte('price', 500)
  .is('in_stock', true)
```

***

## 修飾元

控制查詢結果的傳回方式。

| 修飾元                       | 描述                                                          | 範例                                           |
| ------------------------- | ----------------------------------------------------------- | -------------------------------------------- |
| `.order(column, options)` | 排序結果。選項：`{ ascending: true/false, nullsFirst: true/false }` | `.order('created_at', { ascending: false })` |
| `.limit(count)`           | 限制列數                                                        | `.limit(10)`                                 |
| `.range(from, to)`        | 取得索引之間的列（分頁）                                                | `.range(0, 9)`                               |
| `.single()`               | 傳回物件而不是陣列（如果有多個則擲回）                                         | `.single()`                                  |
| `.maybeSingle()`          | 傳回物件或 null（無錯誤）                                             | `.maybeSingle()`                             |

```javascript theme={null}
// Example: Pagination with sorting
const { data } = await insforge.database
  .from('posts')
  .select()
  .order('created_at', { ascending: false })
  .range(0, 9)
```

***

## 常見模式

### 帶計數的分頁

```javascript theme={null}
const page = 1;
const pageSize = 10;
const from = (page - 1) * pageSize;
const to = from + pageSize - 1;

const { data, count } = await insforge.database
  .from('posts')
  .select('*', { count: 'exact' })
  .range(from, to)
  .order('created_at', { ascending: false })

console.log(`Page ${page}: ${data.length} of ${count} total`)
```

**輸出：**

```json theme={null}
{
  "data": [
    { "id": "1", "title": "Post 1", "created_at": "2024-01-15T10:00:00Z" },
    { "id": "2", "title": "Post 2", "created_at": "2024-01-14T10:00:00Z" }
  ],
  "count": 50,
  "error": null
}
```

### 篩選搜尋

```javascript theme={null}
const { data } = await insforge.database
  .from('products')
  .select('id, name, price, category')
  .eq('category', 'electronics')
  .gte('price', 50)
  .lte('price', 500)
  .order('price', { ascending: true })
  .limit(20)
```

**輸出：**

```json theme={null}
{
  "data": [
    { "id": "101", "name": "USB Cable", "price": 59.99, "category": "electronics" },
    { "id": "102", "name": "Keyboard", "price": 89.99, "category": "electronics" }
  ],
  "error": null
}
```

### 與身分驗證掛勾結合使用

結合資料庫查詢與 `useUser()` 或 `useAuth()` 掛勾來取得使用者特定的資料：

```tsx theme={null}
import { useUser } from '@insforge/react'; // or '@insforge/react-router'
import { insforge } from './lib/insforge';
import { useEffect, useState } from 'react';

function MyProfile() {
  const { user, isLoaded } = useUser();
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    if (user) {
      // Fetch user's posts from database
      insforge.database
        .from('posts')
        .select('*')
        .eq('user_id', user.id)
        .then(({ data }) => setPosts(data));
    }
  }, [user]);

  if (!isLoaded) return <div>Loading...</div>;
  if (!user) return <div>Not signed in</div>;

  return (
    <div>
      <h1>{user.profile?.name}</h1>
      <p>{user.email}</p>
      <h2>My Posts: {posts.length}</h2>
      {posts.map(post => (
        <div key={post.id}>{post.title}</div>
      ))}
    </div>
  );
}
```

**關鍵要點：**

* 使用 `user.id` 為已認證使用者篩選資料
* 在存取 `user` 之前檢查 `isLoaded` 以避免競狀
* 檢查 `!user` 以處理未認證狀態
