xtompie / aql

数组查询语言 - 使用数组构建 SQL

5.1.1 2024-09-05 09:23 UTC

This package is auto-updated.

Last update: 2024-09-05 09:26:16 UTC


README

使用数组绑定构建 SQL 预处理语句

use Xtompie\Aql\Aql;
use Xtompie\Aql\MySQLPlatform;

$aql = new Aql(
    platform: new MySQLPlatform(),
);
$result = $aql([
    'select' => '*',
    'from' => 'order',
    'where' => [
        'status' => 'active',
    ],
    'limit' => 3,
]);
$result->sql(); // 'SELECT * FROM `order` WHERE status = ? LIMIT 3'
$result->binds(); // ['active']
$result->toArray(); // ['SELECT * FROM `order` WHERE status = ? LIMIT 3', ['active']]

需求

PHP >= 8.0

安装

使用 composer

composer require xtompie/aql

文档

API

选择

$aql(['select' => 'post_id', 'title' => 'post_title'])->toArray();
// ["SELECT post_id, post_title as 'title'", []];

$aql(['select' => 'post_id, post_title as title'])->toArray();
// ['SELECT post_id, post_title as title', []];

$aql(['select' => '|x' => '|COUNT(*)'])->toArray();
// ['SELECT COUNT(*) as x', []];

键或值的开头可以指定 | 字符来使用原始 SQL 片段

前缀

$aql(['prefix' => 'SQL_NO_CACHE DISTINCT'])->toArray();
// ['SELECT SQL_NO_CACHE DISTINCT', []];

$aql(['from' => 'user'])->toArray();
// ['FROM user', []];

$aql(['from' => ['u' => 'user']])->toArray();
// ['FROM user as u', []];

$aql(['from' => 'order'])->toArray();
// ['FROM `order`', []];

关键字有引号。

连接

$aql([
    'join' => [
        'JOIN author ON (author_id = post_id_author)',
        'LEFT JOIN img ON (author_id_img = img_id)'
    ]
])->toArray();
// ['JOIN author ON (author_id = post_id_author) LEFT JOIN img ON (author_id_img = img_id)"]

分组

$aql(['group' => 'post_id'])->toArray();
// ['GROUP post_id', []];

分组条件

$aql(['having' => 'post_id > 0'])->toArray();
// ['HAVING post_id > 0', []];

$aql(['having' => ['post_id >' => '0']])->toArray();
// ['HAVING post_id > ?', [0]];

条件数组可以设置为 having。它表现得像 where 条件。见 Where

排序

$aql(['order' => 'created_at DESC'])->toArray();
// ['ORDER BY created_at DESC', []];

排序是原始 SQL 片段。

限制

$aql(['limit' => '10'])->toArray();
// ['LIMIT ?', [10]];

限制被转换为整数。

偏移量

$aql(['offset' => '20'])->toArray();
// ['OFFSET ?', [20]];

偏移量被转换为整数。

条件

字符串键
$aql([
    'where' => [
        'a' => 'a',
        'b' => ['b1', 'b2', 'b3'],
        'c BETWEEN' => [2, 5],
        'd <>' => 'd1',
        'e LIKE' => '%e1%',
        'f:gt' => 9,
    ]
])
    ->toArray()
;
// [
//    'WHERE a = ? AND b IN (?, ?, ?) AND c BETWEEN ? AND ? AND d <> ? AND e LIKE ? AND f > ?',
//    ['a', 'b1', 'b2', 'b3', 2, 5, 'd1', '%e1%', 9]
// ];

当条件键是字符串时,期望是列名,可选的比较运算符。比较运算符在第一个空格或 : 字符之后期望。可用的比较运算符是所有有效的 SQL 比较运算符以及额外的

eq=gt>ge>=lt<le<=notneq!=likeLIKEinINnotinNOT INbetweenBETWEENnotbetweenNOT BETWEEN

键的开头可以指定 | 字符来使用原始 SQL 片段。

默认所有条件的逻辑运算符是 AND。逻辑运算符可以通过 :operator 键进行更改。

$aql([
    'where' => [
        'a' => 'a',
        'b' => 'b',
        ':operator' => 'OR',
    ]
])
    ->toArray()
;
// [
//    'WHERE a = ? OR b = ?',
//    ['a', 'bb']
// ];
整数键和字符串值
$aql(['where' => ['category_id IS NOT NULL']])->toArray();
// ['WHERE category_id IS NOT NULL', []];
整数键和数组值
$aql([
    'where' => [
        'a' => 'aa',
        [
            'b' => 'bb',
            'c' => 'cc',
            ':operator' => 'OR',
        ]
    ]
])->toArray();
// ['WHERE a = ? AND (b = ? OR c = ?)', ['aa', 'bb', 'cc]];

插入

$aql([
    'insert' => 'order',
    'values' => [
        'order' => 1,
        '|time' => 'NOW()',
    ]
])->toArray();
// ['INSERT INTO `order` (`order`, time) VALUES (?, NOW())', [1]];

平台

内置支持的平台

  • Xtompie/Aql/MySQLPlatform,
  • Xtompie/Aql/PostgreSQLPlatform.
  • Xtompie/Aql/SQLitePlatform.

使用 PostgreSQL

use Xtompie/Aql/Aql;
use Xtompie/Aql/PostgreSQLPlatform;

(new Aql(platform: new PostgreSQLPlatform()))([
    'SELECT' => '*',
    'FROM' => 'order'
])->toArray();
// ['SELECT * FROM "order"', []];

扩展

通过装饰

<?php

namespace App\Shared\Database;

use Xtompie\Aql\Aql as BaseAql;
use Xtompie\Aql\Result;

interface Paging
{
    public function limit(): int;
    public function offset(): int;
}

class Aql
{
    public function __construct(
        protected BaseAql $aql,
    ) {}

    public function __invoke(array $aql): Result
    {
        if (isset($aql['paging'])) {
            $paging = $aql['paging'];
            if (!$paging instanceof Paging) {
                throw new \Exception();
            }
            $aql['offset'] => $paging->offset();
            $aql['limit'] => $paging->limit();
            unset($aql['paging']);
        }
        return ($this->aql)($aql);
    }
}