emsifa / laci
PHP JSON 平面文件数据库管理系统
Requires (Dev)
- phpunit/phpunit: 4.*
README
概述
LaciDB 是一个以 JSON 格式存储的平面文件数据库管理系统。由于 JSON 格式,LaciDB 类似于其他 NoSQL 数据库,具有无模式(schemaless)的特性。一个记录可以有不同的列。
在 LaciDB 中没有表的概念,而是集合(collection)。LaciDB 中的集合代表一个存储许多记录(格式为 JSON)的文件。
“Laci”这个名字来源于其功能和流程类似于桌面的抽屉。抽屉通常不需要钥匙(认证),只需打开 > 拿东西或 > 放东西 > 关上。在 LaciDB 中也是如此,每个查询都会打开文件 > 执行查询(select|insert|update|delete) > 关闭文件。Laci 也像我们知道的,是用来存放小物品的地方。不是像仓库或柜子那样的大件物品。
因此,LaciDB 适用于
- 存储大量数据的数据库。
- 需要高安全级别的数据库。
LaciDB 是为以下用途而设计的
- 处理小的数据,如设置或其他小数据。
- 为需要易于导入/导出和备份的便携式数据库。
- 为需要易于自行编辑的数据库,无需使用专用软件。记事本也可以。
工作原理
LaciDB 的工作原理基本上是将 json_decode 的结果流过一系列“管道”,这些管道用于 过滤、映射、排序、限制,最终执行以获取值、更改值或删除值。
以下是对其过程的说明
过滤
要执行过滤,您可以使用 where 和 orWhere 方法。这两个方法可以接受 Closure 参数或 key、operator、value 参数。
映射
映射用于在已过滤的每个记录上形成新值。
以下是一些映射记录的方法
map(Closure $mapper)
用于对已过滤的集合进行映射。
select(array $columns)
用于仅映射记录的某些列。
withOne(Collection|Query $relation, $key, $otherKey, $operator, $thisKey)
用于获取 1:1 关系。
withMany(Collection|Query $relation, $key, $otherKey, $operator, $thisKey)
用于获取 1:n 关系。
排序
排序用于对已过滤和映射的数据进行排序。要进行排序,您可以使用 sortBy($key, $ascending) 方法。参数 $key 可以是字符串 key/列,用于排序,或者 Closure,用于根据预先计算出的值进行排序。
限制/取值
在数据过滤、映射和排序完成后,您可以使用 skip($offset) 或 take($limit, $offset) 方法剪切和获取部分数据。
执行
在过滤、映射、排序和剪切后,下一步是执行结果。
以下是一些执行方法
get(array $columns = null)
获取集合中的记录集合。如果需要获取特定列,请在 $columns 数组中定义列。
first(array $columns = null)
获取集合中的一个(或多个)记录。如果需要获取特定列,请在 $columns 数组中定义列。
count()
获取集合中的数据量。
sum($key)
获取集合中特定键的总和。
avg($key)
从集合中获取特定键的平均值。
min($key)
从集合中的特定键获取最小值。
max($key)
从集合中的特定键获取最大值。
lists($key, $resultKey = null)
将集合中的特定键收集到数组中。
insert(array $data)
将新数据插入集合。
inserts(array $listData)
一次性将多个新数据插入集合。注意:在过滤或映射查询后,不能使用insert和inserts。
update(array $newData)
更新集合中经过过滤和映射的记录的数据。
save()
与update相同。只是save会根据映射结果保存记录,而不是像update那样根据$newData。
delete()
删除集合中经过过滤和映射的数据。
truncate()
删除所有数据。不需要事先进行过滤和映射。
示例
初始化
use Emsifa\Laci\Collection; require 'vendor/autoload.php'; $collection = new Collection(__DIR__.'/users.json');
插入数据
$user = $collection->insert([ 'name' => 'John Doe', 'email' => 'johndoe@mail.com', 'password' => password_hash('password', PASSWORD_BCRYPT) ]);
$user
将是一个如下所示的数组
[ '_id' => '58745c13ad585', 'name' => 'John Doe', 'email' => 'johndoe@mail.com', 'password' => '$2y$10$eMF03850wE6uII7UeujyjOU5Q2XLWz0QEZ1A9yiKPjbo3sA4qYh1m' ]
'_id'是
uniqid()
通过ID查找单个记录
$user = $collection->find('58745c13ad585');
查找单个
$user = $collection->where('email', 'johndoe@mail.com')->first();
选择所有
$data = $collection->all();
更新
$collection->where('email', 'johndoe@mail.com')->update([ 'name' => 'John', 'sex' => 'male' ]);
返回受影响记录的计数
删除
$collection->where('email', 'johndoe@mail.com')->delete();
返回受影响记录的计数
多次插入
$bookCollection = new Collection('db/books.json'); $bookCollection->inserts([ [ 'title' => 'Foobar', 'published_at' => '2016-02-23', 'author' => [ 'name' => 'John Doe', 'email' => 'johndoe@mail.com' ], 'star' => 3, 'views' => 100 ], [ 'title' => 'Bazqux', 'published_at' => '2014-01-10', 'author' => [ 'name' => 'Jane Doe', 'email' => 'janedoe@mail.com' ], 'star' => 5, 'views' => 56 ], [ 'title' => 'Lorem Ipsum', 'published_at' => '2013-05-12', 'author' => [ 'name' => 'Jane Doe', 'email' => 'janedoe@mail.com' ], 'star' => 4, 'views' => 96 ], ]);
查找条件
// select * from books.json where author[name] = 'Jane Doe' $bookCollection->where('author.name', 'Jane Doe')->get(); // select * from books.json where star > 3 $bookCollection->where('star', '>', 3)->get(); // select * from books.json where star > 3 AND author[name] = 'Jane Doe' $bookCollection->where('star', '>', 3)->where('author.name', 'Jane Doe')->get(); // select * from books.json where star > 3 OR author[name] = 'Jane Doe' $bookCollection->where('star', '>', 3)->orWhere('author.name', 'Jane Doe')->get(); // select * from books.json where (star > 3 OR author[name] = 'Jane Doe') $bookCollection->where(function($book) { return $book['star'] > 3 OR $book['author.name'] == 'Jane Doe'; })->get();
操作符可以是'=', '<', '<=', '>', '>=', 'in', 'not in', 'between', 'match'。
获取特定列/键
// select author, title from books.json where star > 3 $bookCollection->where('star', '>', 3)->get(['author.name', 'title']);
列/键别名
// select author[name] as author_name, title from books.json where star > 3 $bookCollection->where('star', '>', 3)->get(['author.name:author_name', 'title']);
映射
$bookCollection->map(function($row) { $row['score'] = $row['star'] + $row['views']; return $row; }) ->sortBy('score', 'desc') ->get();
排序
// select * from books.json order by star asc $bookCollection->sortBy('star')->get(); // select * from books.json order by star desc $bookCollection->sortBy('star', 'desc')->get(); // sorting calculated value $bookCollection->sortBy(function($row) { return $row['star'] + $row['views']; }, 'desc')->get();
限制与偏移量
// select * from books.json offset 4 $bookCollection->skip(4)->get(); // select * from books.json limit 10 offset 4 $bookCollection->take(10, 4)->get();
连接
$userCollection = new Collection('db/users.json'); $bookCollection = new Collection('db/books.json'); // get user with 'books' $userCollection->withMany($bookCollection, 'books', 'author.email', '=', 'email')->get(); // get books with 'user' $bookCollection->withOne($userCollection, 'user', 'email', '=', 'author.email')->get();
映射与保存
$bookCollection->where('star', '>', 3)->map(function($row) { $row['star'] = $row['star'] += 2; return $row; })->save();
事务
$bookCollection->begin(); try { // insert, update, delete, etc // will stored into variable (memory) $bookCollection->commit(); // until this } catch(Exception $e) { $bookCollection->rollback(); }
宏查询
宏查询允许我们向Emsifa\Laci\Collection
的实例中添加新方法,以便可以更流畅地重复使用。
例如,如果我们想获取活跃用户的数据,如果使用常规方法,我们可以进行如下查询
$users->where('active', 1)->get();
如果上述方法被重复使用,有时我们可能会忘记识别活跃用户的值是1
,或true
,或'yes'
,或'YES'
,或'yes'
,或'y'
,或'Y'
,或'Ya'
,或'ya'
等?
因此,为了简化操作,我们可以使用如下宏
$users->macro('active', function ($query) { return $query->where('active', 1); });
因此,我们可以这样获取活跃用户
$users->active()->get();
这样不是更实用吗?