LaciDB - Flat File JSON DBMS
, (*1)
Overview
LaciDB adalah flat file DBMS dengan format penyimpanan berupa JSON. Karena format JSON, LaciDB bersifat schemaless seperti halnya NoSQL lainnya. Sebuah record dapat memiliki kolom yang berbeda-beda., (*2)
Dalam LaciDB tidak ada istilah table, yang ada adalah collection. Collection pada LaciDB mewakili sebuah file yang menyimpan banyak records (dalam format JSON)., (*3)
Nama 'Laci' sendiri diambil karena fungsi dan prosesnya seperti laci pada meja/lemari. Laci pada meja/lemari umumnya tidak membutuhkan kunci (autentikasi), cukup buka > ambil sesuatu dan|atau taruh sesuatu > tutup. Pada LaciDB pun seperti itu, setiap query akan membuka file > eksekusi query (select|insert|update|delete) > file ditutup. Laci juga seperti yang kita ketahui adalah tempat untuk menaruh barang-barang kecil. Bukan barang-barang besar seperti gudang atau lemari., (*4)
Untuk itu LaciDB bukan untuk:, (*5)
- Menyimpan database dengan ukuran yang besar.
- Menyimpan database yang membutuhkan keamanan tingkat tinggi.
LaciDB dibuat untuk:, (*6)
- Menangani data-data yang kecil seperti pengaturan, atau data-data kecil lain.
- Untuk kalian yang menginginkan database portable yang mudah untuk diimport/export dan backup.
- Untuk kalian yang menginginkan database yang mudah diedit sendiri tanpa menggunakan software khusus. Notepad pun bisa.
Cara Kerja
Cara kerja LaciDB pada dasarnya hanyalah mengalirkan array hasil json_decode kedalam 'pipa-pipa' yang berfungsi sebagai filtering, mapping, sorting, limiting sampai akhirnya hasilnya akan di eksekusi untuk diambil nilainya, diubah nilainya atau dibuang (baca: dihapus)., (*7)
Berikut penjelasan terkait prosesnya:, (*8)
Filtering
Untuk melakukan filtering kamu dapat menggunakan method where dan orWhere. Ke2 method tersebut dapat menerima parameter Closure atau beberapa parameter key, operator, value., (*9)
Mapping
Mapping digunakan untuk membentuk nilai yang baru pada setiap record yang telah difilter., (*10)
Berikut beberapa method untuk mapping record:, (*11)
map(Closure $mapper)
Untuk mapping records pada collection yang telah difilter., (*12)
select(array $columns)
Mapping records untuk mengambil kolom-kolom tertentu saja., (*13)
withOne(Collection|Query $relation, $key, $otherKey, $operator, $thisKey)
Untuk mengambil relasi 1:1., (*14)
withMany(Collection|Query $relation, $key, $otherKey, $operator, $thisKey)
Untuk mengambil relasi 1:n., (*15)
Sorting
Sorting digunakan untuk mengurutkan data yang telah difilter dan dimapping. Untuk melakukan sorting kamu dapat menggunakan method sortBy($key, $ascending). Parameter $key dapat berupa string key/kolom yang ingin diurutkan atau Closure jika ingin mengurutkan berdasarkan nilai yang dikomputasi terlebih dahulu., (*16)
Limiting/Taking
Setelah data selesai difilter, dimapping, dan disorting, kamu dapat memotong dan mengambil sebagian data dengan method skip($offset) atau take($limit, $offset)., (*17)
Executing
Setelah difilter, dimapping, disorting, dan disisihkan, langkah selanjutnya adalah ekseskusi hasilnya., (*18)
Berikut beberapa method untuk executing:, (*19)
get(array $columns = null)
Mengambil kumpulan records pada collection. Jika ingin mengambil kolom tertentu definisikan kolom kedalam array $columns., (*20)
first(array $columns = null)
Mengambil (sebuah) record pada collection. Jika ingin mengambil kolom tertentu definisikan kolom kedalam array $columns., (*21)
count()
Mengambil banyak data dari collection., (*22)
sum($key)
Mengambil total key tertentu pada collection., (*23)
avg($key)
Mengambil rata-rata key tertentu pada collection., (*24)
min($key)
Mengambil nilai terendah dari key tertentu pada collection., (*25)
max($key)
Mengambil nilai tertinggi dari key tertentu pada collection., (*26)
lists($key, $resultKey = null)
Mengumpulkan dan mengambil key tertentu kedalam array pada collection., (*27)
insert(array $data)
Insert data baru kedalam collection., (*28)
inserts(array $listData)
Insert beberapa data baru sekaligus kedalam collection. Note: insert dan inserts tidak dapat dilakukan setelah query di filter atau di mapping., (*29)
update(array $newData)
Mengupdate data pada records didalam collection yang difilter dan dimapping., (*30)
save()
Sama seperti update. Hanya saja save akan menyimpan record berdasarkan hasil mapping, bukan berdasarkan $newData seperti pada update., (*31)
delete()
Menghapus data pada collection yang difilter dan dimapping., (*32)
truncate()
Menghapus seluruh data. Tidak membutuhkan filtering dan mapping terlebih dahulu., (*33)
Contoh
Inisialisasi
use Emsifa\Laci\Collection;
require 'vendor/autoload.php';
$collection = new Collection(__DIR__.'/users.json');
Insert Data
$user = $collection->insert([
'name' => 'John Doe',
'email' => 'johndoe@mail.com',
'password' => password_hash('password', PASSWORD_BCRYPT)
]);
$user akan berupa array seperti ini:, (*34)
[
'_id' => '58745c13ad585',
'name' => 'John Doe',
'email' => 'johndoe@mail.com',
'password' => '$2y$10$eMF03850wE6uII7UeujyjOU5Q2XLWz0QEZ1A9yiKPjbo3sA4qYh1m'
]
'_id' adalah uniqid(), (*35)
Find Single Record By ID
$user = $collection->find('58745c13ad585');
Find One
$user = $collection->where('email', 'johndoe@mail.com')->first();
Select All
$data = $collection->all();
Update
$collection->where('email', 'johndoe@mail.com')->update([
'name' => 'John',
'sex' => 'male'
]);
Return value is count affected records, (*36)
Delete
$collection->where('email', 'johndoe@mail.com')->delete();
Return value is count affected records, (*37)
Multiple Inserts
$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
],
]);
Find Where
// 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();
Operator can be '=', '<', '<=', '>', '>=', 'in', 'not in', 'between', 'match'., (*38)
Mengambil Kolom/Key Tertentu
// select author, title from books.json where star > 3
$bookCollection->where('star', '>', 3)->get(['author.name', 'title']);
Alias Kolom/Key
// select author[name] as author_name, title from books.json where star > 3
$bookCollection->where('star', '>', 3)->get(['author.name:author_name', 'title']);
Mapping
$bookCollection->map(function($row) {
$row['score'] = $row['star'] + $row['views'];
return $row;
})
->sortBy('score', 'desc')
->get();
Sorting
// 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();
Limit & Offset
// select * from books.json offset 4
$bookCollection->skip(4)->get();
// select * from books.json limit 10 offset 4
$bookCollection->take(10, 4)->get();
Join
$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();
Map & Save
$bookCollection->where('star', '>', 3)->map(function($row) {
$row['star'] = $row['star'] += 2;
return $row;
})->save();
Transaction
$bookCollection->begin();
try {
// insert, update, delete, etc
// will stored into variable (memory)
$bookCollection->commit(); // until this
} catch(Exception $e) {
$bookCollection->rollback();
}
Macro Query
Macro query memungkinkan kita menambahkan method baru kedalam instance Emsifa\Laci\Collection sehingga dapat kita gunakan berulang-ulang secara lebih fluent., (*39)
Sebagai contoh kita ingin mengambil data user yang aktif, jika dengan cara biasa kita dapat melakukan query seperti ini:, (*40)
$users->where('active', 1)->get();
Cara seperti diatas jika digunakan berulang-ulang, terkadang kita lupa mengenali user aktif itu yang nilai active-nya 1, atau true, atau 'yes', atau 'YES', atau 'yes', atau 'y', atau 'Y', atau 'Ya', atau 'ya', dsb?, (*41)
Jadi untuk mempermudahnya, kita dapat menggunakan macro sebagai berikut:, (*42)
$users->macro('active', function ($query) {
return $query->where('active', 1);
});
Sehingga kita dapat mengambil user aktif dengan cara seperti ini:, (*43)
$users->active()->get();
Tampak lebih praktis bukan?, (*44)