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

# 编写约定

> 写错就报错的几条硬约束。

## 参数是位置参数，不是命名参数

Function 的参数**只能按位置传，不支持按名字传**。这是跨语言设计决定的——不同编程语言里只有位置参数是通用的，命名参数只有 Python / JS 等少数语言支持。

在 `Pipeline` / `Trigger` 里，用 `SOURCE_ROW` 占位符表示"这个位置传源表的那一行"：

```python theme={null}
from blockx import Trigger, SOURCE_ROW

Trigger(
    table="chain.trace.eth",
    func=to_transfer,
    params=[SOURCE_ROW, "eth"],   # 第一个参数是源表的行，第二个是固定值 "eth"
)

def to_transfer(record, chain_id):   # record 对应 SOURCE_ROW，chain_id 对应 "eth"
    ...
```

`record` 具体放在函数签名的第几个位置，由 `params` 里 `SOURCE_ROW` 的位置决定，不要求一定是第一个。

## 返回值必须能 JSON 序列化

返回一个 `dict`（会被写入目标表的一行），或者返回 `None`（这一行被丢弃）。返回值必须是可以序列化成 JSON 的普通值——不能返回自定义对象、不能返回不可序列化的类型。

```python theme={null}
def to_transfer(record, chain_id):
    return {
        "id": record["id"],
        "value": float(record["value"]),   # ✅ 普通类型
        "seen_at": datetime.now(),          # ❌ datetime 不能直接序列化，先转成字符串
    }
```

## Notebook 里可以直接写 def，不需要额外声明

传给 `Trigger(func=...)` 的可以就是一个普通的 Python `def`——SDK 会自动抓取它的源码发给 worker，你不需要额外注册或声明。

```python theme={null}
def to_transfer(record, chain_id):
    ...

Trigger(table="chain.trace.eth", func=to_transfer, params=[SOURCE_ROW, "eth"])
```

<Note>
  worker 侧实际的函数入口名固定为 `_`，SDK 会自动帮你处理这层别名映射，你不用关心。
</Note>
