[Python]NotionAPIのORMっぽいライブラリを作ってみた

Notion API ORMは、Notion APIを簡単に使用するためのPythonライブラリです。このライブラリを使用することで、NotionのデータベースをPythonオブジェクトとして扱うことができ、データベース操作を簡素化することができます。

## 主な機能

- Notionデータベースレコードの作成、読み取り、更新、削除
- Pythonクラスを使用したデータベーススキーマの定義
- データベーススキーマの自動マイグレーション
- データベースレコードのフィルタリングとクエリ
- 様々なフィールドタイプのサポート: CharField, IntegerField, SelectField, MultiSelectField, DateField, BoolField

## インストール

GitHubリポジトリから直接インストールできます：

```bash
pip install git+https://github.com/yuki5155/notion-api.git
```

## 1. モデルの定義

モデルは、Notionのデータベースの構造を表現するPythonクラスです。`notion_api.orm.models.Model`を継承して作成します。各フィールドは、Notionのデータベースの列に対応します。

### クラス定義

```python
from notion_api.orm import models

class TestModel(models.Model):
    # フィールド定義
    ...

    @classmethod
    def table_name(cls):
        return "MyTestTable"
```

### テーブル名の指定

`table_name`メソッドは、Notionに作成されるデータベースの名前を指定します。このメソッドをオーバーライドしないと、デフォルトのテーブル名が使用されます。

```python
@classmethod
def table_name(cls):
    return "MyTestTable"
```

この例では、Notionに"MyTestTable"という名前のデータベースが作成されます。

### フィールドの定義

各フィールドは、Notionのデータベースの列に対応します。利用可能なフィールドタイプは以下の通りです：

1. **CharField**:
   ```python
   username = models.CharField("Username", max_length=1000, is_required=True)
   ```
   - `"Username"`: Notionでの列名
   - `max_length`: 最大文字数
   - `is_required`: 必須フィールドかどうか

2. **IntegerField**:
   ```python
   number = models.IntegerField("Number", is_required=True)
   ```
   - `"Number"`: Notionでの列名
   - `is_required`: 必須フィールドかどうか

3. **SelectField**:
   ```python
   selects = models.SelectField(
       "Selects",
       [
           models.SelectField.option("a"),
           models.SelectField.option("b"),
           models.SelectField.option("c"),
       ],
       is_required=True,
   )
   ```
   - `"Selects"`: Notionでの列名
   - 第2引数: 選択肢のリスト
   - `is_required`: 必須フィールドかどうか

4. **MultiSelectField**:
   ```python
   multi_selects = models.MultiSelectField(
       "MultiSelects",
       [
           models.MultiSelectField.option("x"),
           models.MultiSelectField.option("y"),
           models.MultiSelectField.option("z"),
       ],
       is_required=False,
   )
   ```
   - `"MultiSelects"`: Notionでの列名
   - 第2引数: 選択肢のリスト
   - `is_required`: 必須フィールドかどうか

5. **DateField**:
   ```python
   date_field = models.DateField("DateField", is_required=False)
   ```
   - `"DateField"`: Notionでの列名
   - `is_required`: 必須フィールドかどうか

6. **BoolField**:
   ```python
   bool_field = models.BoolField("BoolField", is_required=False)
   ```
   - `"BoolField"`: Notionでの列名
   - `is_required`: 必須フィールドかどうか

### 注意点

- フィールド名（例：`username`, `number`）はPythonでの変数名として使用されます。
- `"Username"`, `"Number"`などの文字列は、Notionデータベースでの実際の列名として表示されます。
- `is_required=True`を指定すると、そのフィールドは必須となり、値が設定されていない場合にエラーが発生します。

このようにモデルを定義することで、NotionのデータベースとPythonオブジェクトを簡単にマッピングでき、直感的なデータ操作が可能になります。

### 2. モデルのマイグレーション

```python
migration_result = TestModel.migrate(parent_id="your_notion_page_id")
database_id = migration_result["database_id"]
```

### 3. 新しいレコードの作成

```python
new_record = TestModel(
    username="john_doe",
    number=42,
    selects="a",
    multi_selects=["x", "y"],
    date_field="2023-05-01",
    bool_field=True
)
new_record.save(database_id)
```

### 4. レコードのクエリ

```python
# レコードのフィルタリング
filtered_records = TestModel.filter(
    database_id,
    username={"contains": "john"},
    number={"greater_than": 40}
)

# OR条件でのフィルタリング
or_filtered_records = TestModel.filter(
    database_id,
    _operator="or",
    number={"greater_than": 50},
    selects={"equals": "a"}
)
```

### 5. レコードの更新

```python
record_to_update = filtered_records[0]
record_to_update.number = 99
record_to_update.update(database_id)
```

### 6. レコードの削除

```python
record_to_delete = filtered_records[0]
record_to_delete.delete()
```

## 高度な使用方法

### カスタムフィルタリング

各フィールドタイプに対して様々なフィルタリング条件を使用できます：

- CharField: equals, does_not_equal, contains, does_not_contain, starts_with, ends_with
- IntegerField: equals, does_not_equal, greater_than, less_than, greater_than_or_equal_to, less_than_or_equal_to
- SelectField: equals, does_not_equal, is_empty, is_not_empty
- MultiSelectField: contains, does_not_contain, is_empty, is_not_empty
- DateField: equals, before, after, on_or_before, on_or_after, is_empty, is_not_empty
- BoolField: equals, does_not_equal

例：
```python
complex_filter = TestModel.filter(
    database_id,
    username={"starts_with": "j"},
    number={"greater_than_or_equal_to": 10, "less_than": 50},
    date_field={"after": "2023-01-01", "before": "2023-12-31"}
)
```

## まとめ

Notion API ORMを使用することで、NotionデータベースをPythonオブジェクトとして簡単に操作できます。モデルの定義、マイグレーション、CRUD操作、そして高度なフィルタリングまで、直感的なインターフェースを提供しています。このライブラリを活用することで、NotionとPythonの統合がよりスムーズになり、効率的なデータ管理が可能になります。