Tengチート

# 概要
tengのSQL書き方は、SQL::Maker::Conditionを踏襲しているようです。
https://metacpan.org/pod/SQL::Maker::Condition

※pluginのlookupだと、使えない条件指定が多い(特に{}を使う条件)ため、その場合はsingleを使ってください。


## 初期化

```perl
use Teng;
use Teng::Schema::Loader;

my $teng = Teng::Schema::Loader->load(
    connect_info => ['dbi:mysql:dbname=myapp', 'username', 'password'],
    namespace => 'MyApp::DB',
);
```

## 基本的なCRUD操作

### Create (挿入)

```perl
my $row = $teng->insert('table_name', {
    column1 => 'value1',
    column2 => 'value2',
});
```

### Read (検索)

単一行の取得:
```perl
my $row = $teng->single('table_name', { id => 1 });
```

複数行の取得:
```perl
my @rows = $teng->search('table_name', { status => 'active' });
```

### Update (更新)

```perl
$teng->update('table_name', 
    { column1 => 'new_value' },  # 更新するカラムと値
    { id => 1 }                  # WHERE 条件
);
```

### Delete (削除)

```perl
$teng->delete('table_name', { id => 1 });
```

## 高度なクエリ

### IN句

```perl
my @rows = $teng->search('table_name', {
    status => { 'IN' => ['active', 'pending'] }
});
```

### LIKE句

```perl
my @rows = $teng->search('table_name', {
    name => { 'LIKE' => '%John%' }
});
```

### AND条件

```perl
# -and を使用する場合（明示的）
my @rows = $teng->search('table_name', {
    -and => [
        status => 'active',
        age => { '>' => 18 }
    ]
});

# -and を省略する場合（暗黙的）
my @rows = $teng->search('table_name', {
    status => 'active',
    age => { '>' => 18 }
});
```

注: Tengでは、-andキーワードは多くの場合省略可能です。複数の条件を単純にハッシュとして列挙すると、暗黙的にAND条件として扱われます。ただし、より複雑な条件やORとの組み合わせを使用する場合は、明示的に-andを使用すると可読性が向上することがあります。

### OR条件

```perl
my @rows = $teng->search('table_name', {
    -or => [
        status => 'active',
        status => 'pending'
    ]
});
```
### NOT EQUAL条件 (<>)

```perl
my @rows = $teng->search('table_name', {
    status => { '!=' => 'inactive' }
});
```


### 複合条件（AND, OR, NOT EQUALの組み合わせ）

```perl
# -and を使用する場合
my @rows = $teng->search('table_name', {
    -and => [
        status => { '!=' => 'deleted' },
        -or => [
            age => { '>' => 18 },
            has_parent_consent => 1
        ]
    ]
});

# トップレベルの-andを省略する場合
my @rows = $teng->search('table_name', {
    status => { '!=' => 'deleted' },
    -or => [
        age => { '>' => 18 },
        has_parent_consent => 1
    ]
});
```

この例では、statusが'deleted'ではなく、かつ（年齢が18歳より上、または親の同意がある）レコードを検索しています。トップレベルの-andは省略可能ですが、内部の-orは明示的に指定する必要があります。



### ORDER BY

```perl
my @rows = $teng->search('table_name', 
    { status => 'active' },
    { order_by => 'created_at DESC' }
);
```


### LIMIT と OFFSET

```perl
my @rows = $teng->search('table_name', 
    {},
    { limit => 10, offset => 20 }
);
```

## トランザクション

```perl
$teng->txn_begin;
eval {
    $teng->insert('table1', { ... });
    $teng->update('table2', { ... }, { ... });
    $teng->txn_commit;
};
if ($@) {
    $teng->txn_rollback;
}
```

## カスタムSQLの実行

```perl
my $itr = $teng->search_by_sql(q{
    SELECT * FROM table_name WHERE column1 = ? AND column2 = ?
}, ['value1', 'value2']);
```

## スキーマ情報の取得

```perl
my $table_info = $teng->schema->get_table('table_name');
```

## 関連テーブルの取得

```perl
my $row = $teng->single('users', { id => 1 });
my $related_rows = $row->cascade_fetch('posts');  # users.id = posts.user_id の関係を想定
```


## count
(例)

```pl
my $count = $teng->count('order_table', '*', +{import_user => $editor, is_deleted => 0, last_edit_at => undef});
```

## between
(例)

```pl
my $iter = $teng->search(attendance_tbl => +{attendance_date => +{between => [$begin_date, $end_date]}});
```

## bulk_insertについて

```pl
$teng->bulk_insert('webedi_tbl', \@csv_datas_for_insert);
```

bulk_insertは早いと思っていたけど、早くない。
ログを見ると、tengのbulk_insertはinsertしてからselect文を発行する仕様(SQLiteのみ？？)らしく、select文のぶんだけ遅くなってしまった。。

## iteratorで取得するか、配列で取得するか？（性能観点）
search()結果を取得するには、以下の2通りの方法がある。

1．iteratorで取得し、iterator->next()でループ処理
2．配列で取得し、ループ処理

1は取得は早いが、next()で回す回数が多いほど処理が遅くなる。
2は1に比べて取得は若干遅くなる(内部で配列に変換するため？)が、その後のループ処理は早い。

ゆえに、取得データが多ければ多いほど、2のほうが早くなると思われる。