ArrayQueryでオブジェクト配列をタイプセーフORMっぽく扱う

## ArrayQueryとは

[ArrayQuery](https://array-query.vercel.app/)は2024年7月18日にローンチされた、タイプセーフORMライクにオブジェクト配列を扱えるように設計された強力なTypeScriptライブラリです。

軽量でありながら機能豊富なライブラリで、オブジェクト配列に対して複雑な操作を簡単に実行できます。特に、メモリ内の大規模データセットを操作する際や、フロントエンドアプリケーションで高度なフィルタリング、並べ替え、ページネーションを実装する場合に便利です。

https://array-query.vercel.app/

## 主な特徴

- **ページネーション**: 大規模データセットを簡単にページ分割できます。
- **全文検索**: データ内の複数フィールドにわたる柔軟で強力な検索ができます。
- **高度なフィルタリング**: 複雑なフィルタを適用して正確なデータ取得ができます。
- **柔軟な並べ替え**: 昇順と降順の両方をサポートし、任意のフィールドでの並べ替えが可能です。
- **型安全な操作**: TypeScriptを活用して型安全なクエリとデータ操作を実行し、エラーを低減させます。エディタで補完も働くので快適に実装できます。
- **複雑なオブジェクトのフィルタリング**: ネストされたオブジェクトや配列を簡単にフィルタリングできます。
- **軽量かつ高速**: 最適化されたパフォーマンスでアプリケーションへのオーバーヘッドを最小限に抑えられます。

## ArrayQueryの活用シーン

- クライアント側アプリケーションで複雑なフィルタリングと並べ替えを実装する場合
- 大規模データセットを効率的にページ分割する場合
- 複数フィールドにわたる全文検索を実行する場合
- Webアプリケーションにデータテーブル機能を実装する場合

## 導入方法

npmやyarnなどを使用してプロジェクトへパッケージをインストールします。

```bash
npm install @chronicstone/array-query
```

## 基本的な使い方

query関数を使用してオブジェクト配列の操作を行います。
sortのkeyは補完が働くので、対象オブジェクトのフィールド名から選択することができます。また、型安全なので存在しないフィールド名を入力するとエラーとなります。

```ts
import { query } from '@chronicstone/array-query'

const data = [
  { id: 1, name: 'John Doe', age: 30 },
  { id: 2, name: 'Jane Smith', age: 25 },
  { id: 3, name: 'Bob Johnson', age: 35 }
  ...
]

// ageフィールドを昇順でソートして、上限10件を取得
const result = query(data, {
  limit: 10,
  sort: { key: 'age', dir: 'asc' },
})
```

## フィルタリング

複数の条件を指定してフィルタリングすることができます。
階層化されているオブジェクトも条件に含めることができます。
個人的にはmatchModeに指定する値は「=」や「>=」などの等号・不等号を文字列でも指定できたほうがわかりやすいと思いました。

```ts
const employees = [
  { id: 1, name: 'Alice', age: 30, department: { name: 'IT', location: 'New York' } },
  { id: 2, name: 'Bob', age: 25, department: { name: 'HR', location: 'London' } }
];

const result = query(employees, {
  filter: [
    { key: 'age', matchMode: 'greaterThan', value: 25 },
    { key: 'name', matchMode: 'exists', value: 'A' }
    { key: 'department.name', matchMode: 'equals', value: 'IT' }
  ]
})
```

## ソート

ソート条件も複数指定することが可能で、数値だけではなく文字列も対象にすることができます。

```ts
const result = query(data, {
  sort: [
    { key: 'name', dir: 'desc' },
    { key: 'age', dir: 'asc' }
  ]
});
```

## ページネーション

ページネーションはpageとlimitの2つのパラメータで提供されるシンプルな仕様になっています。一般的なページネーションコンポーネントのインタフェースとも相性が良さそうです。

```ts
const data = [
  { id: 1, name: 'Item 1' },
  { id: 2, name: 'Item 2' },
  { id: 3, name: 'Item 3' },
  { id: 4, name: 'Item 4' },
  { id: 5, name: 'Item 5' }
];

const result = query(data, {
  page: 2,
  limit: 2
});
```

## 全文検索

ArrayQueryには強力な検索機能があり、深くネストされたフィールドや配列フィールドなど、データ内の複数のフィールドにわたって全文検索を実行できます。

```ts
const data = [
  {
    id: 1,
    name: 'John Doe',
    contact: {
      email: 'john@example.com',
      address: {
        city: 'New York',
        country: 'USA'
      }
    },
    specialties: ['developer', 'javascript', 'typescript']
  },
  {
    id: 2,
    name: 'Jane Smith',
    contact: {
      email: 'jane@example.com',
      address: {
        city: 'London',
        country: 'UK'
      }
    },
    specialties: ['manager', 'agile', 'scrum']
  }
];

const result = query(data, {
  search: {
    value: 'New York',
    keys: ['contact.address.city']
  }
});
```

他にも大文字・小文字の区別や配列内の検索などにも対応しています。
残念ながら複数の条件を一度に実行することはできないようなので、そのようなケースの場合は結果の配列に対して改めて全文検索する必要があります。（AND検索限定）

## まとめ

ArrayQuery実際に使用してみて、使い慣れたORMのような感覚でオブジェクト配列を操作するのはとても良い体験でした。型安全性により、コードの信頼性が向上し、補完機能を活用することで実装効率の向上が見込めると思います。
今回はベンチマークまでは行いませんでしたが、大規模データセットでも高速に処理できるようです。ぜひプロジェクトで採用してみてはいかがでしょうか。

## 参考

https://array-query.vercel.app/