charm/recordset

一个用于过滤和排序来自不同数据源(如数据库表、数组、API 或 CSV 文件)的数据行的库。

0.0.2 2022-03-05 23:29 UTC

This package is auto-updated.

Last update: 2024-09-06 04:49:32 UTC


README

Charm/Recordset 是一个库,允许您使用几个不同的强大查询 API 从任何数据源定义数据集合。

功能

  • 将任何数据源发布为具有分页、排序和过滤功能的 REST API。
  • 使用标准 SQL(包括 JOIN)查询和连接这些数据源。
  • 支持的数据源
    • PDO 数据库查询
    • Sqlite3 数据库表
    • CSV 文件
    • PHP 数组、生成器和迭代器
    • 其他 REST API
    • 自定义数据源适配器
  • 完全支持 UTF,并带有区域设置排序。

通过单个 API 提供数据,无论数据存储在 CSV 文件、远程 API 或是由生成数据构建。

例如;此 API 允许您执行以下 SQL 查询的等效操作

  • SELECT * FROM ./countries.csv ORDER BY latitude
  • SELECT value FROM positive_integers WHERE value < 10
  • SELECT value FROM all_integers WHERE value > -10 AND value < 10

以上示例只需实现每个表的后端。

TLDR

您可以通过简单的查询 API 提供所有数据,而不是创建各种方法来获取特定类的对象

您可以通过强大的和可预测的查询 API 使用户使用,而不是创建大量的类方法,如 getByUserId(int $userId)getByFirstName(string $name)

    // $user = $users->getById(123);

    // one of three approaches
    $user = $users->eq('id', 123)->first();         // low level API
    $user = $users->where('id=123')->first();       // query string API
    $user = $users->where('id=?', 123)->first();    // query string API with bound and typed columns

这种方法在多个领域带来巨大好处

  • 自动支持更强大的查询:'users where gender = "male" and registered_ts > 123'

  • 更高的安全性;记录集可以在后端“预先过滤”,因此消费者只能查询有限子集的行。

  • 能够在不更新后端适配器的情况下替换后端。

  • 基于文件的后端可以使用版本控制系统更新,而不是通过数据库迁移。

  • 记录集可以作为基于查询字符串过滤的 REST API 集合公开。

后端必须实现 Charm\Recordset\RecordsetInterface。实现此接口的最简单方法是扩展 Charm\Recordset\AbstractRecordset

对于 CSV 文件、PDO 数据库表、数组和生成器,有一些预先制作的后端可用。

下面将展示一些使用示例和 CSV 后端 Country 集合的简单实现。

查询

查询的最紧凑方法是使用 Recordset::query() 方法。

以下示例是等效的

foreach (Country::all()
    ->where('name[gt]=t&name[lt]=z&latitude[gte]=50&latitude[lte]=80&$order=-name')
    ->page(0,100) as $country) {

    echo $country->getCapital()."\n";
}

foreach (Country::all()         // fetch a recordset
    ->gt('name', 't')           // reduce the recordset to countries where name > 't'
    ->lt('name', 'z')           // and where name < '<'
    ->gte('latitude', 50)       // and where latitude >= 20
    ->lt('latitude', 80)        // and where latitude <= 80
    ->order('name', true)       // sort them in descending order by name
    ->page(0, 100)              // fetch the 100 first rows
    as
    $country) {
    
    echo $country->getCapital()."\n";
}

通过向记录集添加运算符表达式来执行查询。

$southernCountries = $countries->lt('latitude', 0);
$northernCountries = $countries->gte('latitude', 0);

请注意,记录集是不可变的。这意味着您可以使用运算符来限制对行的访问。

可以链式使用多个运算符

$countriesNearEquator = $countries->lt('latitude', 23.43)->gt('latitude', -23.43);

以下运算符受支持

运算符方法
=Recordset::eq($key, $value)
>Recordset::gt($key, $value)
>=Recordset::gte($key, $value)
<Recordset::lt($key, $value)
<=Recordset::lte($key, $value)
startsWith`Recordset::startsWith('name', 'n')

获取数据

从记录集中获取前 100 行

$iterator = $northernCountries->page(0, 100)

即使此请求需要 100 次后端 API 调用,对消费者来说也是不可见的。如果过滤是通过数据库引擎执行的,或者过滤是通过 PHP 代码执行的,这也是隐藏的。

迭代结果

要实际获取行,请使用 page 方法

foreach ($southernCountries->page(0, 100) as $country) {
    if ($country instanceof Country) {
        // This requires that the backend objects of this kind
    }
}

国家收藏

<?php
use Charm\Recordset\CSVRecordset;

class Country {
    public $code, name, $latitude, $longitude;

    protected function __construct(string $code, string $name, float $latitude, float $longitude) {
        $this->code = $code;
        $this->name = $name;
        $this->latitude = $latitude;
        $this->longitude = $longitude;
    }

    public static function all() {

        /**
         * It is quite simple to create a custom data provider, but
         * here we'll be using the CSVRecordset class.
         *
         * CSV file are not indexed, but there are ways to accelerate
         * this, for example by using a CachingRecordset or by
         * using a more powerful backend for your data.
         */
        return new CSVRecordset(
            // the filename where data is stored
            'countries.csv',

            // a function which will convert an array of arrays to an array of objects
            function(array $rows) {
                foreach ($rows as $i => $row) {
                    $rows[$i] = new Country($row[0], $row[3], $row[1], $row[2]);
                }
                return $rows;
            }
        });

    }
}

按关键字选择

<?php
// get a particular country
$norway = Country::all()->eq('name', 'Norway');

// get countries sorted by latitude
$countries = Country::all()->order('latitude');

// get countries sorted by name where latitude is greater than 70
$countries = Country::all()->gt('latitude', 70)->order('name');