Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4071fed48f |
@@ -1,30 +0,0 @@
|
||||
name: mkdocs
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Configure Git Credentials
|
||||
run: |
|
||||
git config user.name github-actions[bot]
|
||||
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
key: mkdocs-material-${{ env.cache_id }}
|
||||
path: .cache
|
||||
restore-keys: |
|
||||
mkdocs-material-
|
||||
- run: pip install mkdocs-material
|
||||
- run: pip install mkdocs-glightbox
|
||||
- run: pip install Pygments
|
||||
- run: mkdocs gh-deploy --force
|
||||
@@ -1,44 +0,0 @@
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-and-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v1
|
||||
with:
|
||||
version: 0.14.0-dev.1510+fb0028a0d
|
||||
|
||||
- name: Build release artifacts
|
||||
run: |
|
||||
zig build -Doptimize=ReleaseSmall release
|
||||
|
||||
# The think is 300kb, I dont need to compress it
|
||||
#- name: Create zip files for release artifacts
|
||||
# run: |
|
||||
# mkdir -p zig-out/release/zips
|
||||
# for file in zig-out/release/*; do
|
||||
# if [ -f "$file" ] && [[ "$(basename "$file")" != *.pdb ]]; then
|
||||
# filename=$(basename "$file")
|
||||
# zipname="${filename%.*}"
|
||||
# zip -j "zig-out/release/zips/${zipname}.zip" "$file"
|
||||
# fi
|
||||
# done
|
||||
|
||||
- name: Upload release artifacts
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: "Release ${{ github.ref_name }}"
|
||||
body: "Base release. Most ZipponQL features are here but stuffs around is missing."
|
||||
artifacts: zig-out/release/*
|
||||
@@ -1,13 +0,0 @@
|
||||
.zig-cache
|
||||
.venv
|
||||
ZipponDB
|
||||
data
|
||||
benchmarkDB
|
||||
engine
|
||||
engine.o
|
||||
zig-out
|
||||
test1
|
||||
test2
|
||||
fly.toml
|
||||
dockerfile
|
||||
.dockerignore
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Adrien Bouvais
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,136 +0,0 @@
|
||||
<p align="center">
|
||||
<a href="/ZipponDB"><img src="https://mrbounty.github.io/ZipponDB/images/banner.png" alt="ZipponDB"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>Minimalist Lightweight General Purpose Database written in Zig</em>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
**Documentation**: <a href="/ZipponDB" target="_blank">https://mrbounty.github.io/ZipponDB</a>
|
||||
|
||||
**Source Code**: <a href="https://github.com/MrBounty/ZipponDB" target="_blank">https://github.com/MrBounty/ZipponDB</a>
|
||||
|
||||
---
|
||||
|
||||
ZipponDB is a database built from the ground up in Zig, with zero external dependencies. Designed for simplicity,
|
||||
performance, and portability, it's almost usable for small to
|
||||
medium applications that want a quick and simple database.
|
||||
|
||||
## Key Features
|
||||
|
||||
* **Small Binary:** ~300kb.
|
||||
* **Fast:** Parse millions of entities in milliseconds.*
|
||||
* **Relationship:** Build with focus on easy relationship.
|
||||
* **Query Language:** Use it's own stupid query language.
|
||||
* **No dependencies:** Depend on nothing, every line of code running is in the codebase and written for ZipponDB.
|
||||
* **Open-source:** Open-source under MIT licence.
|
||||
|
||||
<small>* Check <a href="https://mrbounty.github.io/ZipponDB/Benchmark/">benchmark</a>.</small>
|
||||
|
||||
# Declare a schema
|
||||
|
||||
In ZipponDB, you use structures, or structs for short, and not tables to organize how your data is stored and manipulated. A struct has a name like `User` and members like `name` and `age`.
|
||||
|
||||
Create a file that contains a schema that describes all structs. Compared to SQL, you can see it as a file where you declare all table names, column names, data types, and relationships.
|
||||
All structs have an id of the type UUID by default.
|
||||
|
||||
Here an example of a file:
|
||||
```lua
|
||||
User (
|
||||
name: str,
|
||||
age: int,
|
||||
email: str,
|
||||
Parent: User,
|
||||
childrens: []User,
|
||||
orders: []Order,
|
||||
)
|
||||
|
||||
Order (
|
||||
at: datetime,
|
||||
items: []Item,
|
||||
)
|
||||
|
||||
Item (
|
||||
name: str,
|
||||
category: str,
|
||||
)
|
||||
```
|
||||
|
||||
Note that parent is a link to another `User` and can be `none`, `[]` mean an array. You can find more examples [here](https://github.com/MrBounty/ZipponDB/tree/main/schema).
|
||||
|
||||
# ZipponQL
|
||||
|
||||
ZipponDB uses its own query language, ZipponQL or ZiQL for short. Here are the key points to remember:
|
||||
- 4 actions available: `GRAB`, `ADD`, `UPDATE`, `DELETE`
|
||||
- All queries start with an action followed by a struct name
|
||||
- `{}` are filters
|
||||
- `[]` specify how much and what data
|
||||
- `()` contain new or updated data (not already in the file)
|
||||
|
||||
## GRAB
|
||||
|
||||
The main action is `GRAB`, it parse files and return data.
|
||||
```js
|
||||
GRAB User {name = 'Bob' AND (age > 30 OR age < 10)}
|
||||
```
|
||||
|
||||
Using `[]` before the filter tell what to return.
|
||||
```js
|
||||
GRAB User [id, email] {name = 'Bob'}
|
||||
```
|
||||
|
||||
Relationship use filter within filter.
|
||||
```js
|
||||
GRAB User {best_friend IN {name = 'Bob'}}
|
||||
```
|
||||
|
||||
GRAB queries return a list of JSON objects, e.g:
|
||||
```
|
||||
[{id:"1e170a80-84c9-429a-be25-ab4657894653", name: "Gwendolyn Ray", age: 70, email: "austin92@example.org", scores: [ 77 ], friends: [], }, ]
|
||||
```
|
||||
|
||||
## ADD
|
||||
|
||||
The `ADD` action adds one entity to the database. The syntax is similar to `GRAB`, but uses `()`. This signifies that the data is not yet in the database.
|
||||
```js
|
||||
ADD User (name = 'Bob', age = 30)
|
||||
```
|
||||
|
||||
## DELETE
|
||||
|
||||
Similar to `GRAB` but deletes all entities found using the filter and returns a list of deleted UUIDs.
|
||||
```js
|
||||
DELETE User {name = 'Bob'}
|
||||
```
|
||||
|
||||
## UPDATE
|
||||
|
||||
A mix of `GRAB` and `ADD`. It takes a filter first, then the new data.
|
||||
Here, we update the first 5 `User` entities named 'bob' to capitalize the name and become 'Bob':
|
||||
```js
|
||||
UPDATE User [5] {name='bob'} TO (name = 'Bob')
|
||||
```
|
||||
|
||||
## Link query - Not yet implemented
|
||||
|
||||
You can also link query. Each query returns a list of UUID of a specific struct. You can use it in the next query.
|
||||
Here an example where I create a new `Comment` that I then append to the list of comment of one specific `User`.
|
||||
```js
|
||||
ADD Comment (content='Hello world', at=NOW, like_by=[]) => added_comment => UPDATE User {id = '000'} TO (comments APPEND added_comment)
|
||||
```
|
||||
|
||||
The name between `=>` is the variable name of the list of UUID used for the next queries, you can have multiple one if the link has more than 2 queries.
|
||||
You can also just use one `=>` but the list of UUID is discarded in that case.
|
||||
|
||||
This can be use with GRAB too. So you can create variable before making the query. Here an example:
|
||||
```js
|
||||
GRAB User {name = 'Bob'} => bobs =>
|
||||
GRAB User {age > 18} => adults =>
|
||||
GRAB User {IN adults AND !IN bobs}
|
||||
```
|
||||
|
||||
Which is the same as:
|
||||
```js
|
||||
GRAB User {name != 'Bob' AND age > 18}
|
||||
```
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* Lunr languages, `Danish` language
|
||||
* https://github.com/MihaiValentin/lunr-languages
|
||||
*
|
||||
* Copyright 2014, Mihai Valentin
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
/*!
|
||||
* based on
|
||||
* Snowball JavaScript Library v0.3
|
||||
* http://code.google.com/p/urim/
|
||||
* http://snowball.tartarus.org/
|
||||
*
|
||||
* Copyright 2010, Oleg Mazko
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){var e,r=f.cursor+3;if(d=f.limit,0<=r&&r<=f.limit){for(a=r;;){if(e=f.cursor,f.in_grouping(w,97,248)){f.cursor=e;break}if(f.cursor=e,e>=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d<a&&(d=a)}}function n(){var e,r;if(f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del();break;case 2:f.in_grouping_b(p,97,229)&&f.slice_del()}}function t(){var e,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}function s(){var e,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case 2:f.slice_from("løs")}}function o(){var e;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}var a,d,u,c=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],l=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=new i;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var r=f.cursor;return e(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hi=function(){this.pipeline.reset(),this.pipeline.add(e.hi.trimmer,e.hi.stopWordFilter,e.hi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hi.stemmer))},e.hi.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿa-zA-Za-zA-Z0-90-9",e.hi.trimmer=e.trimmerSupport.generateTrimmer(e.hi.wordCharacters),e.Pipeline.registerFunction(e.hi.trimmer,"trimmer-hi"),e.hi.stopWordFilter=e.generateStopWordFilter("अत अपना अपनी अपने अभी अंदर आदि आप इत्यादि इन इनका इन्हीं इन्हें इन्हों इस इसका इसकी इसके इसमें इसी इसे उन उनका उनकी उनके उनको उन्हीं उन्हें उन्हों उस उसके उसी उसे एक एवं एस ऐसे और कई कर करता करते करना करने करें कहते कहा का काफ़ी कि कितना किन्हें किन्हों किया किर किस किसी किसे की कुछ कुल के को कोई कौन कौनसा गया घर जब जहाँ जा जितना जिन जिन्हें जिन्हों जिस जिसे जीधर जैसा जैसे जो तक तब तरह तिन तिन्हें तिन्हों तिस तिसे तो था थी थे दबारा दिया दुसरा दूसरे दो द्वारा न नके नहीं ना निहायत नीचे ने पर पहले पूरा पे फिर बनी बही बहुत बाद बाला बिलकुल भी भीतर मगर मानो मे में यदि यह यहाँ यही या यिह ये रखें रहा रहे ऱ्वासा लिए लिये लेकिन व वग़ैरह वर्ग वह वहाँ वहीं वाले वुह वे वो सकता सकते सबसे सभी साथ साबुत साभ सारा से सो संग ही हुआ हुई हुए है हैं हो होता होती होते होना होने".split(" ")),e.hi.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.hi.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var t=i.toString().toLowerCase().replace(/^\s+/,"");return r.cut(t).split("|")},e.Pipeline.registerFunction(e.hi.stemmer,"stemmer-hi"),e.Pipeline.registerFunction(e.hi.stopWordFilter,"stopWordFilter-hi")}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hy=function(){this.pipeline.reset(),this.pipeline.add(e.hy.trimmer,e.hy.stopWordFilter)},e.hy.wordCharacters="[A-Za-z-֏ff-ﭏ]",e.hy.trimmer=e.trimmerSupport.generateTrimmer(e.hy.wordCharacters),e.Pipeline.registerFunction(e.hy.trimmer,"trimmer-hy"),e.hy.stopWordFilter=e.generateStopWordFilter("դու և եք էիր էիք հետո նաև նրանք որը վրա է որ պիտի են այս մեջ ն իր ու ի այդ որոնք այն կամ էր մի ես համար այլ իսկ էին ենք հետ ին թ էինք մենք նրա նա դուք եմ էի ըստ որպես ում".split(" ")),e.Pipeline.registerFunction(e.hy.stopWordFilter,"stopWordFilter-hy"),e.hy.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}(),e.Pipeline.registerFunction(e.hy.stemmer,"stemmer-hy")}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.ja=function(){this.pipeline.reset(),this.pipeline.add(e.ja.trimmer,e.ja.stopWordFilter,e.ja.stemmer),r?this.tokenizer=e.ja.tokenizer:(e.tokenizer&&(e.tokenizer=e.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.ja.tokenizer))};var t=new e.TinySegmenter;e.ja.tokenizer=function(i){var n,o,s,p,a,u,m,l,c,f;if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(o=i.toString().toLowerCase().replace(/^\s+/,""),n=o.length-1;n>=0;n--)if(/\S/.test(o.charAt(n))){o=o.substring(0,n+1);break}for(a=[],s=o.length,c=0,l=0;c<=s;c++)if(u=o.charAt(c),m=c-l,u.match(/\s/)||c==s){if(m>0)for(p=t.segment(o.slice(l,c)).filter(function(e){return!!e}),f=l,n=0;n<p.length;n++)r?a.push(new e.Token(p[n],{position:[f,p[n].length],index:a.length})):a.push(p[n]),f+=p[n].length;l=c+1}return a},e.ja.stemmer=function(){return function(e){return e}}(),e.Pipeline.registerFunction(e.ja.stemmer,"stemmer-ja"),e.ja.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",e.ja.trimmer=e.trimmerSupport.generateTrimmer(e.ja.wordCharacters),e.Pipeline.registerFunction(e.ja.trimmer,"trimmer-ja"),e.ja.stopWordFilter=e.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),e.Pipeline.registerFunction(e.ja.stopWordFilter,"stopWordFilter-ja"),e.jp=e.ja,e.Pipeline.registerFunction(e.jp.stemmer,"stemmer-jp"),e.Pipeline.registerFunction(e.jp.trimmer,"trimmer-jp"),e.Pipeline.registerFunction(e.jp.stopWordFilter,"stopWordFilter-jp")}});
|
||||
@@ -0,0 +1 @@
|
||||
module.exports=require("./lunr.ja");
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.kn=function(){this.pipeline.reset(),this.pipeline.add(e.kn.trimmer,e.kn.stopWordFilter,e.kn.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.kn.stemmer))},e.kn.wordCharacters="ಀ-಄ಅ-ಔಕ-ಹಾ-ೌ಼-ಽೕ-ೖೝ-ೞೠ-ೡೢ-ೣ೦-೯ೱ-ೳ",e.kn.trimmer=e.trimmerSupport.generateTrimmer(e.kn.wordCharacters),e.Pipeline.registerFunction(e.kn.trimmer,"trimmer-kn"),e.kn.stopWordFilter=e.generateStopWordFilter("ಮತ್ತು ಈ ಒಂದು ರಲ್ಲಿ ಹಾಗೂ ಎಂದು ಅಥವಾ ಇದು ರ ಅವರು ಎಂಬ ಮೇಲೆ ಅವರ ತನ್ನ ಆದರೆ ತಮ್ಮ ನಂತರ ಮೂಲಕ ಹೆಚ್ಚು ನ ಆ ಕೆಲವು ಅನೇಕ ಎರಡು ಹಾಗು ಪ್ರಮುಖ ಇದನ್ನು ಇದರ ಸುಮಾರು ಅದರ ಅದು ಮೊದಲ ಬಗ್ಗೆ ನಲ್ಲಿ ರಂದು ಇತರ ಅತ್ಯಂತ ಹೆಚ್ಚಿನ ಸಹ ಸಾಮಾನ್ಯವಾಗಿ ನೇ ಹಲವಾರು ಹೊಸ ದಿ ಕಡಿಮೆ ಯಾವುದೇ ಹೊಂದಿದೆ ದೊಡ್ಡ ಅನ್ನು ಇವರು ಪ್ರಕಾರ ಇದೆ ಮಾತ್ರ ಕೂಡ ಇಲ್ಲಿ ಎಲ್ಲಾ ವಿವಿಧ ಅದನ್ನು ಹಲವು ರಿಂದ ಕೇವಲ ದ ದಕ್ಷಿಣ ಗೆ ಅವನ ಅತಿ ನೆಯ ಬಹಳ ಕೆಲಸ ಎಲ್ಲ ಪ್ರತಿ ಇತ್ಯಾದಿ ಇವು ಬೇರೆ ಹೀಗೆ ನಡುವೆ ಇದಕ್ಕೆ ಎಸ್ ಇವರ ಮೊದಲು ಶ್ರೀ ಮಾಡುವ ಇದರಲ್ಲಿ ರೀತಿಯ ಮಾಡಿದ ಕಾಲ ಅಲ್ಲಿ ಮಾಡಲು ಅದೇ ಈಗ ಅವು ಗಳು ಎ ಎಂಬುದು ಅವನು ಅಂದರೆ ಅವರಿಗೆ ಇರುವ ವಿಶೇಷ ಮುಂದೆ ಅವುಗಳ ಮುಂತಾದ ಮೂಲ ಬಿ ಮೀ ಒಂದೇ ಇನ್ನೂ ಹೆಚ್ಚಾಗಿ ಮಾಡಿ ಅವರನ್ನು ಇದೇ ಯ ರೀತಿಯಲ್ಲಿ ಜೊತೆ ಅದರಲ್ಲಿ ಮಾಡಿದರು ನಡೆದ ಆಗ ಮತ್ತೆ ಪೂರ್ವ ಆತ ಬಂದ ಯಾವ ಒಟ್ಟು ಇತರೆ ಹಿಂದೆ ಪ್ರಮಾಣದ ಗಳನ್ನು ಕುರಿತು ಯು ಆದ್ದರಿಂದ ಅಲ್ಲದೆ ನಗರದ ಮೇಲಿನ ಏಕೆಂದರೆ ರಷ್ಟು ಎಂಬುದನ್ನು ಬಾರಿ ಎಂದರೆ ಹಿಂದಿನ ಆದರೂ ಆದ ಸಂಬಂಧಿಸಿದ ಮತ್ತೊಂದು ಸಿ ಆತನ ".split(" ")),e.kn.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.kn.tokenizer=function(t){if(!arguments.length||null==t||void 0==t)return[];if(Array.isArray(t))return t.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var n=t.toString().toLowerCase().replace(/^\s+/,"");return r.cut(n).split("|")},e.Pipeline.registerFunction(e.kn.stemmer,"stemmer-kn"),e.Pipeline.registerFunction(e.kn.stopWordFilter,"stopWordFilter-kn")}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){e.multiLanguage=function(){for(var t=Array.prototype.slice.call(arguments),i=t.join("-"),r="",n=[],s=[],p=0;p<t.length;++p)"en"==t[p]?(r+="\\w",n.unshift(e.stopWordFilter),n.push(e.stemmer),s.push(e.stemmer)):(r+=e[t[p]].wordCharacters,e[t[p]].stopWordFilter&&n.unshift(e[t[p]].stopWordFilter),e[t[p]].stemmer&&(n.push(e[t[p]].stemmer),s.push(e[t[p]].stemmer)));var o=e.trimmerSupport.generateTrimmer(r);return e.Pipeline.registerFunction(o,"lunr-multi-trimmer-"+i),n.unshift(o),function(){this.pipeline.reset(),this.pipeline.add.apply(this.pipeline,n),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add.apply(this.searchPipeline,s))}}}});
|
||||
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* Lunr languages, `Norwegian` language
|
||||
* https://github.com/MihaiValentin/lunr-languages
|
||||
*
|
||||
* Copyright 2014, Mihai Valentin
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
/*!
|
||||
* based on
|
||||
* Snowball JavaScript Library v0.3
|
||||
* http://code.google.com/p/urim/
|
||||
* http://snowball.tartarus.org/
|
||||
*
|
||||
* Copyright 2010, Oleg Mazko
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a<s&&(a=s)}}function i(){var e,r,n;if(w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case 3:w.slice_from("er")}}function t(){var e,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}function o(){var e,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}var s,a,m=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],u=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sa=function(){this.pipeline.reset(),this.pipeline.add(e.sa.trimmer,e.sa.stopWordFilter,e.sa.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sa.stemmer))},e.sa.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿ꣠-꣱ꣲ-ꣷ꣸-ꣻ꣼-ꣽꣾ-ꣿᆰ0-ᆰ9",e.sa.trimmer=e.trimmerSupport.generateTrimmer(e.sa.wordCharacters),e.Pipeline.registerFunction(e.sa.trimmer,"trimmer-sa"),e.sa.stopWordFilter=e.generateStopWordFilter('तथा अयम् एकम् इत्यस्मिन् तथा तत् वा अयम् इत्यस्य ते आहूत उपरि तेषाम् किन्तु तेषाम् तदा इत्यनेन अधिकः इत्यस्य तत् केचन बहवः द्वि तथा महत्वपूर्णः अयम् अस्य विषये अयं अस्ति तत् प्रथमः विषये इत्युपरि इत्युपरि इतर अधिकतमः अधिकः अपि सामान्यतया ठ इतरेतर नूतनम् द न्यूनम् कश्चित् वा विशालः द सः अस्ति तदनुसारम् तत्र अस्ति केवलम् अपि अत्र सर्वे विविधाः तत् बहवः यतः इदानीम् द दक्षिण इत्यस्मै तस्य उपरि नथ अतीव कार्यम् सर्वे एकैकम् इत्यादि। एते सन्ति उत इत्थम् मध्ये एतदर्थं . स कस्य प्रथमः श्री. करोति अस्मिन् प्रकारः निर्मिता कालः तत्र कर्तुं समान अधुना ते सन्ति स एकः अस्ति सः अर्थात् तेषां कृते . स्थितम् विशेषः अग्रिम तेषाम् समान स्रोतः ख म समान इदानीमपि अधिकतया करोतु ते समान इत्यस्य वीथी सह यस्मिन् कृतवान् धृतः तदा पुनः पूर्वं सः आगतः किम् कुल इतर पुरा मात्रा स विषये उ अतएव अपि नगरस्य उपरि यतः प्रतिशतं कतरः कालः साधनानि भूत तथापि जात सम्बन्धि अन्यत् ग अतः अस्माकं स्वकीयाः अस्माकं इदानीं अन्तः इत्यादयः भवन्तः इत्यादयः एते एताः तस्य अस्य इदम् एते तेषां तेषां तेषां तान् तेषां तेषां तेषां समानः सः एकः च तादृशाः बहवः अन्ये च वदन्ति यत् कियत् कस्मै कस्मै यस्मै यस्मै यस्मै यस्मै न अतिनीचः किन्तु प्रथमं सम्पूर्णतया ततः चिरकालानन्तरं पुस्तकं सम्पूर्णतया अन्तः किन्तु अत्र वा इह इव श्रद्धाय अवशिष्यते परन्तु अन्ये वर्गाः सन्ति ते सन्ति शक्नुवन्ति सर्वे मिलित्वा सर्वे एकत्र"'.split(" ")),e.sa.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.sa.tokenizer=function(t){if(!arguments.length||null==t||void 0==t)return[];if(Array.isArray(t))return t.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var i=t.toString().toLowerCase().replace(/^\s+/,"");return r.cut(i).split("|")},e.Pipeline.registerFunction(e.sa.stemmer,"stemmer-sa"),e.Pipeline.registerFunction(e.sa.stopWordFilter,"stopWordFilter-sa")}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(r,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(r.lunr)}(this,function(){return function(r){r.stemmerSupport={Among:function(r,t,i,s){if(this.toCharArray=function(r){for(var t=r.length,i=new Array(t),s=0;s<t;s++)i[s]=r.charCodeAt(s);return i},!r&&""!=r||!t&&0!=t||!i)throw"Bad Among initialisation: s:"+r+", substring_i: "+t+", result: "+i;this.s_size=r.length,this.s=this.toCharArray(r),this.substring_i=t,this.result=i,this.method=s},SnowballProgram:function(){var r;return{bra:0,ket:0,limit:0,cursor:0,limit_backward:0,setCurrent:function(t){r=t,this.cursor=0,this.limit=t.length,this.limit_backward=0,this.bra=this.cursor,this.ket=this.limit},getCurrent:function(){var t=r;return r=null,t},in_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e>s||e<i)return this.cursor++,!0;if(e-=i,!(t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e<i)return this.cursor--,!0;if(e-=i,!(t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor+s)!=i.charCodeAt(s))return!1;return this.cursor+=t,!0},eq_s_b:function(t,i){if(this.cursor-this.limit_backward<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor-t+s)!=i.charCodeAt(s))return!1;return this.cursor-=t,!0},find_among:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=t[a],m=l;m<_.s_size;m++){if(n+l==u){f=-1;break}if(f=r.charCodeAt(n+l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=t[a],m=_.s_size-1-l;m>=0;m--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n-_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n-_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}});
|
||||
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* Lunr languages, `Swedish` language
|
||||
* https://github.com/MihaiValentin/lunr-languages
|
||||
*
|
||||
* Copyright 2014, Mihai Valentin
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
/*!
|
||||
* based on
|
||||
* Snowball JavaScript Library v0.3
|
||||
* http://code.google.com/p/urim/
|
||||
* http://snowball.tartarus.org/
|
||||
*
|
||||
* Copyright 2010, Oleg Mazko
|
||||
* http://www.mozilla.org/MPL/
|
||||
*/
|
||||
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o<a&&(o=a)}}function t(){var e,r=w.limit_backward;if(w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ta=function(){this.pipeline.reset(),this.pipeline.add(e.ta.trimmer,e.ta.stopWordFilter,e.ta.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ta.stemmer))},e.ta.wordCharacters="-உஊ-ஏஐ-ஙச-ட-னப-யர-ஹ-ிீ-ொ-ௐ---௩௪-௯௰-௹௺-a-zA-Za-zA-Z0-90-9",e.ta.trimmer=e.trimmerSupport.generateTrimmer(e.ta.wordCharacters),e.Pipeline.registerFunction(e.ta.trimmer,"trimmer-ta"),e.ta.stopWordFilter=e.generateStopWordFilter("அங்கு அங்கே அது அதை அந்த அவர் அவர்கள் அவள் அவன் அவை ஆக ஆகவே ஆகையால் ஆதலால் ஆதலினால் ஆனாலும் ஆனால் இங்கு இங்கே இது இதை இந்த இப்படி இவர் இவர்கள் இவள் இவன் இவை இவ்வளவு உனக்கு உனது உன் உன்னால் எங்கு எங்கே எது எதை எந்த எப்படி எவர் எவர்கள் எவள் எவன் எவை எவ்வளவு எனக்கு எனது எனவே என் என்ன என்னால் ஏது ஏன் தனது தன்னால் தானே தான் நாங்கள் நாம் நான் நீ நீங்கள்".split(" ")),e.ta.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var t=e.wordcut;t.init(),e.ta.tokenizer=function(r){if(!arguments.length||null==r||void 0==r)return[];if(Array.isArray(r))return r.map(function(t){return isLunr2?new e.Token(t.toLowerCase()):t.toLowerCase()});var i=r.toString().toLowerCase().replace(/^\s+/,"");return t.cut(i).split("|")},e.Pipeline.registerFunction(e.ta.stemmer,"stemmer-ta"),e.Pipeline.registerFunction(e.ta.stopWordFilter,"stopWordFilter-ta")}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.te=function(){this.pipeline.reset(),this.pipeline.add(e.te.trimmer,e.te.stopWordFilter,e.te.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.te.stemmer))},e.te.wordCharacters="ఀ-ఄఅ-ఔక-హా-ౌౕ-ౖౘ-ౚౠ-ౡౢ-ౣ౦-౯౸-౿఼ఽ్ౝ౷",e.te.trimmer=e.trimmerSupport.generateTrimmer(e.te.wordCharacters),e.Pipeline.registerFunction(e.te.trimmer,"trimmer-te"),e.te.stopWordFilter=e.generateStopWordFilter("అందరూ అందుబాటులో అడగండి అడగడం అడ్డంగా అనుగుణంగా అనుమతించు అనుమతిస్తుంది అయితే ఇప్పటికే ఉన్నారు ఎక్కడైనా ఎప్పుడు ఎవరైనా ఎవరో ఏ ఏదైనా ఏమైనప్పటికి ఒక ఒకరు కనిపిస్తాయి కాదు కూడా గా గురించి చుట్టూ చేయగలిగింది తగిన తర్వాత దాదాపు దూరంగా నిజంగా పై ప్రకారం ప్రక్కన మధ్య మరియు మరొక మళ్ళీ మాత్రమే మెచ్చుకో వద్ద వెంట వేరుగా వ్యతిరేకంగా సంబంధం".split(" ")),e.te.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var t=e.wordcut;t.init(),e.te.tokenizer=function(r){if(!arguments.length||null==r||void 0==r)return[];if(Array.isArray(r))return r.map(function(t){return isLunr2?new e.Token(t.toLowerCase()):t.toLowerCase()});var i=r.toString().toLowerCase().replace(/^\s+/,"");return t.cut(i).split("|")},e.Pipeline.registerFunction(e.te.stemmer,"stemmer-te"),e.Pipeline.registerFunction(e.te.stopWordFilter,"stopWordFilter-te")}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.th=function(){this.pipeline.reset(),this.pipeline.add(e.th.trimmer),r?this.tokenizer=e.th.tokenizer:(e.tokenizer&&(e.tokenizer=e.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.th.tokenizer))},e.th.wordCharacters="[-]",e.th.trimmer=e.trimmerSupport.generateTrimmer(e.th.wordCharacters),e.Pipeline.registerFunction(e.th.trimmer,"trimmer-th");var t=e.wordcut;t.init(),e.th.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t):t});var n=i.toString().replace(/^\s+/,"");return t.cut(n).split("|")}}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r(require("@node-rs/jieba")):r()(e.lunr)}(this,function(e){return function(r,t){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==r.version[0];r.zh=function(){this.pipeline.reset(),this.pipeline.add(r.zh.trimmer,r.zh.stopWordFilter,r.zh.stemmer),i?this.tokenizer=r.zh.tokenizer:(r.tokenizer&&(r.tokenizer=r.zh.tokenizer),this.tokenizerFn&&(this.tokenizerFn=r.zh.tokenizer))},r.zh.tokenizer=function(n){if(!arguments.length||null==n||void 0==n)return[];if(Array.isArray(n))return n.map(function(e){return i?new r.Token(e.toLowerCase()):e.toLowerCase()});t&&e.load(t);var o=n.toString().trim().toLowerCase(),s=[];e.cut(o,!0).forEach(function(e){s=s.concat(e.split(" "))}),s=s.filter(function(e){return!!e});var u=0;return s.map(function(e,t){if(i){var n=o.indexOf(e,u),s={};return s.position=[n,e.length],s.index=t,u=n,new r.Token(e,s)}return e})},r.zh.wordCharacters="\\w一-龥",r.zh.trimmer=r.trimmerSupport.generateTrimmer(r.zh.wordCharacters),r.Pipeline.registerFunction(r.zh.trimmer,"trimmer-zh"),r.zh.stemmer=function(){return function(e){return e}}(),r.Pipeline.registerFunction(r.zh.stemmer,"stemmer-zh"),r.zh.stopWordFilter=r.generateStopWordFilter("的 一 不 在 人 有 是 为 為 以 于 於 上 他 而 后 後 之 来 來 及 了 因 下 可 到 由 这 這 与 與 也 此 但 并 並 个 個 其 已 无 無 小 我 们 們 起 最 再 今 去 好 只 又 或 很 亦 某 把 那 你 乃 它 吧 被 比 别 趁 当 當 从 從 得 打 凡 儿 兒 尔 爾 该 該 各 给 給 跟 和 何 还 還 即 几 幾 既 看 据 據 距 靠 啦 另 么 麽 每 嘛 拿 哪 您 凭 憑 且 却 卻 让 讓 仍 啥 如 若 使 谁 誰 虽 雖 随 隨 同 所 她 哇 嗡 往 些 向 沿 哟 喲 用 咱 则 則 怎 曾 至 致 着 著 诸 諸 自".split(" ")),r.Pipeline.registerFunction(r.zh.stopWordFilter,"stopWordFilter-zh")}});
|
||||
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* export the module via AMD, CommonJS or as a browser global
|
||||
* Export code from https://github.com/umdjs/umd/blob/master/returnExports.js
|
||||
*/
|
||||
;(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(factory)
|
||||
} else if (typeof exports === 'object') {
|
||||
/**
|
||||
* Node. Does not work with strict CommonJS, but
|
||||
* only CommonJS-like environments that support module.exports,
|
||||
* like Node.
|
||||
*/
|
||||
module.exports = factory()
|
||||
} else {
|
||||
// Browser globals (root is window)
|
||||
factory()(root.lunr);
|
||||
}
|
||||
}(this, function () {
|
||||
/**
|
||||
* Just return a value to define the module export.
|
||||
* This example returns an object, but the module
|
||||
* can return a function as the exported value.
|
||||
*/
|
||||
|
||||
return function(lunr) {
|
||||
// TinySegmenter 0.1 -- Super compact Japanese tokenizer in Javascript
|
||||
// (c) 2008 Taku Kudo <taku@chasen.org>
|
||||
// TinySegmenter is freely distributable under the terms of a new BSD licence.
|
||||
// For details, see http://chasen.org/~taku/software/TinySegmenter/LICENCE.txt
|
||||
|
||||
function TinySegmenter() {
|
||||
var patterns = {
|
||||
"[一二三四五六七八九十百千万億兆]":"M",
|
||||
"[一-龠々〆ヵヶ]":"H",
|
||||
"[ぁ-ん]":"I",
|
||||
"[ァ-ヴーア-ン゙ー]":"K",
|
||||
"[a-zA-Za-zA-Z]":"A",
|
||||
"[0-90-9]":"N"
|
||||
}
|
||||
this.chartype_ = [];
|
||||
for (var i in patterns) {
|
||||
var regexp = new RegExp(i);
|
||||
this.chartype_.push([regexp, patterns[i]]);
|
||||
}
|
||||
|
||||
this.BIAS__ = -332
|
||||
this.BC1__ = {"HH":6,"II":2461,"KH":406,"OH":-1378};
|
||||
this.BC2__ = {"AA":-3267,"AI":2744,"AN":-878,"HH":-4070,"HM":-1711,"HN":4012,"HO":3761,"IA":1327,"IH":-1184,"II":-1332,"IK":1721,"IO":5492,"KI":3831,"KK":-8741,"MH":-3132,"MK":3334,"OO":-2920};
|
||||
this.BC3__ = {"HH":996,"HI":626,"HK":-721,"HN":-1307,"HO":-836,"IH":-301,"KK":2762,"MK":1079,"MM":4034,"OA":-1652,"OH":266};
|
||||
this.BP1__ = {"BB":295,"OB":304,"OO":-125,"UB":352};
|
||||
this.BP2__ = {"BO":60,"OO":-1762};
|
||||
this.BQ1__ = {"BHH":1150,"BHM":1521,"BII":-1158,"BIM":886,"BMH":1208,"BNH":449,"BOH":-91,"BOO":-2597,"OHI":451,"OIH":-296,"OKA":1851,"OKH":-1020,"OKK":904,"OOO":2965};
|
||||
this.BQ2__ = {"BHH":118,"BHI":-1159,"BHM":466,"BIH":-919,"BKK":-1720,"BKO":864,"OHH":-1139,"OHM":-181,"OIH":153,"UHI":-1146};
|
||||
this.BQ3__ = {"BHH":-792,"BHI":2664,"BII":-299,"BKI":419,"BMH":937,"BMM":8335,"BNN":998,"BOH":775,"OHH":2174,"OHM":439,"OII":280,"OKH":1798,"OKI":-793,"OKO":-2242,"OMH":-2402,"OOO":11699};
|
||||
this.BQ4__ = {"BHH":-3895,"BIH":3761,"BII":-4654,"BIK":1348,"BKK":-1806,"BMI":-3385,"BOO":-12396,"OAH":926,"OHH":266,"OHK":-2036,"ONN":-973};
|
||||
this.BW1__ = {",と":660,",同":727,"B1あ":1404,"B1同":542,"、と":660,"、同":727,"」と":1682,"あっ":1505,"いう":1743,"いっ":-2055,"いる":672,"うし":-4817,"うん":665,"から":3472,"がら":600,"こう":-790,"こと":2083,"こん":-1262,"さら":-4143,"さん":4573,"した":2641,"して":1104,"すで":-3399,"そこ":1977,"それ":-871,"たち":1122,"ため":601,"った":3463,"つい":-802,"てい":805,"てき":1249,"でき":1127,"です":3445,"では":844,"とい":-4915,"とみ":1922,"どこ":3887,"ない":5713,"なっ":3015,"など":7379,"なん":-1113,"にし":2468,"には":1498,"にも":1671,"に対":-912,"の一":-501,"の中":741,"ませ":2448,"まで":1711,"まま":2600,"まる":-2155,"やむ":-1947,"よっ":-2565,"れた":2369,"れで":-913,"をし":1860,"を見":731,"亡く":-1886,"京都":2558,"取り":-2784,"大き":-2604,"大阪":1497,"平方":-2314,"引き":-1336,"日本":-195,"本当":-2423,"毎日":-2113,"目指":-724,"B1あ":1404,"B1同":542,"」と":1682};
|
||||
this.BW2__ = {"..":-11822,"11":-669,"――":-5730,"−−":-13175,"いう":-1609,"うか":2490,"かし":-1350,"かも":-602,"から":-7194,"かれ":4612,"がい":853,"がら":-3198,"きた":1941,"くな":-1597,"こと":-8392,"この":-4193,"させ":4533,"され":13168,"さん":-3977,"しい":-1819,"しか":-545,"した":5078,"して":972,"しな":939,"その":-3744,"たい":-1253,"たた":-662,"ただ":-3857,"たち":-786,"たと":1224,"たは":-939,"った":4589,"って":1647,"っと":-2094,"てい":6144,"てき":3640,"てく":2551,"ては":-3110,"ても":-3065,"でい":2666,"でき":-1528,"でし":-3828,"です":-4761,"でも":-4203,"とい":1890,"とこ":-1746,"とと":-2279,"との":720,"とみ":5168,"とも":-3941,"ない":-2488,"なが":-1313,"など":-6509,"なの":2614,"なん":3099,"にお":-1615,"にし":2748,"にな":2454,"によ":-7236,"に対":-14943,"に従":-4688,"に関":-11388,"のか":2093,"ので":-7059,"のに":-6041,"のの":-6125,"はい":1073,"はが":-1033,"はず":-2532,"ばれ":1813,"まし":-1316,"まで":-6621,"まれ":5409,"めて":-3153,"もい":2230,"もの":-10713,"らか":-944,"らし":-1611,"らに":-1897,"りし":651,"りま":1620,"れた":4270,"れて":849,"れば":4114,"ろう":6067,"われ":7901,"を通":-11877,"んだ":728,"んな":-4115,"一人":602,"一方":-1375,"一日":970,"一部":-1051,"上が":-4479,"会社":-1116,"出て":2163,"分の":-7758,"同党":970,"同日":-913,"大阪":-2471,"委員":-1250,"少な":-1050,"年度":-8669,"年間":-1626,"府県":-2363,"手権":-1982,"新聞":-4066,"日新":-722,"日本":-7068,"日米":3372,"曜日":-601,"朝鮮":-2355,"本人":-2697,"東京":-1543,"然と":-1384,"社会":-1276,"立て":-990,"第に":-1612,"米国":-4268,"11":-669};
|
||||
this.BW3__ = {"あた":-2194,"あり":719,"ある":3846,"い.":-1185,"い。":-1185,"いい":5308,"いえ":2079,"いく":3029,"いた":2056,"いっ":1883,"いる":5600,"いわ":1527,"うち":1117,"うと":4798,"えと":1454,"か.":2857,"か。":2857,"かけ":-743,"かっ":-4098,"かに":-669,"から":6520,"かり":-2670,"が,":1816,"が、":1816,"がき":-4855,"がけ":-1127,"がっ":-913,"がら":-4977,"がり":-2064,"きた":1645,"けど":1374,"こと":7397,"この":1542,"ころ":-2757,"さい":-714,"さを":976,"し,":1557,"し、":1557,"しい":-3714,"した":3562,"して":1449,"しな":2608,"しま":1200,"す.":-1310,"す。":-1310,"する":6521,"ず,":3426,"ず、":3426,"ずに":841,"そう":428,"た.":8875,"た。":8875,"たい":-594,"たの":812,"たり":-1183,"たる":-853,"だ.":4098,"だ。":4098,"だっ":1004,"った":-4748,"って":300,"てい":6240,"てお":855,"ても":302,"です":1437,"でに":-1482,"では":2295,"とう":-1387,"とし":2266,"との":541,"とも":-3543,"どう":4664,"ない":1796,"なく":-903,"など":2135,"に,":-1021,"に、":-1021,"にし":1771,"にな":1906,"には":2644,"の,":-724,"の、":-724,"の子":-1000,"は,":1337,"は、":1337,"べき":2181,"まし":1113,"ます":6943,"まっ":-1549,"まで":6154,"まれ":-793,"らし":1479,"られ":6820,"るる":3818,"れ,":854,"れ、":854,"れた":1850,"れて":1375,"れば":-3246,"れる":1091,"われ":-605,"んだ":606,"んで":798,"カ月":990,"会議":860,"入り":1232,"大会":2217,"始め":1681,"市":965,"新聞":-5055,"日,":974,"日、":974,"社会":2024,"カ月":990};
|
||||
this.TC1__ = {"AAA":1093,"HHH":1029,"HHM":580,"HII":998,"HOH":-390,"HOM":-331,"IHI":1169,"IOH":-142,"IOI":-1015,"IOM":467,"MMH":187,"OOI":-1832};
|
||||
this.TC2__ = {"HHO":2088,"HII":-1023,"HMM":-1154,"IHI":-1965,"KKH":703,"OII":-2649};
|
||||
this.TC3__ = {"AAA":-294,"HHH":346,"HHI":-341,"HII":-1088,"HIK":731,"HOH":-1486,"IHH":128,"IHI":-3041,"IHO":-1935,"IIH":-825,"IIM":-1035,"IOI":-542,"KHH":-1216,"KKA":491,"KKH":-1217,"KOK":-1009,"MHH":-2694,"MHM":-457,"MHO":123,"MMH":-471,"NNH":-1689,"NNO":662,"OHO":-3393};
|
||||
this.TC4__ = {"HHH":-203,"HHI":1344,"HHK":365,"HHM":-122,"HHN":182,"HHO":669,"HIH":804,"HII":679,"HOH":446,"IHH":695,"IHO":-2324,"IIH":321,"III":1497,"IIO":656,"IOO":54,"KAK":4845,"KKA":3386,"KKK":3065,"MHH":-405,"MHI":201,"MMH":-241,"MMM":661,"MOM":841};
|
||||
this.TQ1__ = {"BHHH":-227,"BHHI":316,"BHIH":-132,"BIHH":60,"BIII":1595,"BNHH":-744,"BOHH":225,"BOOO":-908,"OAKK":482,"OHHH":281,"OHIH":249,"OIHI":200,"OIIH":-68};
|
||||
this.TQ2__ = {"BIHH":-1401,"BIII":-1033,"BKAK":-543,"BOOO":-5591};
|
||||
this.TQ3__ = {"BHHH":478,"BHHM":-1073,"BHIH":222,"BHII":-504,"BIIH":-116,"BIII":-105,"BMHI":-863,"BMHM":-464,"BOMH":620,"OHHH":346,"OHHI":1729,"OHII":997,"OHMH":481,"OIHH":623,"OIIH":1344,"OKAK":2792,"OKHH":587,"OKKA":679,"OOHH":110,"OOII":-685};
|
||||
this.TQ4__ = {"BHHH":-721,"BHHM":-3604,"BHII":-966,"BIIH":-607,"BIII":-2181,"OAAA":-2763,"OAKK":180,"OHHH":-294,"OHHI":2446,"OHHO":480,"OHIH":-1573,"OIHH":1935,"OIHI":-493,"OIIH":626,"OIII":-4007,"OKAK":-8156};
|
||||
this.TW1__ = {"につい":-4681,"東京都":2026};
|
||||
this.TW2__ = {"ある程":-2049,"いった":-1256,"ころが":-2434,"しょう":3873,"その後":-4430,"だって":-1049,"ていた":1833,"として":-4657,"ともに":-4517,"もので":1882,"一気に":-792,"初めて":-1512,"同時に":-8097,"大きな":-1255,"対して":-2721,"社会党":-3216};
|
||||
this.TW3__ = {"いただ":-1734,"してい":1314,"として":-4314,"につい":-5483,"にとっ":-5989,"に当た":-6247,"ので,":-727,"ので、":-727,"のもの":-600,"れから":-3752,"十二月":-2287};
|
||||
this.TW4__ = {"いう.":8576,"いう。":8576,"からな":-2348,"してい":2958,"たが,":1516,"たが、":1516,"ている":1538,"という":1349,"ました":5543,"ません":1097,"ようと":-4258,"よると":5865};
|
||||
this.UC1__ = {"A":484,"K":93,"M":645,"O":-505};
|
||||
this.UC2__ = {"A":819,"H":1059,"I":409,"M":3987,"N":5775,"O":646};
|
||||
this.UC3__ = {"A":-1370,"I":2311};
|
||||
this.UC4__ = {"A":-2643,"H":1809,"I":-1032,"K":-3450,"M":3565,"N":3876,"O":6646};
|
||||
this.UC5__ = {"H":313,"I":-1238,"K":-799,"M":539,"O":-831};
|
||||
this.UC6__ = {"H":-506,"I":-253,"K":87,"M":247,"O":-387};
|
||||
this.UP1__ = {"O":-214};
|
||||
this.UP2__ = {"B":69,"O":935};
|
||||
this.UP3__ = {"B":189};
|
||||
this.UQ1__ = {"BH":21,"BI":-12,"BK":-99,"BN":142,"BO":-56,"OH":-95,"OI":477,"OK":410,"OO":-2422};
|
||||
this.UQ2__ = {"BH":216,"BI":113,"OK":1759};
|
||||
this.UQ3__ = {"BA":-479,"BH":42,"BI":1913,"BK":-7198,"BM":3160,"BN":6427,"BO":14761,"OI":-827,"ON":-3212};
|
||||
this.UW1__ = {",":156,"、":156,"「":-463,"あ":-941,"う":-127,"が":-553,"き":121,"こ":505,"で":-201,"と":-547,"ど":-123,"に":-789,"の":-185,"は":-847,"も":-466,"や":-470,"よ":182,"ら":-292,"り":208,"れ":169,"を":-446,"ん":-137,"・":-135,"主":-402,"京":-268,"区":-912,"午":871,"国":-460,"大":561,"委":729,"市":-411,"日":-141,"理":361,"生":-408,"県":-386,"都":-718,"「":-463,"・":-135};
|
||||
this.UW2__ = {",":-829,"、":-829,"〇":892,"「":-645,"」":3145,"あ":-538,"い":505,"う":134,"お":-502,"か":1454,"が":-856,"く":-412,"こ":1141,"さ":878,"ざ":540,"し":1529,"す":-675,"せ":300,"そ":-1011,"た":188,"だ":1837,"つ":-949,"て":-291,"で":-268,"と":-981,"ど":1273,"な":1063,"に":-1764,"の":130,"は":-409,"ひ":-1273,"べ":1261,"ま":600,"も":-1263,"や":-402,"よ":1639,"り":-579,"る":-694,"れ":571,"を":-2516,"ん":2095,"ア":-587,"カ":306,"キ":568,"ッ":831,"三":-758,"不":-2150,"世":-302,"中":-968,"主":-861,"事":492,"人":-123,"会":978,"保":362,"入":548,"初":-3025,"副":-1566,"北":-3414,"区":-422,"大":-1769,"天":-865,"太":-483,"子":-1519,"学":760,"実":1023,"小":-2009,"市":-813,"年":-1060,"強":1067,"手":-1519,"揺":-1033,"政":1522,"文":-1355,"新":-1682,"日":-1815,"明":-1462,"最":-630,"朝":-1843,"本":-1650,"東":-931,"果":-665,"次":-2378,"民":-180,"気":-1740,"理":752,"発":529,"目":-1584,"相":-242,"県":-1165,"立":-763,"第":810,"米":509,"自":-1353,"行":838,"西":-744,"見":-3874,"調":1010,"議":1198,"込":3041,"開":1758,"間":-1257,"「":-645,"」":3145,"ッ":831,"ア":-587,"カ":306,"キ":568};
|
||||
this.UW3__ = {",":4889,"1":-800,"−":-1723,"、":4889,"々":-2311,"〇":5827,"」":2670,"〓":-3573,"あ":-2696,"い":1006,"う":2342,"え":1983,"お":-4864,"か":-1163,"が":3271,"く":1004,"け":388,"げ":401,"こ":-3552,"ご":-3116,"さ":-1058,"し":-395,"す":584,"せ":3685,"そ":-5228,"た":842,"ち":-521,"っ":-1444,"つ":-1081,"て":6167,"で":2318,"と":1691,"ど":-899,"な":-2788,"に":2745,"の":4056,"は":4555,"ひ":-2171,"ふ":-1798,"へ":1199,"ほ":-5516,"ま":-4384,"み":-120,"め":1205,"も":2323,"や":-788,"よ":-202,"ら":727,"り":649,"る":5905,"れ":2773,"わ":-1207,"を":6620,"ん":-518,"ア":551,"グ":1319,"ス":874,"ッ":-1350,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278,"・":-3794,"一":-1619,"下":-1759,"世":-2087,"両":3815,"中":653,"主":-758,"予":-1193,"二":974,"人":2742,"今":792,"他":1889,"以":-1368,"低":811,"何":4265,"作":-361,"保":-2439,"元":4858,"党":3593,"全":1574,"公":-3030,"六":755,"共":-1880,"円":5807,"再":3095,"分":457,"初":2475,"別":1129,"前":2286,"副":4437,"力":365,"動":-949,"務":-1872,"化":1327,"北":-1038,"区":4646,"千":-2309,"午":-783,"協":-1006,"口":483,"右":1233,"各":3588,"合":-241,"同":3906,"和":-837,"員":4513,"国":642,"型":1389,"場":1219,"外":-241,"妻":2016,"学":-1356,"安":-423,"実":-1008,"家":1078,"小":-513,"少":-3102,"州":1155,"市":3197,"平":-1804,"年":2416,"広":-1030,"府":1605,"度":1452,"建":-2352,"当":-3885,"得":1905,"思":-1291,"性":1822,"戸":-488,"指":-3973,"政":-2013,"教":-1479,"数":3222,"文":-1489,"新":1764,"日":2099,"旧":5792,"昨":-661,"時":-1248,"曜":-951,"最":-937,"月":4125,"期":360,"李":3094,"村":364,"東":-805,"核":5156,"森":2438,"業":484,"氏":2613,"民":-1694,"決":-1073,"法":1868,"海":-495,"無":979,"物":461,"特":-3850,"生":-273,"用":914,"町":1215,"的":7313,"直":-1835,"省":792,"県":6293,"知":-1528,"私":4231,"税":401,"立":-960,"第":1201,"米":7767,"系":3066,"約":3663,"級":1384,"統":-4229,"総":1163,"線":1255,"者":6457,"能":725,"自":-2869,"英":785,"見":1044,"調":-562,"財":-733,"費":1777,"車":1835,"軍":1375,"込":-1504,"通":-1136,"選":-681,"郎":1026,"郡":4404,"部":1200,"金":2163,"長":421,"開":-1432,"間":1302,"関":-1282,"雨":2009,"電":-1045,"非":2066,"駅":1620,"1":-800,"」":2670,"・":-3794,"ッ":-1350,"ア":551,"グ":1319,"ス":874,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278};
|
||||
this.UW4__ = {",":3930,".":3508,"―":-4841,"、":3930,"。":3508,"〇":4999,"「":1895,"」":3798,"〓":-5156,"あ":4752,"い":-3435,"う":-640,"え":-2514,"お":2405,"か":530,"が":6006,"き":-4482,"ぎ":-3821,"く":-3788,"け":-4376,"げ":-4734,"こ":2255,"ご":1979,"さ":2864,"し":-843,"じ":-2506,"す":-731,"ず":1251,"せ":181,"そ":4091,"た":5034,"だ":5408,"ち":-3654,"っ":-5882,"つ":-1659,"て":3994,"で":7410,"と":4547,"な":5433,"に":6499,"ぬ":1853,"ね":1413,"の":7396,"は":8578,"ば":1940,"ひ":4249,"び":-4134,"ふ":1345,"へ":6665,"べ":-744,"ほ":1464,"ま":1051,"み":-2082,"む":-882,"め":-5046,"も":4169,"ゃ":-2666,"や":2795,"ょ":-1544,"よ":3351,"ら":-2922,"り":-9726,"る":-14896,"れ":-2613,"ろ":-4570,"わ":-1783,"を":13150,"ん":-2352,"カ":2145,"コ":1789,"セ":1287,"ッ":-724,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637,"・":-4371,"ー":-11870,"一":-2069,"中":2210,"予":782,"事":-190,"井":-1768,"人":1036,"以":544,"会":950,"体":-1286,"作":530,"側":4292,"先":601,"党":-2006,"共":-1212,"内":584,"円":788,"初":1347,"前":1623,"副":3879,"力":-302,"動":-740,"務":-2715,"化":776,"区":4517,"協":1013,"参":1555,"合":-1834,"和":-681,"員":-910,"器":-851,"回":1500,"国":-619,"園":-1200,"地":866,"場":-1410,"塁":-2094,"士":-1413,"多":1067,"大":571,"子":-4802,"学":-1397,"定":-1057,"寺":-809,"小":1910,"屋":-1328,"山":-1500,"島":-2056,"川":-2667,"市":2771,"年":374,"庁":-4556,"後":456,"性":553,"感":916,"所":-1566,"支":856,"改":787,"政":2182,"教":704,"文":522,"方":-856,"日":1798,"時":1829,"最":845,"月":-9066,"木":-485,"来":-442,"校":-360,"業":-1043,"氏":5388,"民":-2716,"気":-910,"沢":-939,"済":-543,"物":-735,"率":672,"球":-1267,"生":-1286,"産":-1101,"田":-2900,"町":1826,"的":2586,"目":922,"省":-3485,"県":2997,"空":-867,"立":-2112,"第":788,"米":2937,"系":786,"約":2171,"経":1146,"統":-1169,"総":940,"線":-994,"署":749,"者":2145,"能":-730,"般":-852,"行":-792,"規":792,"警":-1184,"議":-244,"谷":-1000,"賞":730,"車":-1481,"軍":1158,"輪":-1433,"込":-3370,"近":929,"道":-1291,"選":2596,"郎":-4866,"都":1192,"野":-1100,"銀":-2213,"長":357,"間":-2344,"院":-2297,"際":-2604,"電":-878,"領":-1659,"題":-792,"館":-1984,"首":1749,"高":2120,"「":1895,"」":3798,"・":-4371,"ッ":-724,"ー":-11870,"カ":2145,"コ":1789,"セ":1287,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637};
|
||||
this.UW5__ = {",":465,".":-299,"1":-514,"E2":-32768,"]":-2762,"、":465,"。":-299,"「":363,"あ":1655,"い":331,"う":-503,"え":1199,"お":527,"か":647,"が":-421,"き":1624,"ぎ":1971,"く":312,"げ":-983,"さ":-1537,"し":-1371,"す":-852,"だ":-1186,"ち":1093,"っ":52,"つ":921,"て":-18,"で":-850,"と":-127,"ど":1682,"な":-787,"に":-1224,"の":-635,"は":-578,"べ":1001,"み":502,"め":865,"ゃ":3350,"ょ":854,"り":-208,"る":429,"れ":504,"わ":419,"を":-1264,"ん":327,"イ":241,"ル":451,"ン":-343,"中":-871,"京":722,"会":-1153,"党":-654,"務":3519,"区":-901,"告":848,"員":2104,"大":-1296,"学":-548,"定":1785,"嵐":-1304,"市":-2991,"席":921,"年":1763,"思":872,"所":-814,"挙":1618,"新":-1682,"日":218,"月":-4353,"査":932,"格":1356,"機":-1508,"氏":-1347,"田":240,"町":-3912,"的":-3149,"相":1319,"省":-1052,"県":-4003,"研":-997,"社":-278,"空":-813,"統":1955,"者":-2233,"表":663,"語":-1073,"議":1219,"選":-1018,"郎":-368,"長":786,"間":1191,"題":2368,"館":-689,"1":-514,"E2":-32768,"「":363,"イ":241,"ル":451,"ン":-343};
|
||||
this.UW6__ = {",":227,".":808,"1":-270,"E1":306,"、":227,"。":808,"あ":-307,"う":189,"か":241,"が":-73,"く":-121,"こ":-200,"じ":1782,"す":383,"た":-428,"っ":573,"て":-1014,"で":101,"と":-105,"な":-253,"に":-149,"の":-417,"は":-236,"も":-206,"り":187,"る":-135,"を":195,"ル":-673,"ン":-496,"一":-277,"中":201,"件":-800,"会":624,"前":302,"区":1792,"員":-1212,"委":798,"学":-960,"市":887,"広":-695,"後":535,"業":-697,"相":753,"社":-507,"福":974,"空":-822,"者":1811,"連":463,"郎":1082,"1":-270,"E1":306,"ル":-673,"ン":-496};
|
||||
|
||||
return this;
|
||||
}
|
||||
TinySegmenter.prototype.ctype_ = function(str) {
|
||||
for (var i in this.chartype_) {
|
||||
if (str.match(this.chartype_[i][0])) {
|
||||
return this.chartype_[i][1];
|
||||
}
|
||||
}
|
||||
return "O";
|
||||
}
|
||||
|
||||
TinySegmenter.prototype.ts_ = function(v) {
|
||||
if (v) { return v; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
TinySegmenter.prototype.segment = function(input) {
|
||||
if (input == null || input == undefined || input == "") {
|
||||
return [];
|
||||
}
|
||||
var result = [];
|
||||
var seg = ["B3","B2","B1"];
|
||||
var ctype = ["O","O","O"];
|
||||
var o = input.split("");
|
||||
for (i = 0; i < o.length; ++i) {
|
||||
seg.push(o[i]);
|
||||
ctype.push(this.ctype_(o[i]))
|
||||
}
|
||||
seg.push("E1");
|
||||
seg.push("E2");
|
||||
seg.push("E3");
|
||||
ctype.push("O");
|
||||
ctype.push("O");
|
||||
ctype.push("O");
|
||||
var word = seg[3];
|
||||
var p1 = "U";
|
||||
var p2 = "U";
|
||||
var p3 = "U";
|
||||
for (var i = 4; i < seg.length - 3; ++i) {
|
||||
var score = this.BIAS__;
|
||||
var w1 = seg[i-3];
|
||||
var w2 = seg[i-2];
|
||||
var w3 = seg[i-1];
|
||||
var w4 = seg[i];
|
||||
var w5 = seg[i+1];
|
||||
var w6 = seg[i+2];
|
||||
var c1 = ctype[i-3];
|
||||
var c2 = ctype[i-2];
|
||||
var c3 = ctype[i-1];
|
||||
var c4 = ctype[i];
|
||||
var c5 = ctype[i+1];
|
||||
var c6 = ctype[i+2];
|
||||
score += this.ts_(this.UP1__[p1]);
|
||||
score += this.ts_(this.UP2__[p2]);
|
||||
score += this.ts_(this.UP3__[p3]);
|
||||
score += this.ts_(this.BP1__[p1 + p2]);
|
||||
score += this.ts_(this.BP2__[p2 + p3]);
|
||||
score += this.ts_(this.UW1__[w1]);
|
||||
score += this.ts_(this.UW2__[w2]);
|
||||
score += this.ts_(this.UW3__[w3]);
|
||||
score += this.ts_(this.UW4__[w4]);
|
||||
score += this.ts_(this.UW5__[w5]);
|
||||
score += this.ts_(this.UW6__[w6]);
|
||||
score += this.ts_(this.BW1__[w2 + w3]);
|
||||
score += this.ts_(this.BW2__[w3 + w4]);
|
||||
score += this.ts_(this.BW3__[w4 + w5]);
|
||||
score += this.ts_(this.TW1__[w1 + w2 + w3]);
|
||||
score += this.ts_(this.TW2__[w2 + w3 + w4]);
|
||||
score += this.ts_(this.TW3__[w3 + w4 + w5]);
|
||||
score += this.ts_(this.TW4__[w4 + w5 + w6]);
|
||||
score += this.ts_(this.UC1__[c1]);
|
||||
score += this.ts_(this.UC2__[c2]);
|
||||
score += this.ts_(this.UC3__[c3]);
|
||||
score += this.ts_(this.UC4__[c4]);
|
||||
score += this.ts_(this.UC5__[c5]);
|
||||
score += this.ts_(this.UC6__[c6]);
|
||||
score += this.ts_(this.BC1__[c2 + c3]);
|
||||
score += this.ts_(this.BC2__[c3 + c4]);
|
||||
score += this.ts_(this.BC3__[c4 + c5]);
|
||||
score += this.ts_(this.TC1__[c1 + c2 + c3]);
|
||||
score += this.ts_(this.TC2__[c2 + c3 + c4]);
|
||||
score += this.ts_(this.TC3__[c3 + c4 + c5]);
|
||||
score += this.ts_(this.TC4__[c4 + c5 + c6]);
|
||||
// score += this.ts_(this.TC5__[c4 + c5 + c6]);
|
||||
score += this.ts_(this.UQ1__[p1 + c1]);
|
||||
score += this.ts_(this.UQ2__[p2 + c2]);
|
||||
score += this.ts_(this.UQ3__[p3 + c3]);
|
||||
score += this.ts_(this.BQ1__[p2 + c2 + c3]);
|
||||
score += this.ts_(this.BQ2__[p2 + c3 + c4]);
|
||||
score += this.ts_(this.BQ3__[p3 + c2 + c3]);
|
||||
score += this.ts_(this.BQ4__[p3 + c3 + c4]);
|
||||
score += this.ts_(this.TQ1__[p2 + c1 + c2 + c3]);
|
||||
score += this.ts_(this.TQ2__[p2 + c2 + c3 + c4]);
|
||||
score += this.ts_(this.TQ3__[p3 + c1 + c2 + c3]);
|
||||
score += this.ts_(this.TQ4__[p3 + c2 + c3 + c4]);
|
||||
var p = "O";
|
||||
if (score > 0) {
|
||||
result.push(word);
|
||||
word = "";
|
||||
p = "B";
|
||||
}
|
||||
p1 = p2;
|
||||
p2 = p3;
|
||||
p3 = p;
|
||||
word += seg[i];
|
||||
}
|
||||
result.push(word);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
lunr.TinySegmenter = TinySegmenter;
|
||||
};
|
||||
|
||||
}));
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["src/templates/assets/stylesheets/palette/_scheme.scss","../../../../src/templates/assets/stylesheets/palette.scss","src/templates/assets/stylesheets/palette/_accent.scss","src/templates/assets/stylesheets/palette/_primary.scss","src/templates/assets/stylesheets/utilities/_break.scss"],"names":[],"mappings":"AA2BA,cAGE,6BAME,sDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CACA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CAGA,mDAAA,CACA,gDAAA,CAGA,0BAAA,CACA,mCAAA,CAGA,iCAAA,CACA,kCAAA,CACA,mCAAA,CACA,mCAAA,CACA,kCAAA,CACA,iCAAA,CACA,+CAAA,CACA,6DAAA,CACA,gEAAA,CACA,4DAAA,CACA,4DAAA,CACA,6DAAA,CAGA,6CAAA,CAGA,+CAAA,CAGA,uDAAA,CACA,6DAAA,CACA,2DAAA,CAGA,iCAAA,CAGA,yDAAA,CACA,iEAAA,CAGA,mDAAA,CACA,mDAAA,CAGA,qDAAA,CACA,uDAAA,CAGA,8DAAA,CAKA,8DAAA,CAKA,0DAAA,CAvEA,iBCeF,CD6DE,kHAEE,YC3DJ,CDkFE,yDACE,4BChFJ,CD+EE,2DACE,4BC7EJ,CD4EE,gEACE,4BC1EJ,CDyEE,2DACE,4BCvEJ,CDsEE,yDACE,4BCpEJ,CDmEE,0DACE,4BCjEJ,CDgEE,gEACE,4BC9DJ,CD6DE,0DACE,4BC3DJ,CD0DE,2OACE,4BC/CJ,CDsDA,+FAGE,iCCpDF,CACF,CC/CE,2BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD2CN,CCrDE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDkDN,CC5DE,8BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDyDN,CCnEE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDgEN,CC1EE,8BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDuEN,CCjFE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD8EN,CCxFE,kCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDqFN,CC/FE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD4FN,CCtGE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDmGN,CC7GE,6BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD0GN,CCpHE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDiHN,CC3HE,4BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCD2HN,CClIE,8BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCDkIN,CCzIE,6BACE,yBAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCDyIN,CChJE,8BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCDgJN,CCvJE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDoJN,CEzJE,4BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsJN,CEjKE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8JN,CEzKE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsKN,CEjLE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8KN,CEzLE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsLN,CEjME,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8LN,CEzME,mCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsMN,CEjNE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8MN,CEzNE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsNN,CEjOE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8NN,CEzOE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsON,CEjPE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFiPN,CEzPE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFyPN,CEjQE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFiQN,CEzQE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFyQN,CEjRE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8QN,CEzRE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsRN,CEjSE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCAAA,CAKA,4BF0RN,CE1SE,kCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCAAA,CAKA,4BFmSN,CEpRE,sEACE,4BFuRJ,CExRE,+DACE,4BF2RJ,CE5RE,iEACE,4BF+RJ,CEhSE,gEACE,4BFmSJ,CEpSE,iEACE,4BFuSJ,CE9RA,8BACE,mDAAA,CACA,4DAAA,CACA,0DAAA,CACA,oDAAA,CACA,2DAAA,CAGA,4BF+RF,CE5RE,yCACE,+BF8RJ,CE3RI,kDAEE,0CAAA,CACA,sCAAA,CAFA,mCF+RN,CG3MI,mCD1EA,+CACE,8CFwRJ,CErRI,qDACE,8CFuRN,CElRE,iEACE,mCFoRJ,CACF,CGtNI,sCDvDA,uCACE,oCFgRJ,CACF,CEvQA,8BACE,kDAAA,CACA,4DAAA,CACA,wDAAA,CACA,oDAAA,CACA,6DAAA,CAGA,4BFwQF,CErQE,yCACE,+BFuQJ,CEpQI,kDAEE,0CAAA,CACA,sCAAA,CAFA,mCFwQN,CEjQE,yCACE,6CFmQJ,CG5NI,0CDhCA,8CACE,gDF+PJ,CACF,CGjOI,0CDvBA,iFACE,6CF2PJ,CACF,CGzPI,sCDKA,uCACE,6CFuPJ,CACF","file":"palette.css"}
|
||||
@@ -1,186 +0,0 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
// Run
|
||||
// -----------------------------------------------
|
||||
{
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "zippondb",
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
b.installArtifact(exe);
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
|
||||
exe.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
|
||||
exe.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") }));
|
||||
exe.root_module.addImport("ZipponData", b.createModule(.{ .root_source_file = b.path("lib/zid.zig") }));
|
||||
exe.root_module.addImport("error", b.createModule(.{ .root_source_file = b.path("lib/errors.zig") }));
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
}
|
||||
|
||||
// Test
|
||||
// -----------------------------------------------
|
||||
{
|
||||
const tests1 = b.addTest(.{
|
||||
.root_source_file = b.path("src/dataStructure/UUIDFileIndex.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.name = "CLI tokenizer",
|
||||
.test_runner = b.path("src/test_runner.zig"),
|
||||
});
|
||||
tests1.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
|
||||
const run_tests1 = b.addRunArtifact(tests1);
|
||||
|
||||
const tests2 = b.addTest(.{
|
||||
.root_source_file = b.path("src/cli/tokenizer.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.name = "CLI tokenizer",
|
||||
.test_runner = b.path("src/test_runner.zig"),
|
||||
});
|
||||
const run_tests2 = b.addRunArtifact(tests2);
|
||||
|
||||
const tests3 = b.addTest(.{
|
||||
.root_source_file = b.path("src/ziql/tokenizer.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.name = "ZiQL tokenizer",
|
||||
.test_runner = b.path("src/test_runner.zig"),
|
||||
});
|
||||
const run_tests3 = b.addRunArtifact(tests3);
|
||||
|
||||
const tests4 = b.addTest(.{
|
||||
.root_source_file = b.path("src/schema/tokenizer.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.name = "Schema tokenizer",
|
||||
.test_runner = b.path("src/test_runner.zig"),
|
||||
});
|
||||
tests4.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") }));
|
||||
tests4.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
|
||||
const run_tests4 = b.addRunArtifact(tests4);
|
||||
|
||||
const tests5 = b.addTest(.{
|
||||
.root_source_file = b.path("src/test.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.name = "ZiQL parser",
|
||||
.test_runner = b.path("src/test_runner.zig"),
|
||||
});
|
||||
tests5.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
|
||||
tests5.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") }));
|
||||
tests5.root_module.addImport("ZipponData", b.createModule(.{ .root_source_file = b.path("lib/zid.zig") }));
|
||||
tests5.root_module.addImport("error", b.createModule(.{ .root_source_file = b.path("lib/errors.zig") }));
|
||||
const run_tests5 = b.addRunArtifact(tests5);
|
||||
|
||||
const tests6 = b.addTest(.{
|
||||
.root_source_file = b.path("src/dataStructure/filter.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.name = "Filter tree",
|
||||
.test_runner = b.path("src/test_runner.zig"),
|
||||
});
|
||||
tests6.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
|
||||
tests6.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") }));
|
||||
tests6.root_module.addImport("ZipponData", b.createModule(.{ .root_source_file = b.path("lib/zid.zig") }));
|
||||
tests6.root_module.addImport("error", b.createModule(.{ .root_source_file = b.path("lib/errors.zig") }));
|
||||
const run_tests6 = b.addRunArtifact(tests6);
|
||||
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
test_step.dependOn(&run_tests1.step);
|
||||
test_step.dependOn(&run_tests2.step);
|
||||
test_step.dependOn(&run_tests3.step);
|
||||
test_step.dependOn(&run_tests4.step);
|
||||
test_step.dependOn(&run_tests5.step);
|
||||
test_step.dependOn(&run_tests6.step);
|
||||
}
|
||||
|
||||
// Test zid
|
||||
// -----------------------------------------------
|
||||
{
|
||||
const tests1 = b.addTest(.{
|
||||
.root_source_file = b.path("lib/zid.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.name = "File parsing",
|
||||
.test_runner = b.path("src/test_runner.zig"),
|
||||
});
|
||||
const run_tests1 = b.addRunArtifact(tests1);
|
||||
|
||||
const test_step = b.step("benchmark-parsing", "Run the benchmark of ZipponData (Single thread).");
|
||||
test_step.dependOn(&run_tests1.step);
|
||||
}
|
||||
|
||||
// Benchmark
|
||||
// -----------------------------------------------
|
||||
{
|
||||
const benchmark = b.addExecutable(.{
|
||||
.name = "benchmark",
|
||||
.root_source_file = b.path("src/benchmark.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
benchmark.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
|
||||
benchmark.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config_benchmark.zig") }));
|
||||
benchmark.root_module.addImport("ZipponData", b.createModule(.{ .root_source_file = b.path("lib/zid.zig") }));
|
||||
benchmark.root_module.addImport("error", b.createModule(.{ .root_source_file = b.path("lib/errors.zig") }));
|
||||
b.installArtifact(benchmark);
|
||||
|
||||
const run_benchmark = b.addRunArtifact(benchmark);
|
||||
run_benchmark.step.dependOn(b.getInstallStep());
|
||||
|
||||
const benchmark_step = b.step("benchmark", "Run benchmarks");
|
||||
benchmark_step.dependOn(&run_benchmark.step);
|
||||
}
|
||||
|
||||
// Release
|
||||
// -----------------------------------------------
|
||||
{
|
||||
const release_step = b.step("release", "Create release binaries for multiple platforms");
|
||||
|
||||
const targets = [_]std.Build.ResolvedTarget{
|
||||
b.resolveTargetQuery(.{ .os_tag = .windows, .cpu_arch = .x86_64 }),
|
||||
//b.resolveTargetQuery(.{ .os_tag = .windows, .cpu_arch = .arm }),
|
||||
b.resolveTargetQuery(.{ .os_tag = .macos, .cpu_arch = .x86_64 }),
|
||||
b.resolveTargetQuery(.{ .os_tag = .macos, .cpu_arch = .aarch64 }),
|
||||
b.resolveTargetQuery(.{ .os_tag = .linux, .cpu_arch = .x86_64 }),
|
||||
b.resolveTargetQuery(.{ .os_tag = .linux, .cpu_arch = .aarch64 }),
|
||||
//b.resolveTargetQuery(.{ .os_tag = .linux, .cpu_arch = .arm }),
|
||||
b.resolveTargetQuery(.{ .os_tag = .linux, .cpu_arch = .riscv64 }),
|
||||
};
|
||||
|
||||
for (targets) |tar| {
|
||||
const exe_name = b.fmt("zippondb-{s}-{s}", .{
|
||||
@tagName(tar.query.cpu_arch.?),
|
||||
@tagName(tar.query.os_tag.?),
|
||||
});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = exe_name,
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = tar,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
// Add the same imports as your main executable
|
||||
exe.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
|
||||
exe.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") }));
|
||||
exe.root_module.addImport("ZipponData", b.createModule(.{ .root_source_file = b.path("lib/zid.zig") }));
|
||||
exe.root_module.addImport("error", b.createModule(.{ .root_source_file = b.path("lib/errors.zig") }));
|
||||
|
||||
const install_exe = b.addInstallArtifact(exe, .{
|
||||
.dest_dir = .{ .override = .{ .custom = "release" } },
|
||||
});
|
||||
|
||||
release_step.dependOn(&install_exe.step);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
.{
|
||||
.name = "ZipponDB",
|
||||
.version = "0.1.4",
|
||||
.dependencies = .{},
|
||||
.paths = .{
|
||||
"",
|
||||
},
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
# Benchmark
|
||||
|
||||
***Benchmark are set to evolve. I have currently multiple ideas to improve performance.***
|
||||
|
||||
ZipponDB is fairly fast and can easely query millions of entities.
|
||||
Current limitation is around 5GB I would say, depending of CPU cores, usage and kind of data saved.
|
||||
After that query can start to become slow as optimizations are still missing.
|
||||
|
||||
Most of query's time is writing entities into a JSON format. Parsing the file itself take little time.
|
||||
For example in the benchmark report bellow, I parse 100 000 users in around 40ms if there is no entities to send and 130ms if all 100 000 entities are to send.
|
||||
|
||||
I choosed to release ZipponDB binary with the small release.
|
||||
Zig has a fast and safe release, but the fast release isn't that much faster in my case, if not at all.
|
||||
If you want you can build it with it.
|
||||
|
||||
## Command
|
||||
|
||||
You can run `zig build benchmark`, if you clone the repo to benchmark your machine.
|
||||
[More info on how to build from source.](/ZipponDB/build)
|
||||
|
||||
Here an example on my machine with 16 core:
|
||||
|
||||
```
|
||||
=====================================
|
||||
|
||||
Populating with 5000 users.
|
||||
Populate duration: 0.035698 seconds
|
||||
|
||||
Database path: benchmarkDB
|
||||
Total size: 0.36Mb
|
||||
CPU core: 16
|
||||
Max file size: 5.00Mb
|
||||
LOG: 0.02Mb
|
||||
BACKUP: 0.00Mb
|
||||
DATA: 0.33Mb
|
||||
Item: 0.00Mb | 19 entities | 1 files
|
||||
User: 0.33Mb | 5000 entities | 1 files
|
||||
Order: 0.00Mb | 0 entities | 1 files
|
||||
Category: 0.00Mb | 4 entities | 1 files
|
||||
|
||||
--------------------------------------
|
||||
|
||||
Query: GRAB User {}
|
||||
Time: 16.90 ± 25.22 ms | Min 8.25ms | Max 92.55ms
|
||||
|
||||
Query: GRAB User {name='asd'}
|
||||
Time: 2.62 ± 0.10 ms | Min 2.52ms | Max 2.85ms
|
||||
|
||||
Query: GRAB User [1] {}
|
||||
Time: 0.16 ± 0.01 ms | Min 0.15ms | Max 0.18ms
|
||||
|
||||
Query: GRAB User [name] {}
|
||||
Time: 7.88 ± 11.69 ms | Min 3.91ms | Max 42.94ms
|
||||
|
||||
Query: GRAB User {name = 'Charlie'}
|
||||
Time: 3.87 ± 0.16 ms | Min 3.70ms | Max 4.17ms
|
||||
|
||||
Query: GRAB Category {}
|
||||
Time: 0.20 ± 0.07 ms | Min 0.17ms | Max 0.41ms
|
||||
|
||||
Query: GRAB Item {}
|
||||
Time: 0.21 ± 0.02 ms | Min 0.19ms | Max 0.25ms
|
||||
|
||||
Query: GRAB Order {}
|
||||
Time: 0.14 ± 0.01 ms | Min 0.13ms | Max 0.18ms
|
||||
|
||||
Query: GRAB Order [from, items, quantity, at] {}
|
||||
Time: 4.18 ± 12.01 ms | Min 0.15ms | Max 40.21ms
|
||||
|
||||
Query: DELETE User {}
|
||||
Time: 0.64 ± 1.13 ms | Min 0.23ms | Max 4.04ms
|
||||
|
||||
Read: 1907698 Entity/second *Include small condition
|
||||
Write: 350200 Entity/second
|
||||
|
||||
=====================================
|
||||
|
||||
Populating with 100000 users.
|
||||
Populate duration: 0.707605 seconds
|
||||
|
||||
Database path: benchmarkDB
|
||||
Total size: 6.62Mb
|
||||
CPU core: 16
|
||||
Max file size: 5.00Mb
|
||||
LOG: 0.02Mb
|
||||
BACKUP: 0.00Mb
|
||||
DATA: 6.59Mb
|
||||
Item: 0.00Mb | 19 entities | 1 files
|
||||
User: 6.59Mb | 100000 entities | 2 files
|
||||
Order: 0.00Mb | 0 entities | 1 files
|
||||
Category: 0.00Mb | 4 entities | 1 files
|
||||
|
||||
--------------------------------------
|
||||
|
||||
Query: GRAB User {}
|
||||
Time: 126.99 ± 3.05 ms | Min 123.37ms | Max 133.56ms
|
||||
|
||||
Query: GRAB User {name='asd'}
|
||||
Time: 38.12 ± 1.60 ms | Min 36.48ms | Max 41.88ms
|
||||
|
||||
Query: GRAB User [1] {}
|
||||
Time: 0.19 ± 0.02 ms | Min 0.16ms | Max 0.22ms
|
||||
|
||||
Query: GRAB User [name] {}
|
||||
Time: 59.33 ± 1.29 ms | Min 58.02ms | Max 61.47ms
|
||||
|
||||
Query: GRAB User {name = 'Charlie'}
|
||||
Time: 53.29 ± 1.00 ms | Min 51.50ms | Max 54.78ms
|
||||
|
||||
Query: GRAB Category {}
|
||||
Time: 0.19 ± 0.01 ms | Min 0.18ms | Max 0.22ms
|
||||
|
||||
Query: GRAB Item {}
|
||||
Time: 5.51 ± 13.43 ms | Min 0.22ms | Max 45.22ms
|
||||
|
||||
Query: GRAB Order {}
|
||||
Time: 0.16 ± 0.01 ms | Min 0.15ms | Max 0.18ms
|
||||
|
||||
Query: GRAB Order [from, items, quantity, at] {}
|
||||
Time: 0.17 ± 0.02 ms | Min 0.15ms | Max 0.21ms
|
||||
|
||||
Query: DELETE User {}
|
||||
Time: 5.96 ± 17.04 ms | Min 0.26ms | Max 57.07ms
|
||||
|
||||
Read: 2623338 Entity/second *Include small condition
|
||||
Write: 1125278 Entity/second
|
||||
|
||||
=====================================
|
||||
|
||||
Populating with 1000000 users.
|
||||
Populate duration: 7.029142 seconds
|
||||
|
||||
Database path: benchmarkDB
|
||||
Total size: 65.96Mb
|
||||
CPU core: 16
|
||||
Max file size: 5.00Mb
|
||||
LOG: 0.02Mb
|
||||
BACKUP: 0.00Mb
|
||||
DATA: 65.93Mb
|
||||
Item: 0.00Mb | 19 entities | 1 files
|
||||
User: 65.93Mb | 1000000 entities | 14 files
|
||||
Order: 0.00Mb | 0 entities | 1 files
|
||||
Category: 0.00Mb | 4 entities | 1 files
|
||||
|
||||
--------------------------------------
|
||||
|
||||
Query: GRAB User {}
|
||||
Time: 250.77 ± 6.74 ms | Min 247.08ms | Max 270.61ms
|
||||
|
||||
Query: GRAB User {name='asd'}
|
||||
Time: 67.90 ± 0.42 ms | Min 67.31ms | Max 68.78ms
|
||||
|
||||
Query: GRAB User [1] {}
|
||||
Time: 8.92 ± 24.86 ms | Min 0.55ms | Max 83.51ms
|
||||
|
||||
Query: GRAB User [name] {}
|
||||
Time: 110.08 ± 5.27 ms | Min 106.86ms | Max 125.21ms
|
||||
|
||||
Query: GRAB User {name = 'Charlie'}
|
||||
Time: 73.65 ± 2.79 ms | Min 69.24ms | Max 79.22ms
|
||||
|
||||
Query: GRAB Category {}
|
||||
Time: 0.19 ± 0.04 ms | Min 0.16ms | Max 0.33ms
|
||||
|
||||
Query: GRAB Item {}
|
||||
Time: 0.21 ± 0.02 ms | Min 0.19ms | Max 0.26ms
|
||||
|
||||
Query: GRAB Order {}
|
||||
Time: 0.15 ± 0.01 ms | Min 0.14ms | Max 0.17ms
|
||||
|
||||
Query: GRAB Order [from, items, quantity, at] {}
|
||||
Time: 0.17 ± 0.01 ms | Min 0.16ms | Max 0.18ms
|
||||
|
||||
Query: DELETE User {}
|
||||
Time: 11.74 ± 34.19 ms | Min 0.29ms | Max 114.30ms
|
||||
|
||||
Read: 14727354 Entity/second *Include small condition
|
||||
Write: 5468517 Entity/second
|
||||
|
||||
=====================================
|
||||
|
||||
Populating with 10000000 users.
|
||||
Populate duration: 72.675680 seconds
|
||||
|
||||
Database path: benchmarkDB
|
||||
Total size: 659.33Mb
|
||||
CPU core: 16
|
||||
Max file size: 5.00Mb
|
||||
LOG: 0.02Mb
|
||||
BACKUP: 0.00Mb
|
||||
DATA: 659.30Mb
|
||||
Item: 0.00Mb | 19 entities | 1 files
|
||||
User: 659.30Mb | 10000000 entities | 132 files
|
||||
Order: 0.00Mb | 0 entities | 1 files
|
||||
Category: 0.00Mb | 4 entities | 1 files
|
||||
|
||||
--------------------------------------
|
||||
|
||||
Query: GRAB User {}
|
||||
Time: 2535.29 ± 86.92 ms | Min 2448.39ms | Max 2712.78ms
|
||||
|
||||
Query: GRAB User {name='asd'}
|
||||
Time: 684.75 ± 39.96 ms | Min 649.09ms | Max 797.13ms
|
||||
|
||||
Query: GRAB User [1] {}
|
||||
Time: 6.65 ± 1.00 ms | Min 5.36ms | Max 8.75ms
|
||||
|
||||
Query: GRAB User [name] {}
|
||||
Time: 1106.21 ± 33.57 ms | Min 1056.57ms | Max 1172.61ms
|
||||
|
||||
Query: GRAB User {name = 'Charlie'}
|
||||
Time: 690.56 ± 20.41 ms | Min 661.51ms | Max 718.07ms
|
||||
|
||||
Query: GRAB Category {}
|
||||
Time: 0.21 ± 0.03 ms | Min 0.18ms | Max 0.31ms
|
||||
|
||||
Query: GRAB Item {}
|
||||
Time: 0.23 ± 0.04 ms | Min 0.19ms | Max 0.32ms
|
||||
|
||||
Query: GRAB Order {}
|
||||
Time: 0.15 ± 0.01 ms | Min 0.13ms | Max 0.17ms
|
||||
|
||||
Query: GRAB Order [from, items, quantity, at] {}
|
||||
Time: 0.17 ± 0.02 ms | Min 0.15ms | Max 0.21ms
|
||||
|
||||
Query: DELETE User {}
|
||||
Time: 109.55 ± 326.64ms | Min 0.47ms | Max 1089.46ms
|
||||
|
||||
Read: 14603810 Entity/second *Include small condition
|
||||
Write: 5403847 Entity/second
|
||||
=====================================
|
||||
```
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
# Data types
|
||||
|
||||
ZipponDB have a little set of types. This is on purpose, to keep the database simple and fast. But more type may be added in the future.
|
||||
|
||||
## Primary Data Types
|
||||
|
||||
ZipponDB supports 8 primary data types:
|
||||
|
||||
| Type | Description | Example |
|
||||
|------|-------------|---------|
|
||||
| int | 32-bit integer | 42 |
|
||||
| float | 64-bit float (must include a decimal point) | 3.14 |
|
||||
| bool | Boolean value | true or false |
|
||||
| string | Character array enclosed in single quotes | 'Hello, World!' |
|
||||
| UUID | Universally Unique Identifier | 123e4567-e89b-12d3-a456-426614174000 |
|
||||
| date | Date in yyyy/mm/dd format | 2024/10/19 |
|
||||
| time | Time in hh:mm:ss.mmmm format | 12:45:00.0000 |
|
||||
| datetime | Combined date and time | 2024/10/19-12:45:00.0000 |
|
||||
|
||||
## Array Types
|
||||
|
||||
Any of these data types can be used as an array by prefixing it with `[]`. For example:
|
||||
|
||||
- `[]int`: An array of integers
|
||||
- `[]string`: An array of strings
|
||||
@@ -1,47 +0,0 @@
|
||||
# Quickstart
|
||||
|
||||
This guide will help you set up and start using ZipponDB quickly.
|
||||
|
||||
## Step 1: Get a Binary
|
||||
|
||||
Obtain a binary for your architecture by:
|
||||
|
||||
- Downloading a pre-built binary from the [releases page](https://github.com/MrBounty/ZipponDB/releases)
|
||||
- Building from [source code](https://mrbounty.github.io/ZipponDB/build)
|
||||
|
||||
Once with the binary, run it to get access to the CLI.
|
||||
|
||||
## Step 2: Select a Database
|
||||
|
||||
Once in the CLI, create a database by running:
|
||||
```bash
|
||||
db use path/to/dir
|
||||
```
|
||||
|
||||
Alternatively, set the `ZIPPONDB_PATH` environment variable.
|
||||
|
||||
## Step 3: Attach a Schema
|
||||
|
||||
Define a [schema](/ZipponDB/Schema) and attach it to the database by running:
|
||||
|
||||
```bash
|
||||
schema use path/to/schema.txt
|
||||
```
|
||||
|
||||
This will create the necessary directories and empty files for data storage. Test the current database schema by running:
|
||||
|
||||
```bash
|
||||
schema describe
|
||||
```
|
||||
|
||||
Alternatively, set the `ZIPPONDB_SCHEMA` environment variable.
|
||||
|
||||
## Step 4: Use the Database
|
||||
|
||||
Start using the database by sending queries, such as:
|
||||
|
||||
```bash
|
||||
run "ADD User (name = 'Bob')"
|
||||
```
|
||||
|
||||
[Learn more about ZiQL.](/ZipponDB/ziql/intro)
|
||||
@@ -1,58 +0,0 @@
|
||||
# Roadmap
|
||||
|
||||
***Note: This will probably evolve over time.***
|
||||
|
||||
### Alpha
|
||||
#### v0.1 - Base
|
||||
- [X] UUID
|
||||
- [X] CLI
|
||||
- [X] Tokenizers
|
||||
- [X] ZiQL parser
|
||||
- [X] Schema engine
|
||||
- [X] File engine
|
||||
|
||||
#### v0.2 - Usable
|
||||
- [X] Relationships
|
||||
- [X] Custom data file
|
||||
- [X] Date
|
||||
- [X] Logs
|
||||
- [X] Query multi threading
|
||||
- [X] Arrays manipulation
|
||||
|
||||
#### v0.3 - QoL
|
||||
- [X] Docs website
|
||||
- [ ] Ordering
|
||||
- [ ] Dot operator
|
||||
- [ ] Linked query
|
||||
- [ ] Schema migration
|
||||
- [ ] Dump/Bump data
|
||||
- [ ] Recovery
|
||||
- [ ] Better CLI
|
||||
|
||||
#### v0.4 - Usability
|
||||
- [ ] Single file
|
||||
- [ ] Docker
|
||||
- [ ] YAML config file
|
||||
- [ ] Python interface
|
||||
- [ ] Go interface
|
||||
|
||||
#### v0.5 - In memory
|
||||
- [ ] In memory option
|
||||
- [ ] Cache
|
||||
|
||||
#### v0.6 - Performance
|
||||
- [ ] Transaction
|
||||
- [ ] Other multi threading
|
||||
- [ ] Query optimization
|
||||
- [ ] Index
|
||||
|
||||
#### v0.7 - Safety
|
||||
- [ ] Metrics
|
||||
- [ ] Durability
|
||||
|
||||
#### v0.8 - Docs
|
||||
- [ ] ZiQL tuto
|
||||
- [ ] Deployment tuto
|
||||
- [ ] Code docs
|
||||
- [ ] CLI help
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
# Schema
|
||||
|
||||
In ZipponDB, data is organized and manipulated using structures, or structs, rather than traditional tables. A struct is defined by a name, such as `User`, and members, such as `name` and `age`.
|
||||
|
||||
## Defining a Schema
|
||||
|
||||
To declare structs for use in your database, create a separate file containing the schema definitions. Below is an example of a simple schema file:
|
||||
```lua
|
||||
User (
|
||||
name: str,
|
||||
email: str,
|
||||
best_friend: User,
|
||||
)
|
||||
```
|
||||
|
||||
In this example, the `best_friend` member is a reference to another `User`.
|
||||
|
||||
Here's a more complex example featuring multiple structs:
|
||||
```lua
|
||||
User (
|
||||
name: str,
|
||||
email: str,
|
||||
friends: []User,
|
||||
posts: []Post,
|
||||
comments: []Comment,
|
||||
)
|
||||
|
||||
Post (
|
||||
title: str,
|
||||
image: str,
|
||||
at: date,
|
||||
like_by: []User,
|
||||
comments: []Comment,
|
||||
)
|
||||
|
||||
Comment (
|
||||
content: str,
|
||||
at: date,
|
||||
like_by: []User,
|
||||
)
|
||||
```
|
||||
|
||||
*Note: The [] symbol preceding a type indicates an array of that type. For example, []User represents an array of User structs.*
|
||||
|
||||
## Schema Migration - Not yet implemented
|
||||
|
||||
In future releases, ZipponDB will support schema updates, allowing you to modify existing structs or add new ones, and then apply these changes to your database. Currently, schema modifications are not possible once the database has been initialized.
|
||||
|
||||
I will add commands or query to add, delete and update struct in the schema. Maybe the schema will be a Struct itself with a schema like that:
|
||||
|
||||
```lua
|
||||
Struct (
|
||||
name: str,
|
||||
members: []Member,
|
||||
)
|
||||
|
||||
Member (
|
||||
name: str,
|
||||
type: int,
|
||||
)
|
||||
```
|
||||
|
||||
Like that can just do ZiQL query directly on it.
|
||||
|
||||
### Planned Migration Features
|
||||
|
||||
- Add new members to existing structs
|
||||
- Modify or remove existing members
|
||||
- Rename structs or members
|
||||
- Update relationships between structs
|
||||
- More...
|
||||
@@ -1,15 +0,0 @@
|
||||
# Single file
|
||||
|
||||
In the future I will migrate into a single file database like SQLite.
|
||||
|
||||
## FileBlok
|
||||
|
||||
A blok is like memory but for file. It has a starting point and a size and can hold entities or FileVar.
|
||||
Everything I will save will be linked into a Blok and I can create and delete them at will. The size is in the config and can't change.
|
||||
|
||||
In SQLite, it is what they call it a page I think. Similare thing.
|
||||
|
||||
## FileVar
|
||||
|
||||
A FileVar is a single value but saved in a file. This have a Blok, a position, a size and a type.
|
||||
For string, I will create something different I think, with a size max and a len, and can request more if needed.
|
||||
@@ -1,8 +0,0 @@
|
||||
- [ ] Array manipulation
|
||||
- [ ] Some time keyword like NOW
|
||||
- [X] Benchmark command
|
||||
|
||||
## Run in WASM for a demo
|
||||
|
||||
This could be fun, make a small demo where you get a wasm that run the database locally in the browser.
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
# Intro
|
||||
|
||||
TODO
|
||||
|
||||
***Note: Code snippets in this documentation are simplified examples and may not represent the actual codebase.***
|
||||
|
||||
## Tokenizers
|
||||
|
||||
Tokenizers are responsible for converting a buffer string into a list of tokens. Each token has a `Tag` enum that represents its type, such as `equal` for the `=` symbol, and a `Loc` struct with start and end indices that represent its position in the buffer.
|
||||
|
||||
All tokenizers work similarly and are based on the [zig tokenizer.](https://github.com/ziglang/zig/blob/master/lib/std/zig/tokenizer.zig) They have two main methods: next, which returns the next token, and getTokenSlice, which returns the slice of the buffer that represents the token.
|
||||
|
||||
Here's an example of how to use a tokenizer:
|
||||
```zig
|
||||
const toker = Tokenizer.init(buff);
|
||||
const token = toker.next();
|
||||
std.debug.print("{s}", .{toker.getTokenSlice(token)});
|
||||
```
|
||||
|
||||
Tokenizers are often used in a loop until the `end` tag is reached. In each iteration, the next token is retrieved and processed based on its tag. Here's a simple example:
|
||||
```zig
|
||||
const toker = Tokenizer.init(buff);
|
||||
var token = toker.next();
|
||||
while (token.tag != .end) : (token = toker.next()) switch (token.tag) {
|
||||
.equal => std.debug.print("{s}", .{toker.getTokenSlice(token)}),
|
||||
else => {},
|
||||
}
|
||||
```
|
||||
|
||||
### Available Tokenizers
|
||||
|
||||
There are four different tokenizers in ZipponDB:
|
||||
|
||||
- **ZiQL:** Tokenizer for the query language.
|
||||
- **cli:** Tokenizer the commands.
|
||||
- **schema:** Tokenizer for the schema file.
|
||||
|
||||
Each tokenizer has its own set of tags and parsing rules, but they all work similarly.
|
||||
|
||||
## Parser
|
||||
|
||||
Parsers are the next step after tokenization. They take tokens and perform actions or raise errors. There are three parsers in ZipponDB: one for ZiQL, one for schema files, and one for CLI commands.
|
||||
|
||||
A parser has a `State` enum and a `Tokenizer` instance as members, and a parse method that processes tokens until the `end` state is reached.
|
||||
|
||||
Here's an example of how a parser works:
|
||||
```zig
|
||||
var state = .start;
|
||||
var token = self.toker.next();
|
||||
while (state != .end) : (token = self.toker.next()) switch (state) {
|
||||
.start => switch (token.tag) {
|
||||
.identifier => self.addStruct(token),
|
||||
else => printError("Error: Expected a struct name.", token),
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
```
|
||||
|
||||
The parser's state is updated based on the combination of the current state and token tag. This process continues until the `end` state is reached.
|
||||
|
||||
The ZiQL parser uses different methods for parsing:
|
||||
|
||||
- `parse`: The main parsing method that calls other methods.
|
||||
- `parseFilter`: Creates a filter tree from the query.
|
||||
- `parseCondition`: Creates a condition from a part of the query.
|
||||
- `parseAdditionalData`: Populates additional data from the query.
|
||||
- `parseNewData`: Returns a string map with key-value pairs from the query.
|
||||
- `parseOption`: Not implemented yet.
|
||||
|
||||
## File parsing
|
||||
|
||||
File parsing is done through a small library that I did named [ZipponData](https://github.com/MrBounty/ZipponData).
|
||||
|
||||
It is minimal and fast, it can parse 1_000_000 entity in 0.3s on one thread
|
||||
on a 7 7800X3D at around 4.5GHz with a Samsung SSD 980 PRO 2TB (up to 7,000/5,100MB/s for read/write speed).
|
||||
|
||||
To read a file, you create an iterator for a single file and then you can iterate with `.next()`. It will return an array of `Data`. This make everything very easy to use.
|
||||
|
||||
```zig
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
const allocator = std.testing.allocator;
|
||||
|
||||
// 0. Make a temporary directory
|
||||
try std.fs.cwd().makeDir("tmp");
|
||||
const dir = try std.fs.cwd().openDir("tmp", .{});
|
||||
|
||||
// 1. Create a file
|
||||
try createFile("test", dir);
|
||||
|
||||
// 2. Create some Data
|
||||
const data = [_]Data{
|
||||
Data.initInt(1),
|
||||
Data.initFloat(3.14159),
|
||||
Data.initInt(-5),
|
||||
Data.initStr("Hello world"),
|
||||
Data.initBool(true),
|
||||
Data.initUnix(2021),
|
||||
};
|
||||
|
||||
// 3. Create a DataWriter
|
||||
var dwriter = try DataWriter.init("test", dir);
|
||||
defer dwriter.deinit(); // This just close the file
|
||||
|
||||
// 4. Write some data
|
||||
try dwriter.write(&data);
|
||||
try dwriter.write(&data);
|
||||
try dwriter.flush(); // Dont forget to flush !
|
||||
|
||||
// 5. Create a schema
|
||||
// A schema is how the iterator will parse the file.
|
||||
// If you are wrong here, it will return wrong/random data
|
||||
// And most likely an error when iterating in the while loop
|
||||
const schema = &[_]DType{
|
||||
.Int,
|
||||
.Float,
|
||||
.Int,
|
||||
.Str,
|
||||
.Bool,
|
||||
.Unix,
|
||||
};
|
||||
|
||||
// 6. Create a DataIterator
|
||||
var iter = try DataIterator.init(allocator, "test", dir, schema);
|
||||
defer iter.deinit();
|
||||
|
||||
// 7. Iterate over data
|
||||
while (try iter.next()) |row| {
|
||||
std.debug.print("Row: {any}\n", .{ row });
|
||||
}
|
||||
|
||||
// 8. Delete the file (Optional ofc)
|
||||
try deleteFile("test", dir);
|
||||
try std.fs.cwd().deleteDir("tmp");
|
||||
}
|
||||
```
|
||||
|
||||
## Engines
|
||||
|
||||
ZipponDB segregate responsability with Engines.
|
||||
|
||||
For example the `FileEngine` is the only place where files used, for both writting and reading. This simplify refactoring, testing, etc.
|
||||
|
||||
### DBEngine
|
||||
|
||||
This is just a wrapper around all other Engines to keep them at the same place. This doesnt do anything except storing other Engines.
|
||||
|
||||
This can be find in `main.zig`, in the `main` function.
|
||||
|
||||
### FileEngine
|
||||
|
||||
The `FileEngine` is responsible for managing files, including reading and writing.
|
||||
|
||||
Most methods will parse all files of a struct and evaluate them with a filter and do stuff if `true`. For example `parseEntities` will parse all entities and if the filter return `true`,
|
||||
will write using the writer argument a JSON object with the entity's data.
|
||||
|
||||
Those methods are usually sperated into 2 methods. The main one and a `OneFile` version, e.g. `parseEntitiesOneFile`. The main one will call a thread for each file using multiple `OneFile` version.
|
||||
This is how multi-threading is done.
|
||||
|
||||
### SchemaEngine
|
||||
|
||||
The `SchemaEngine` manage everything related to schemas.
|
||||
|
||||
This is mostly used to store a list of `SchemaStruct`, with is just one struct as defined in the schema. With all member names, data types, links, etc.
|
||||
|
||||
This is also here that I store the `UUIDFileIndex`, that is a map of UUID to file index. So I can quickly check if a UUID exist and in which file it is store.
|
||||
This work well but use a bit too much memory for me, around 220MB for 1_000_000 entities. I tried doing a Radix Trie but it doesn't use that much less memory, maybe I did a mistake somewhere.
|
||||
|
||||
### ThreadEngine
|
||||
|
||||
The `ThreadEngine` manage the thread pool of the database.
|
||||
|
||||
This is also where is stored the `ThreadSyncContext` that is use for each `OneFile` version of parsing methods in the `FileEngine`. This is the only atomix value currently used in the database.
|
||||
|
||||
## Multi-threading
|
||||
|
||||
ZipponDB uses multi-threading to improve performance. Each struct is saved in multiple `.zid` files, and a thread pool is used to process files concurrently. Each thread has its own buffered writer, and the results are concatenated and sent once all threads finish.
|
||||
|
||||
The only shared atomic values between threads are the number of found structs and the number of finished threads. This approach keeps things simple and easy to implement, avoiding parallel threads accessing the same file.
|
||||
|
||||
## Data Structures
|
||||
|
||||
### AdditionalData
|
||||
|
||||
AdditionalData keep what is between `[]`. It is composed of 2 struct `AdditionalData` and `AdditionalDataMember`.
|
||||
|
||||
`AdditionalDataMember` have the name of the member, it's position in the schema file and an `AdditionalData`.
|
||||
|
||||
`AdditionalData` have a limit (the first part `[100]`), and a list of `AdditionalDataMember`.
|
||||
|
||||
### Filters
|
||||
|
||||
A filter is a series of condition. It use a tree approach, by that I mean the filter have a root node that is either a condition or have 2 others nodes (left and right).
|
||||
|
||||
For example the filter `{name = 'Bob'}` have one root node that is the condition. So when I evaluate the struct, I just check this condition.
|
||||
|
||||
Now for like `{name = 'Bob' AND age > 0}`, the root node have as left node the condition `name = 'Bob'` and right node the condition `age > 0`.
|
||||
|
||||
To look like that:
|
||||
```
|
||||
AND
|
||||
/ \
|
||||
OR OR
|
||||
/ \ / \
|
||||
name name age age
|
||||
='A' ='B' >80 <20
|
||||
```
|
||||
|
||||
### Condition
|
||||
|
||||
A condition is part of filters. It is one 'unit of condition'. For example `name = 'Bob'` is one condition.
|
||||
`name = 'Bob' and age > 0` are 2 conditions and one filter. It is created inside `parseCondition` in the `ziqlParser`.
|
||||
|
||||
A condition have those infos:
|
||||
|
||||
- value: ConditionValue. E.g. `32`
|
||||
- operation: ComparisonOperator. E.g. `equal` or `in`
|
||||
- data_type: DataType. E.g. `int` or `str`
|
||||
- data_index: usize. This is the index in when parsing returned by zid `DataIterator`
|
||||
|
||||
### NewData
|
||||
|
||||
NewData is a map with member name as key and ConditionValue as value, it is created when parsing and is use to add data into a file.
|
||||
I transform ConditionValue into Zid Data. Maybe I can directly do a map member name -> zid Data ?
|
||||
|
||||
### RelationMap
|
||||
|
||||
A `RelationMap` is use when I need to return relationship. Let's say we have this query `GRAB User [orders [date]]`.
|
||||
|
||||
The `RelationMap` have a struct_name, here Order. A member name, here orders. A map with UUID as key and a string as value.
|
||||
|
||||
When I first init the map, I am parsing the first struct (here User). So it populate the map with empty string for entities that I want to return.
|
||||
Here it will be UUID of Order.
|
||||
|
||||
Then I parse Order file and add the string to the right UUID, skipping UUID that are not in the map.
|
||||
Once that done, I parse the JSON response that I generated when parsing User. Where a relationship should be, there is `{<|[16]u8|>}`, where `[16]u8` is the UUID of the entity that shoud be here.
|
||||
So now I can just replace it by the right key in the map.
|
||||
|
||||
## EntityWriter
|
||||
|
||||
This is responsable to transform the raw Data into a JSON, Table or other output format to send send to end user.
|
||||
Basically the last step before sending.
|
||||
@@ -1,195 +0,0 @@
|
||||
# ZipponData
|
||||
|
||||
ZipponData is a library developped in the context of [ZipponDB](https://github.com/MrBounty/ZipponDB/tree/v0.1.3).
|
||||
|
||||
The library intent to create a simple way to store and parse data from a file in the most efficient and fast way possible.
|
||||
|
||||
There is 6 data type available in ZipponData:
|
||||
|
||||
| Type | Zig type | Bytes in file |
|
||||
| --- | --- | --- |
|
||||
| int | i32 | 4 |
|
||||
| float | f64 | 8 |
|
||||
| bool | bool | 1 |
|
||||
| str | []u8 | 4 + len |
|
||||
| uuid | [16]u8 | 16 |
|
||||
| unix | u64 | 8 |
|
||||
|
||||
Each type have its array equivalent.
|
||||
|
||||
## Quickstart
|
||||
|
||||
1. Create a file with `createFile`
|
||||
2. Create some `Data`
|
||||
3. Create a `DataWriter`
|
||||
4. Write the data
|
||||
5. Create a schema
|
||||
6. Create an iterator with `DataIterator`
|
||||
7. Iterate over all value
|
||||
8. Delete the file with `deleteFile`
|
||||
|
||||
Here an example of how to use it:
|
||||
``` zig
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
const allocator = std.testing.allocator;
|
||||
|
||||
// 0. Make a temporary directory
|
||||
try std.fs.cwd().makeDir("tmp");
|
||||
const dir = try std.fs.cwd().openDir("tmp", .{});
|
||||
|
||||
// 1. Create a file
|
||||
try createFile("test", dir);
|
||||
|
||||
// 2. Create some Data
|
||||
const data = [_]Data{
|
||||
Data.initInt(1),
|
||||
Data.initFloat(3.14159),
|
||||
Data.initInt(-5),
|
||||
Data.initStr("Hello world"),
|
||||
Data.initBool(true),
|
||||
Data.initUnix(2021),
|
||||
};
|
||||
|
||||
// 3. Create a DataWriter
|
||||
var dwriter = try DataWriter.init("test", dir);
|
||||
defer dwriter.deinit(); // This just close the file
|
||||
|
||||
// 4. Write some data
|
||||
try dwriter.write(&data);
|
||||
try dwriter.write(&data);
|
||||
try dwriter.write(&data);
|
||||
try dwriter.write(&data);
|
||||
try dwriter.write(&data);
|
||||
try dwriter.write(&data);
|
||||
try dwriter.flush(); // Dont forget to flush !
|
||||
|
||||
// 5. Create a schema
|
||||
// A schema is how the iterator will parse the file.
|
||||
// If you are wrong here, it will return wrong/random data
|
||||
// And most likely an error when iterating in the while loop
|
||||
const schema = &[_]DType{
|
||||
.Int,
|
||||
.Float,
|
||||
.Int,
|
||||
.Str,
|
||||
.Bool,
|
||||
.Unix,
|
||||
};
|
||||
|
||||
// 6. Create a DataIterator
|
||||
var iter = try DataIterator.init(allocator, "test", dir, schema);
|
||||
defer iter.deinit();
|
||||
|
||||
// 7. Iterate over data
|
||||
while (try iter.next()) |row| {
|
||||
std.debug.print("Row: {any}\n", .{ row });
|
||||
}
|
||||
|
||||
// 8. Delete the file (Optional ofc)
|
||||
try deleteFile("test", dir);
|
||||
try std.fs.cwd().deleteDir("tmp");
|
||||
}
|
||||
```
|
||||
|
||||
***Note: The dir can be null and it will use cwd.***
|
||||
|
||||
## Array
|
||||
|
||||
All data type have an array equivalent. To write an array, you need to first encode it using `allocEncodArray` before writing it.
|
||||
This use an allocator so you need to free what it return.
|
||||
|
||||
When read, an array is just the raw bytes. To get the data itself, you need to create an `ArrayIterator`. Here an example:
|
||||
|
||||
```zig
|
||||
pub fn main() !void {
|
||||
const allocator = std.testing.allocator;
|
||||
|
||||
// 0. Make a temporary directory
|
||||
try std.fs.cwd().makeDir("array_tmp");
|
||||
const dir = try std.fs.cwd().openDir("array_tmp", .{});
|
||||
|
||||
// 1. Create a file
|
||||
try createFile("test", dir);
|
||||
|
||||
// 2. Create and encode some Data
|
||||
const int_array = [4]i32{ 32, 11, 15, 99 };
|
||||
const data = [_]Data{
|
||||
Data.initIntArray(try allocEncodArray.Int(allocator, &int_array)), // Encode
|
||||
};
|
||||
defer allocator.free(data[0].IntArray); // DOnt forget to free it
|
||||
|
||||
// 3. Create a DataWriter
|
||||
var dwriter = try DataWriter.init("test", dir);
|
||||
defer dwriter.deinit();
|
||||
|
||||
// 4. Write some data
|
||||
try dwriter.write(&data);
|
||||
try dwriter.flush();
|
||||
|
||||
// 5. Create a schema
|
||||
const schema = &[_]DType{
|
||||
.IntArray,
|
||||
};
|
||||
|
||||
// 6. Create a DataIterator
|
||||
var iter = try DataIterator.init(allocator, "test", dir, schema);
|
||||
defer iter.deinit();
|
||||
|
||||
// 7. Iterate over data
|
||||
var i: usize = 0;
|
||||
if (try iter.next()) |row| {
|
||||
|
||||
// 8. Iterate over array
|
||||
var array_iter = ArrayIterator.init(&row[0]); // Sub array iterator
|
||||
while (array_iter.next()) |d| {
|
||||
try std.testing.expectEqual(int_array[i], d.Int);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try deleteFile("test", dir);
|
||||
try std.fs.cwd().deleteDir("array_tmp");
|
||||
}
|
||||
```
|
||||
|
||||
## Benchmark
|
||||
|
||||
Done on a AMD Ryzen 7 7800X3D with a Samsung SSD 980 PRO 2TB (up to 7,000/5,100MB/s for read/write speed) on one thread.
|
||||
|
||||
Data use:
|
||||
```zig
|
||||
const schema = &[_]DType{
|
||||
.Int,
|
||||
.Float,
|
||||
.Int,
|
||||
.Str,
|
||||
.Bool,
|
||||
.Unix,
|
||||
};
|
||||
|
||||
const data = &[_]Data{
|
||||
Data.initInt(1),
|
||||
Data.initFloat(3.14159),
|
||||
Data.initInt(-5),
|
||||
Data.initStr("Hello world"),
|
||||
Data.initBool(true),
|
||||
Data.initUnix(2021),
|
||||
};
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
| Number of Entity | Total Write Time (ms) | Average Write Time / entity (μs) | Total Read Time (ms) | Average Read Time / entity (μs) | File Size (kB) |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | 0.01 | 13.63 | 0.025 | 25.0 | 0.04 |
|
||||
| 10 | 0.01 | 1.69 | 0.03 | 3.28 | 0.4 |
|
||||
| 100 | 0.04 | 0.49 | 0.07 | 0.67 | 4.0 |
|
||||
| 1_000 | 0.36 | 0.36 | 0.48 | 0.48 | 40 |
|
||||
| 10_000 | 3.42 | 0.34 | 4.67 | 0.47 | 400 |
|
||||
| 100_000 | 36.39 | 0.36 | 48.00 | 0.49 | 4_000 |
|
||||
| 1_000_000 | 361.41 | 0.36 | 481.00 | 0.48 | 40_000 |
|
||||
|
||||
***Note: You can check [benchmark](/ZipponDB/Benchmark) to see performance of the real database using multi-threading. Was able to parse 1_000_000 users in less than 100ms***
|
||||
@@ -1,40 +0,0 @@
|
||||
# About
|
||||
|
||||
## Me
|
||||
|
||||
ZipponDB is developped by a single person, [Adrien Bouvais](https://github.com/MrBounty).
|
||||
|
||||
I started this project because I wanted to learn a lot of things:
|
||||
|
||||
* Database
|
||||
* Zig
|
||||
* CI/CD
|
||||
* Data structures
|
||||
* Algorithms
|
||||
* Documentation
|
||||
* Memory management
|
||||
* High performance
|
||||
* Low level programming
|
||||
* ...
|
||||
|
||||
### Why
|
||||
|
||||
I wanted to create a "real" project, not just some TODO app. But something original with actually everything.
|
||||
That's why I added automatic documentation update when push in main. Or automatic build and release when I push a new tag. And why I make it look like a proper open-source project.
|
||||
|
||||
I didn't research that much how other db do stuff. I wanted to just do it, figure it out and make silly mistake. That how you learn.
|
||||
I may take this knowledge and try to do more niche database, something maybe a bit more through upfront.
|
||||
Because here I just wrote the simpliest query I could think of that can do easy relationship.
|
||||
But let's be honest, that's kind of a mess. I more want to do like a vector db or tigerbeetle and there transaction database.
|
||||
|
||||
Or just just simply a SQL db. I mean I don't think it would be that difficult based on what I already did.
|
||||
|
||||
### How
|
||||
|
||||
I came into this project with 0 real knowledge of how a database work and a small week-end of coding zig. I didn't read that much about how other people make databases.
|
||||
My goal was more to learn by mistake, doing it myself. I spended a lot of time at the beguining planing how the database will work inside, before coding.
|
||||
|
||||
For the how itself, I solved one small problem at the time. 'How to open a file ?', 'How to read and write bytes ?', 'How to do a tokenizer ?', etc... And litle by litle,
|
||||
you go closer and closer to your objectif.
|
||||
|
||||
I learned a lot of thing with this project. And even if I would do some part differently if I do it again, I think it is a fairly decent piece of software.
|
||||
@@ -1,60 +0,0 @@
|
||||
# Build
|
||||
|
||||
On this page, I will show you how to build ZipponDB from source.
|
||||
|
||||
## 1. Get Zig
|
||||
|
||||
First thing first, <a href="https://ziglang.org/" target="_blank">go get zig</a>.
|
||||
|
||||
## 2. Clone repo
|
||||
|
||||
Simple enough, clone ZipponDB repository and cd into it.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/MrBounty/ZipponDB
|
||||
cd ZipponDB
|
||||
```
|
||||
|
||||
## 3. Config
|
||||
|
||||
In `lib/config.zig` you will find a config file. There is few parameters and they are comptime for now (can't change from cli). But more will be added.
|
||||
|
||||
Parameter | Default | Description
|
||||
----- | ----- | ---------------
|
||||
MAX_FILE_SIZE | 1Mb | Max size of each individual file where data is store.
|
||||
CPU_CORE | 16 | Number of thread the pool will use. (At least 4 recommended for db > 100Mb)
|
||||
|
||||
## 4. build
|
||||
|
||||
```
|
||||
zig build
|
||||
```
|
||||
|
||||
Create 2 binaries in `zig-out/bin`:
|
||||
|
||||
* **zippondb:** The database CLI.
|
||||
* **benchmark:** Run and print a benchmark.
|
||||
|
||||
### build run
|
||||
|
||||
```
|
||||
zig build run
|
||||
```
|
||||
|
||||
Build and run the CLI.
|
||||
|
||||
### build benchmark
|
||||
|
||||
```
|
||||
zig build benchmark
|
||||
```
|
||||
|
||||
Build and run the benchmark.
|
||||
|
||||
### build test
|
||||
|
||||
```
|
||||
zig build test
|
||||
```
|
||||
|
||||
Build and run tests.
|
||||
@@ -1,111 +0,0 @@
|
||||
# Command Line Interface
|
||||
|
||||
ZipponDB use a CLI to interact, there is few commands available for now as focus was given to ZiQL. But more commands will be added in the future.
|
||||
|
||||
## run
|
||||
|
||||
Run a ZiQL query on the selected database.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```go
|
||||
run "QUERY" // (1)!
|
||||
```
|
||||
|
||||
1. Note that query need to be between ""
|
||||
|
||||
## db
|
||||
|
||||
### db metrics
|
||||
|
||||
Print some metrics from the db, including: Size on disk and number of entities stored.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```
|
||||
db metrics
|
||||
```
|
||||
|
||||
### db new
|
||||
|
||||
Create a new empty directory that can be then initialize with a schema.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```
|
||||
db new path/to/dir
|
||||
```
|
||||
|
||||
### db use
|
||||
|
||||
Select an already created database with `db new`.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```
|
||||
db use path/to/dir
|
||||
```
|
||||
|
||||
### db state
|
||||
|
||||
Return the state of the database, either `Ok` or `MissingDatabase` if no database selected or `MissingSchema` if no schema was initialize.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```
|
||||
db state
|
||||
```
|
||||
|
||||
## schema
|
||||
|
||||
### schema use
|
||||
|
||||
Attach a schema to the database using a schema file.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```
|
||||
schema use path/to/schema.file
|
||||
```
|
||||
|
||||
### schema describe
|
||||
|
||||
Print the schema use by the selected database.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```
|
||||
schema describe
|
||||
```
|
||||
|
||||
## dump
|
||||
|
||||
Export the entier database in a specific format.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```
|
||||
dump [FORMAT] [PATH]
|
||||
```
|
||||
|
||||
FORMAT options: `csv`, `json`, `zid`
|
||||
|
||||
## quit
|
||||
|
||||
Quit the CLI.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```
|
||||
quit
|
||||
```
|
||||
|
||||
## help
|
||||
|
||||
Write an help message.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```
|
||||
help
|
||||
```
|
||||
@@ -1,57 +0,0 @@
|
||||
# ZipponDB: A Minimalist Lightweight General Purpose Database in Zig
|
||||
|
||||
<style>
|
||||
.md-content .md-typeset h1 { display: none; }
|
||||
</style>
|
||||
|
||||
<p align="center">
|
||||
<a href="/ZipponDB"><img src="images/banner.png" alt="ZipponDB"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>Minimalist Lightweight General Purpose Database written in Zig</em>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
**Documentation**: <a href="/ZipponDB" target="_blank">https://mrbounty.github.io/ZipponDB</a>
|
||||
|
||||
**Source Code**: <a href="https://github.com/MrBounty/ZipponDB" target="_blank">https://github.com/MrBounty/ZipponDB</a>
|
||||
|
||||
---
|
||||
|
||||
ZipponDB is a database built from the ground up in Zig, with zero external dependencies. Designed for simplicity,
|
||||
performance, and portability, it's almost usable for small to
|
||||
medium applications that want a quick and simple database.
|
||||
|
||||
## Key Features
|
||||
|
||||
* **Small Binary:** ~300kb.
|
||||
* **Fast:** Parse millions of entities in milliseconds.*
|
||||
* **Relationship:** Build with focus on easy relationship.
|
||||
* **Query Language:** Use it's own stupid query language.
|
||||
* **No dependencies:** Depend on nothing, every line of code running is in the codebase and written for ZipponDB.
|
||||
* **Open-source:** Open-source under MIT licence.
|
||||
|
||||
<small>* Check <a href="/Benchmark">benchmark</a>.</small>
|
||||
|
||||
### Planned
|
||||
|
||||
* **Interface:** Small package to interact with ZipponDB from different programming language.
|
||||
* **Single file:** Like SQLite, ZipponDB's database aim to be a single file.
|
||||
* **Schema migration:** Update dynamically database schema.
|
||||
* **Custom index:** Speed up query with custom indexing.
|
||||
* **Better QL:** Improving ZiQL and adding features.
|
||||
* **Safety and Performance:** Improve general safty and performance.
|
||||
|
||||
<small>More info in the Roadmap.</small>
|
||||
|
||||
### Maybe
|
||||
|
||||
Those are idea for very long term with 0 promesse, maybe as extension.
|
||||
|
||||
* **Web interface:** Similare to EdgeDB, getting a webapp to query and config the DB.
|
||||
* **HTTP server:** Be able to start a simple HTTP server and send json.
|
||||
* **Auth:** Be able to auth users, maybe third-party OAuth.
|
||||
* **Per user database:** Like Turso.
|
||||
* **Performace:** I'm sure I can do better.
|
||||
* **Client side database:** Run it on the client side with WASM.
|
||||
@@ -1,35 +0,0 @@
|
||||
# Interface
|
||||
|
||||
Interfaces are way to use ZipponDB from other programming language.
|
||||
|
||||
## Python
|
||||
|
||||
**Not yet implemented, to give a general idea. Exact code may change.**
|
||||
|
||||
```python
|
||||
from zippondb import Client
|
||||
|
||||
db = Client("data")
|
||||
db.run("ADD User (name='Bob')")
|
||||
```
|
||||
|
||||
### Pydantic
|
||||
|
||||
I will most likely implement with Pydantic. Something like that:
|
||||
|
||||
```python
|
||||
from zippondb import Client, Model
|
||||
|
||||
class User(Model):
|
||||
name: str
|
||||
age: int
|
||||
|
||||
db = Client("data")
|
||||
users = db.run("GRAB User {}", model=User)
|
||||
```
|
||||
|
||||
`Model` is like `BaseModel` from pydantic but all member are optional. If no model provided, return a list of dict.
|
||||
|
||||
## Golang
|
||||
|
||||
TODO
|
||||
@@ -1,3 +0,0 @@
|
||||
# Log
|
||||
|
||||
I have logging implemented but badly and I don't log enough. I need to check this part.
|
||||
@@ -1,11 +0,0 @@
|
||||
# Release
|
||||
|
||||
## 0.1.8
|
||||
|
||||
First release.
|
||||
|
||||
Mostly to test the release pipeline with Github actions.
|
||||
Only include CLI, most ZiQL features here but still missing some part.
|
||||
Mostly missing thing around the database to make it usable.
|
||||
|
||||
[Link](https://github.com/MrBounty/ZipponDB/releases/tag/0.1.8)
|
||||
@@ -1,33 +0,0 @@
|
||||
# ADD
|
||||
|
||||
The `ADD` action adds entities to the database. The syntax is similar to `GRAB`, but uses `()`. This signifies that the data is not yet in the database.
|
||||
|
||||
Here's an example:
|
||||
```lua
|
||||
ADD User (name = 'Bob', age = 30, email = 'bob@email.com', scores = [1 100 44 82])
|
||||
```
|
||||
|
||||
You need to specify all members when adding an entity (default values comming).
|
||||
|
||||
|
||||
The `ADD` query will return a list of added IDs, e.g.:
|
||||
```
|
||||
["1e170a80-84c9-429a-be25-ab4657894653", "1e170a80-84c9-429a-be25-ab4657894654", ]
|
||||
```
|
||||
|
||||
And you can also add them in batch
|
||||
```
|
||||
ADD User (name = 'Bob', age = 30, email = 'bob@email.com', scores = [1 100 44 82]) (name = 'Bob2', age = 33, email = 'bob2@email.com', scores = [])
|
||||
```
|
||||
|
||||
You don't need to specify member's name for the second entity as long as the order is respected:
|
||||
```
|
||||
ADD User
|
||||
(name = 'Bob', age = 30, email = 'bob@email.com', scores = [1 100 44 82])
|
||||
('Bob2', 33, 'bob2@email.com', [])
|
||||
```
|
||||
|
||||
* Default value
|
||||
* Array default is empty
|
||||
* Link default is none
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# DELETE
|
||||
|
||||
Similar to `GRAB` but deletes all entities found using the filter and returns a list of deleted UUIDs.
|
||||
```js
|
||||
DELETE User {name = 'Bob'}
|
||||
```
|
||||
|
||||
The `DELETE` query will return a list of deleted IDs, e.g.:
|
||||
```
|
||||
["1e170a80-84c9-429a-be25-ab4657894653", "1e170a80-84c9-429a-be25-ab4657894654", ]
|
||||
```
|
||||
@@ -1,130 +0,0 @@
|
||||
# GRAB
|
||||
|
||||
The main action is `GRAB`, this will parse files and return data.
|
||||
|
||||
## Basic
|
||||
|
||||
Here's how to return all `User` without any filtering:
|
||||
```
|
||||
GRAB User
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To get all `User` above 30 years old:
|
||||
```
|
||||
GRAB User {age > 30}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To return only the member `name` of `User`:
|
||||
```
|
||||
GRAB User [name] {age > 30}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To return the 10 first `User`:
|
||||
```
|
||||
GRAB User [10] {age > 30}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
You can combine these options:
|
||||
```
|
||||
GRAB User [10; name] {age > 30}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Use multiple conditions:
|
||||
```
|
||||
GRAB User {name = 'Bob' AND (age > 30 OR age < 10)}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
GRAB queries return a list of JSON objects with the data inside, e.g:
|
||||
```
|
||||
[{id:"1e170a80-84c9-429a-be25-ab4657894653", name: "Gwendolyn Ray", age: 70, email: "austin92@example.org", scores: [ 77 ], friends: [], }, ]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ordering - Not yet implemented
|
||||
|
||||
To order the results by `name`:
|
||||
```js
|
||||
GRAB User [10; name] {age > 10} |ASC name|
|
||||
```
|
||||
|
||||
## Array
|
||||
You can use the `IN` operator to check if something is in an array:
|
||||
```js
|
||||
GRAB User { age > 10 AND name IN ['Adrien' 'Bob']}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Relationship
|
||||
|
||||
2 main things to remember with relationship:
|
||||
|
||||
* You can use filter inside filter.
|
||||
* You can use the dot `.` to refer to a relationship. (Not yet implemented)
|
||||
|
||||
Get `User` that have a best friend named Adrien:
|
||||
```js
|
||||
GRAB User { bestfriend IN { name = 'Adrien' } }
|
||||
```
|
||||
---
|
||||
|
||||
You can specify how much data to return and which members to include, even for links. In this example, I get 1 friend's name for 10 `User`:
|
||||
```js
|
||||
GRAB User [10; friends [1; name]]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
When using `IN`, it return all `User` that have AT LEAST one friend named Adrien:
|
||||
```js
|
||||
GRAB User { friends IN { name = 'Adrien' } }
|
||||
```
|
||||
---
|
||||
|
||||
To get `User` with all friends named Adrien:
|
||||
```js
|
||||
GRAB User { friends ALLIN { name = 'Adrien' } }
|
||||
```
|
||||
---
|
||||
|
||||
You can use `!` to say not in:
|
||||
```js
|
||||
GRAB User { friends !IN { name = 'Adrien' } }
|
||||
```
|
||||
---
|
||||
|
||||
## Dot - Not yet implemented
|
||||
|
||||
You can use `.` if you just want to do one comparison. Here I get all `User` that ordered at least one book:
|
||||
```js
|
||||
GRAB User { orders.products.category.name = 'Book' }
|
||||
```
|
||||
|
||||
Same as:
|
||||
```
|
||||
GRAB User {orders IN { products IN { category IN { name = 'Book'} } } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
You can also use the dot like that:
|
||||
|
||||
```js
|
||||
GRAB User.orders {name = 'Bob'}
|
||||
```
|
||||
|
||||
The filter is done on User but it return Order.
|
||||
It return all Order from User named 'Bob'.
|
||||
@@ -1,211 +0,0 @@
|
||||
# ZipponQL
|
||||
|
||||
ZipponDB uses its own query language, ZipponQL or ZiQL for short.
|
||||
The language goal is to be minimal, small and simple.
|
||||
Yet allowing powerful relationship.
|
||||
|
||||
Here are the key points to remember:
|
||||
|
||||
* 4 actions available: `GRAB`, `ADD`, `UPDATE`, `DELETE`
|
||||
* All queries start with an action followed by a struct name
|
||||
* `{}` are filters
|
||||
* `[]` specify how much and what data
|
||||
* `()` contain new or updated data (not already in files)
|
||||
* `||` for ordering
|
||||
* By default, all members that are not links are returned
|
||||
|
||||
***Disclaimer: The language may change a bit over time.***
|
||||
|
||||
---
|
||||
|
||||
## Making errors
|
||||
|
||||
When you make an error writing ZiQL, you should see something like this to help you understand where you made a mistake:
|
||||
```lua
|
||||
Error: Expected string
|
||||
GRAB User {name = Bob}
|
||||
^^^
|
||||
```
|
||||
|
||||
```
|
||||
Error: Expected ( or member name.
|
||||
GRAB User {name = 'Bob' AND {age > 10}}
|
||||
^
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## To return
|
||||
|
||||
What is between `[]` are what data to return. You can see it as the column name after `SELECT` in SQL and number after `LIMIT`.
|
||||
|
||||
Here I return just the name of all users:
|
||||
```
|
||||
GRAB User [name] {}
|
||||
```
|
||||
|
||||
|
||||
Here the 100 first users:
|
||||
```
|
||||
GRAB User [100] {}
|
||||
```
|
||||
|
||||
Here the name of the 100 first users:
|
||||
```
|
||||
GRAB User [100; name]
|
||||
```
|
||||
|
||||
You can also specify what data to return for each relationship returned. By default, query do not return any relationship.
|
||||
|
||||
This will return the name and best friend of all users:
|
||||
```
|
||||
GRAB User [name, best_friend] {}
|
||||
```
|
||||
|
||||
You can also specify what the best friend return:
|
||||
|
||||
```
|
||||
GRAB User [name, best_friend [name, age]] {}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Filters
|
||||
|
||||
What is between `{}` are filters, basically as a list of condition. This filter is use when parsing files and evaluate entities. You can see it as `WHERE` in SQL.
|
||||
|
||||
For example `{ name = 'Bob' }` will return `true` if the member `name` of the evaluated entity is equal to `Bob`. This is the most important thing in ZipponDB.
|
||||
|
||||
Here an example in a query:
|
||||
|
||||
```
|
||||
GRAB User {name = 'Bob' AND age > 44}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Relationship
|
||||
|
||||
Filter can be use inside filter. This allow simple yet powerfull relationship.
|
||||
|
||||
This query will return all users that have a best friend named 'Bob'.
|
||||
|
||||
```
|
||||
GRAB User {best_friend IN {name = 'Bob'}}
|
||||
```
|
||||
|
||||
You are obviously not limited to one depth. This will return all users that ordered at least one book in 2024:
|
||||
|
||||
```go
|
||||
GRAB User {
|
||||
orders IN {
|
||||
products IN {
|
||||
category IN {
|
||||
name = 'Book'
|
||||
}
|
||||
},
|
||||
date > 2024/01/01
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Same as:
|
||||
```go
|
||||
GRAB User {orders IN { products.category.name = 'Book' AND date > 2024/01/01} } // (1)!
|
||||
```
|
||||
|
||||
1. Dot not yet implemented
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Link query - Not yet implemented
|
||||
|
||||
You can also link query. Each query returns a list of UUID of a specific struct. You can use it in the next query.
|
||||
Here an example where I create a new `Comment` that I then append to the list of comment of one specific `User`.
|
||||
```
|
||||
ADD Comment (content='Hello world', at=NOW, like_by=[], by={id='000'})
|
||||
=> added_comment =>
|
||||
UPDATE User {id = '000'} TO (comments APPEND added_comment)
|
||||
```
|
||||
|
||||
The name between `=>` is the variable name of the list of UUID used for the next queries, you can have multiple one if the link has more than 2 queries.
|
||||
You can also just use one `=>` but the list of UUID is discarded in that case.
|
||||
|
||||
This can be use with GRAB too. So you can create variable before making the query. Here an example:
|
||||
```
|
||||
GRAB User {name = 'Bob'} => bobs =>
|
||||
GRAB User {age > 18} => adults =>
|
||||
GRAB User {IN adults AND !IN bobs}
|
||||
```
|
||||
|
||||
Which is the same as:
|
||||
```
|
||||
GRAB User {name != 'Bob' AND age > 18}
|
||||
```
|
||||
|
||||
<small>Note that the query are completly isolated, so files will be parse 3 times.</small>
|
||||
|
||||
Another example:
|
||||
```
|
||||
GRAB Product [1] {category.name = 'Book'} => book =>
|
||||
GRAB Order {date > 2024/01/01 AND products IN book} => book_orders =>
|
||||
GRAB User [100] {orders IN book_orders}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Actions
|
||||
|
||||
### [GRAB](/ZipponDB/ziql/grab)
|
||||
|
||||
The main action is `GRAB`, it parse files and return data.
|
||||
```js
|
||||
GRAB User {name = 'Bob' AND (age > 30 OR age < 10)}
|
||||
```
|
||||
|
||||
Using `[]` before the filter tell what to return.
|
||||
```js
|
||||
GRAB User [id, email] {name = 'Bob'}
|
||||
```
|
||||
|
||||
Relationship use filter within filter.
|
||||
```js
|
||||
GRAB User {best_friend IN {name = 'Bob'}}
|
||||
```
|
||||
|
||||
GRAB queries return a list of JSON objects, e.g:
|
||||
```
|
||||
[{id:"1e170a80-84c9-429a-be25-ab4657894653", name: "Gwendolyn Ray", age: 70, email: "austin92@example.org", scores: [ 77 ], friends: [], }, ]
|
||||
```
|
||||
|
||||
[More info.](/ZipponDB/ziql/grab)
|
||||
|
||||
### [ADD](/ZipponDB/ziql/add)
|
||||
|
||||
The `ADD` action adds one entity to the database. The syntax is similar to `GRAB`, but uses `()`. This signifies that the data is not yet in the database.
|
||||
```js
|
||||
ADD User (name = 'Bob', age = 30)
|
||||
```
|
||||
|
||||
[More info.](/ZipponDB/ziql/add)
|
||||
|
||||
### [DELETE](/ZipponDB/ziql/delete)
|
||||
|
||||
Similar to `GRAB` but deletes all entities found using the filter and returns a list of deleted UUIDs.
|
||||
```js
|
||||
DELETE User {name = 'Bob'}
|
||||
```
|
||||
|
||||
[More info.](/ZipponDB/ziql/delete)
|
||||
|
||||
### [UPDATE](/ZipponDB/ziql/update)
|
||||
|
||||
A mix of `GRAB` and `ADD`. It takes a filter first, then the new data.
|
||||
Here, we update the first 5 `User` entities named 'bob' to capitalize the name and become 'Bob':
|
||||
```js
|
||||
UPDATE User [5] {name='bob'} TO (name = 'Bob')
|
||||
```
|
||||
|
||||
[More info.](/ZipponDB/ziql/update)
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# UPDATE
|
||||
|
||||
A mix of `GRAB` and `ADD`. It takes a filter first, then the new data.
|
||||
Here, we update the first 5 `User` entities named 'adrien' to capitalize the name and become 'Adrien':
|
||||
```js
|
||||
UPDATE User [5] {name='adrien'} TO (name = 'Adrien')
|
||||
```
|
||||
|
||||
Note that, compared to `ADD`, you don't need to specify all members between `()`. Only the ones specified will be updated.
|
||||
|
||||
The `UPDATE` query will return a list of updated IDs, e.g.:
|
||||
```
|
||||
["1e170a80-84c9-429a-be25-ab4657894653", "1e170a80-84c9-429a-be25-ab4657894654", ]
|
||||
```
|
||||
|
||||
## Not yet implemented
|
||||
|
||||
You can use operations on values themselves when updating:
|
||||
```js
|
||||
UPDATE User {name = 'Bob'} TO (age += 1)
|
||||
```
|
||||
|
||||
## Array - Not yet implemented
|
||||
|
||||
You can also manipulate arrays, like adding or removing values:
|
||||
```js
|
||||
UPDATE User {name='Bob'} TO (scores APPEND 45)
|
||||
UPDATE User {name='Bob'} TO (scores APPEND [45 99])
|
||||
UPDATE User {name='Bob'} TO (scores REMOVEAT [0 1 2])
|
||||
```
|
||||
|
||||
Currently, there will be four keywords for manipulating lists:
|
||||
|
||||
- `APPEND`: Adds a value to the end of the list.
|
||||
- `REMOVE`: Checks the list, and if the value is found, deletes it.
|
||||
- `REMOVEAT`: Deletes the value at a specific index.
|
||||
- `CLEAR`: Removes all values from the array.
|
||||
- `POP`: Remove the last value.
|
||||
|
||||
Except for `CLEAR` and `POP`, which takes no value, each keyword can use one value or an array of values. If you choose an array, it will perform the operation on all values in the array.
|
||||
|
||||
For relationships, you can use filters:
|
||||
```js
|
||||
UPDATE User {name='Bob'} TO (comments APPEND {id = '000'})
|
||||
UPDATE User {name='Bob'} TO (comments REMOVE [1] { at < '2023/12/31'})
|
||||
```
|
||||
|
||||
I may include more options later.
|
||||
@@ -1,136 +0,0 @@
|
||||
# Vs SQL
|
||||
|
||||
A good way to see how ZipponQl work is to compare it to SQL.
|
||||
|
||||
## Select everything
|
||||
|
||||
```
|
||||
SELECT * FROM User
|
||||
```
|
||||
|
||||
```
|
||||
GRAB User {}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Selection on condition
|
||||
|
||||
```
|
||||
SELECT *
|
||||
FROM Users
|
||||
WHERE name = 'Bob'
|
||||
AND (age > 30 OR age < 10);
|
||||
```
|
||||
|
||||
```go
|
||||
GRAB User {name = 'Bob' AND (age > 30 OR age < 10)}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Select something
|
||||
|
||||
```
|
||||
SELECT name, age
|
||||
FROM Users
|
||||
LIMIT 100
|
||||
```
|
||||
|
||||
```go
|
||||
GRAB User [100; name, age] {}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Relationship
|
||||
|
||||
|
||||
```
|
||||
SELECT u1.name AS user_name, GROUP_CONCAT(u2.name || ' (' || u2.age || ')') AS friends_list
|
||||
FROM Users u1
|
||||
LEFT JOIN User u2 ON ',' || u1.friends || ',' LIKE '%,' || u2.id || ',%'
|
||||
WHERE u1.age > 30
|
||||
GROUP BY u1.name;
|
||||
```
|
||||
|
||||
```go
|
||||
GRAB User [name, friends [name, age]] {age > 30}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
SQL:
|
||||
```
|
||||
SELECT Users.name, Orders.orderID, Orders.orderDate
|
||||
FROM Users
|
||||
INNER JOIN Orders ON Users.UserID = Orders.UserID;
|
||||
```
|
||||
|
||||
ZiQL:
|
||||
```go
|
||||
GRAB User [name, order [id, date]] {}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
SQL:
|
||||
```
|
||||
SELECT
|
||||
U.name AS UserName,
|
||||
O.orderID,
|
||||
O.orderDate,
|
||||
P.productName,
|
||||
C.categoryName,
|
||||
OD.quantity,
|
||||
FROM
|
||||
Users U
|
||||
INNER JOIN Orders O ON U.UserID = O.UserID
|
||||
INNER JOIN OrderDetails OD ON O.OrderID = OD.OrderID
|
||||
INNER JOIN Products P ON OD.ProductID = P.ProductID
|
||||
INNER JOIN Categories C ON P.CategoryID = C.CategoryID
|
||||
WHERE
|
||||
O.orderDate >= '2023-01-01'
|
||||
AND C.categoryName != 'Accessories'
|
||||
ORDER BY
|
||||
O.orderDate DESC;
|
||||
```
|
||||
|
||||
ZiQL:
|
||||
```go
|
||||
GRAB User
|
||||
[ name, orders [id, date, details [quantity, products [name, category [name]]]]]
|
||||
{ orders IN {date >= 2023/01/01 AND details.products.category.name != 'Accessories' } } // (1)!
|
||||
| orders.date DESC | // (2)!
|
||||
```
|
||||
|
||||
1. Dot not yet implemented. But you can do it with:
|
||||
```
|
||||
details IN { products IN {category IN {name != 'Accessories'}}}
|
||||
```
|
||||
2. Ordering not yet implemented
|
||||
|
||||
---
|
||||
|
||||
SQL:
|
||||
```
|
||||
UPDATE orders o
|
||||
JOIN customers c ON o.customer_id = c.customer_id
|
||||
SET o.status = 'Priority'
|
||||
WHERE c.membership_level = 'Premium' AND o.order_date > '2023-01-01';
|
||||
```
|
||||
|
||||
ZiQL:
|
||||
```go
|
||||
GRAB User.orders { membership_level = 'Premium' } // (1)!
|
||||
=> premium_order => // (2)!
|
||||
UPDATE Order {id IN premium_order AND date > 2023/01/01}
|
||||
TO (status = 'Priority')
|
||||
```
|
||||
|
||||
1. Not yet implemented. Can't do it now.
|
||||
Here that mean filter are done on User but it return Order.
|
||||
It return all order of User with a premium membership.
|
||||
|
||||
2. Linked query not implemented
|
||||
|
||||
|
Before Width: | Height: | Size: 740 KiB After Width: | Height: | Size: 740 KiB |
|
Before Width: | Height: | Size: 488 KiB After Width: | Height: | Size: 488 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
@@ -1,73 +0,0 @@
|
||||
pub const BUFFER_SIZE = 1024 * 10; // Used a bit everywhere. The size for the schema for example. 10kB
|
||||
pub const MAX_FILE_SIZE = 1024 * 1024 * 5; // Tried multiple MAX_FILE_SIZE and found 5Mb is good
|
||||
pub const CPU_CORE = 0; // If 0, take maximum using std.Thread.getCpuCount()
|
||||
|
||||
// Debug
|
||||
pub const PRINT_STATE = false;
|
||||
pub const DONT_SEND = false;
|
||||
pub const DONT_SEND_ERROR = false;
|
||||
pub const RESET_LOG_AT_RESTART = false; // If true, will reset the log file at the start of the db, otherwise just keep adding to it
|
||||
|
||||
// Help message
|
||||
pub const HELP_MESSAGE = struct {
|
||||
pub const main: []const u8 =
|
||||
\\Welcome to ZipponDB v0.2!
|
||||
\\
|
||||
\\Available commands:
|
||||
\\run To run a query.
|
||||
\\db Create or chose a database.
|
||||
\\schema Initialize the database schema.
|
||||
\\dump To export data in other format and backup.
|
||||
\\quit Stop the CLI with memory safety.
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/cli
|
||||
\\
|
||||
;
|
||||
pub const db: []const u8 =
|
||||
\\Available commands:
|
||||
\\use Select or create a folder to use as database.
|
||||
\\metrics Print some metrics of the current database.
|
||||
\\state Print the current db state (Ok, MissingSchemaEngine, MissingFileEngine).
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/cli
|
||||
\\
|
||||
;
|
||||
pub const schema: []const u8 =
|
||||
\\Available commands:
|
||||
\\describe Print the schema use by the currently database.
|
||||
\\use Take the path to a schema file and initialize the database.
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/cli
|
||||
\\
|
||||
;
|
||||
pub const dump: []const u8 =
|
||||
\\Available commands:
|
||||
\\csv Export all database in a csv format.
|
||||
\\json Export all database in a json format. (Not implemented)
|
||||
\\zid Export all database in a zid format. (Not implemented)
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/cli
|
||||
\\
|
||||
;
|
||||
pub const no_engine: []const u8 =
|
||||
\\To start using ZipponDB you need to create a new database.
|
||||
\\This is a directory/folder that will be use to store data, logs, backup, ect.
|
||||
\\To create one use 'db new path/to/directory'. E.g. 'db new data'.
|
||||
\\Or use an existing one with 'db use'.
|
||||
\\
|
||||
\\You can also set the environment variable ZIPPONDB_PATH to the desire path.
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/cli
|
||||
\\
|
||||
;
|
||||
pub const no_schema: []const u8 =
|
||||
\\A database was found here `{s}` but no schema find inside.
|
||||
\\To start a database, you need to attach it a schema using a schema file.
|
||||
\\By using 'schema use path/to/schema'. For more informations on how to create a schema: TODO add link
|
||||
\\
|
||||
\\You can also set the environment variable ZIPPONDB_SCHEMA to the path to a schema file.
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/Schema
|
||||
\\
|
||||
;
|
||||
};
|
||||
@@ -1,73 +0,0 @@
|
||||
pub const BUFFER_SIZE = 1024 * 1024; // Used a bit everywhere. The size for the schema for example. 10kB
|
||||
pub const MAX_FILE_SIZE = 1024 * 1024 * 5; // Tried multiple MAX_FILE_SIZE and found 5Mb is good
|
||||
pub const CPU_CORE = 16;
|
||||
|
||||
// Debug
|
||||
pub const PRINT_STATE = false;
|
||||
pub const DONT_SEND = true;
|
||||
pub const DONT_SEND_ERROR = false;
|
||||
pub const RESET_LOG_AT_RESTART = false; // If true, will reset the log file at the start of the db, otherwise just keep adding to it
|
||||
|
||||
// Help message
|
||||
pub const HELP_MESSAGE = struct {
|
||||
pub const main: []const u8 =
|
||||
\\Welcome to ZipponDB v0.2!
|
||||
\\
|
||||
\\Available commands:
|
||||
\\run To run a query.
|
||||
\\db Create or chose a database.
|
||||
\\schema Initialize the database schema.
|
||||
\\dump To export data in other format and backup. (experimental)
|
||||
\\quit Stop the CLI with memory safety.
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/cli
|
||||
\\
|
||||
;
|
||||
pub const db: []const u8 =
|
||||
\\Available commands:
|
||||
\\use Select or create a folder to use as database.
|
||||
\\metrics Print some metrics of the current database.
|
||||
\\state Print the current db state (Ok, MissingSchemaEngine, MissingFileEngine).
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/cli
|
||||
\\
|
||||
;
|
||||
pub const schema: []const u8 =
|
||||
\\Available commands:
|
||||
\\describe Print the schema use by the currently database.
|
||||
\\use Take the path to a schema file and initialize the database.
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/cli
|
||||
\\
|
||||
;
|
||||
pub const dump: []const u8 =
|
||||
\\Available commands:
|
||||
\\csv Export all database in a csv format.
|
||||
\\json Export all database in a json format. (Not implemented)
|
||||
\\zid Export all database in a zid format. (Not implemented)
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/cli
|
||||
\\
|
||||
;
|
||||
pub const no_engine: []const u8 =
|
||||
\\To start using ZipponDB you need to create a new database.
|
||||
\\This is a directory/folder that will be use to store data, logs, backup, ect.
|
||||
\\To create one use 'db new path/to/directory'. E.g. 'db new data'.
|
||||
\\Or use an existing one with 'db use'.
|
||||
\\
|
||||
\\You can also set the environment variable ZIPPONDB_PATH to the desire path.
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/cli
|
||||
\\
|
||||
;
|
||||
pub const no_schema: []const u8 =
|
||||
\\A database was found here `{s}` but no schema find inside.
|
||||
\\To start a database, you need to attach it a schema using a schema file.
|
||||
\\By using 'schema init path/to/schema'. For more informations on how to create a schema: TODO add link
|
||||
\\
|
||||
\\You can also set the environment variable ZIPPONDB_SCHEMA to the path to a schema file.
|
||||
\\
|
||||
\\For more informations: https://mrbounty.github.io/ZipponDB/Schema
|
||||
\\
|
||||
;
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
pub const ZipponError = error{
|
||||
SchemaFileNotFound,
|
||||
SchemaNotConform,
|
||||
DATAFolderNotFound,
|
||||
StructFolderNotFound,
|
||||
CantMakeDir,
|
||||
CantMakeFile,
|
||||
CantOpenDir,
|
||||
CantOpenFile,
|
||||
StreamError,
|
||||
ReadError,
|
||||
InvalidUUID,
|
||||
InvalidDate,
|
||||
InvalidFileIndex,
|
||||
DirIterError,
|
||||
FileStatError,
|
||||
DeleteFileError,
|
||||
RenameFileError,
|
||||
ZipponDataError,
|
||||
AllocEncodError,
|
||||
MemoryError,
|
||||
SynthaxError,
|
||||
ThreadError,
|
||||
CantWriteEntity,
|
||||
WriteError,
|
||||
ConditionError,
|
||||
ParsingValueError,
|
||||
MemberNotFound,
|
||||
MemberMissing,
|
||||
StructNotFound,
|
||||
};
|
||||
@@ -1,466 +0,0 @@
|
||||
// Thanks to: https://github.com/nektro/zig-time/blob/master/time.zig
|
||||
|
||||
const std = @import("std");
|
||||
const string = []const u8;
|
||||
const time = @This();
|
||||
|
||||
pub const DateTime = struct {
|
||||
ms: u16,
|
||||
seconds: u8,
|
||||
minutes: u8,
|
||||
hours: u8,
|
||||
days: u8,
|
||||
months: u8,
|
||||
years: u16,
|
||||
|
||||
const Self = @This(); // Pas mal ca
|
||||
|
||||
pub fn initUnixMs(unix: u64) Self {
|
||||
return epoch_unix.addMs(unix);
|
||||
}
|
||||
|
||||
pub fn initUnix(unix: u64) Self {
|
||||
return epoch_unix.addSecs(unix);
|
||||
}
|
||||
|
||||
pub fn now() Self {
|
||||
return epoch_unix.addMs(@as(u64, @intCast(std.time.milliTimestamp())));
|
||||
}
|
||||
|
||||
/// Caller asserts that this is > epoch
|
||||
pub fn init(year: u16, month: u8, day: u8, hr: u8, min: u8, sec: u8, ms: u16) Self {
|
||||
return Self{
|
||||
.years = if (year < 1970) 1970 else year,
|
||||
.months = month,
|
||||
.days = day,
|
||||
.hours = hr,
|
||||
.minutes = min,
|
||||
.seconds = sec,
|
||||
.ms = ms,
|
||||
};
|
||||
}
|
||||
|
||||
pub const epoch_unix = Self{
|
||||
.ms = 0,
|
||||
.seconds = 0,
|
||||
.minutes = 0,
|
||||
.hours = 0,
|
||||
.days = 0,
|
||||
.months = 0,
|
||||
.years = 1970,
|
||||
};
|
||||
|
||||
pub fn eql(self: Self, other: Self) bool {
|
||||
return self.ms == other.ms and
|
||||
self.seconds == other.seconds and
|
||||
self.minutes == other.minutes and
|
||||
self.hours == other.hours and
|
||||
self.days == other.days and
|
||||
self.months == other.months and
|
||||
self.years == other.years;
|
||||
}
|
||||
|
||||
pub fn compareDate(self: Self, other: Self) bool {
|
||||
return self.days == other.days and
|
||||
self.months == other.months and
|
||||
self.years == other.years;
|
||||
}
|
||||
|
||||
pub fn compareTime(self: Self, other: Self) bool {
|
||||
return self.ms == other.ms and
|
||||
self.seconds == other.seconds and
|
||||
self.minutes == other.minutes and
|
||||
self.hours == other.hours;
|
||||
}
|
||||
|
||||
pub fn compareDatetime(self: Self, other: Self) bool {
|
||||
return self.ms == other.ms and
|
||||
self.seconds == other.seconds and
|
||||
self.minutes == other.minutes and
|
||||
self.hours == other.hours and
|
||||
self.days == other.days and
|
||||
self.months == other.months and
|
||||
self.years == other.years;
|
||||
}
|
||||
|
||||
// So as long as the count / unit, it continue adding the next unit, smart
|
||||
pub fn addMs(self: Self, count: u64) Self {
|
||||
if (count == 0) return self;
|
||||
var result = self;
|
||||
result.ms += @intCast(count % 1000);
|
||||
return result.addSecs(count / 1000);
|
||||
}
|
||||
|
||||
pub fn addSecs(self: Self, count: u64) Self {
|
||||
if (count == 0) return self;
|
||||
var result = self;
|
||||
result.seconds += @intCast(count % 60);
|
||||
return result.addMins(count / 60);
|
||||
}
|
||||
|
||||
pub fn addMins(self: Self, count: u64) Self {
|
||||
if (count == 0) return self;
|
||||
var result = self;
|
||||
result.minutes += @intCast(count % 60);
|
||||
return result.addHours(count / 60);
|
||||
}
|
||||
|
||||
pub fn addHours(self: Self, count: u64) Self {
|
||||
if (count == 0) return self;
|
||||
var result = self;
|
||||
result.hours += @intCast(count % 24);
|
||||
return result.addDays(count / 24);
|
||||
}
|
||||
|
||||
pub fn addDays(self: Self, count: u64) Self {
|
||||
if (count == 0) return self;
|
||||
var result = self;
|
||||
var input = count;
|
||||
|
||||
while (true) {
|
||||
const year_len = result.daysThisYear();
|
||||
if (input >= year_len) {
|
||||
result.years += 1;
|
||||
input -= year_len;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (true) {
|
||||
const month_len = result.daysThisMonth();
|
||||
if (input >= month_len) {
|
||||
result.months += 1;
|
||||
input -= month_len;
|
||||
|
||||
if (result.months == 12) {
|
||||
result.years += 1;
|
||||
result.months = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
{
|
||||
const month_len = result.daysThisMonth();
|
||||
if (result.days + input > month_len) {
|
||||
const left = month_len - result.days;
|
||||
input -= left;
|
||||
result.months += 1;
|
||||
result.days = 0;
|
||||
}
|
||||
result.days += @intCast(input);
|
||||
|
||||
if (result.days == result.daysThisMonth()) {
|
||||
result.months += 1;
|
||||
result.days = 0;
|
||||
}
|
||||
if (result.months == 12) {
|
||||
result.years += 1;
|
||||
result.months = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std.debug.assert(result.ms < 1000);
|
||||
std.debug.assert(result.seconds < 60);
|
||||
std.debug.assert(result.minutes < 60);
|
||||
std.debug.assert(result.hours < 24);
|
||||
std.debug.assert(result.days < result.daysThisMonth());
|
||||
std.debug.assert(result.months < 12);
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn addMonths(self: Self, count: u64) Self {
|
||||
if (count == 0) return self;
|
||||
var result = self;
|
||||
var input = count;
|
||||
while (input > 0) {
|
||||
const new = result.addDays(result.daysThisMonth());
|
||||
result = new;
|
||||
input -= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn addYears(self: Self, count: u64) Self {
|
||||
var result = self;
|
||||
for (0..count) |_| {
|
||||
result = result.addDays(result.daysThisYear());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn isLeapYear(self: Self) bool {
|
||||
return time.isLeapYear(self.years);
|
||||
}
|
||||
|
||||
pub fn daysThisYear(self: Self) u16 {
|
||||
return time.daysInYear(self.years);
|
||||
}
|
||||
|
||||
pub fn daysThisMonth(self: Self) u16 {
|
||||
return self.daysInMonth(self.months);
|
||||
}
|
||||
|
||||
fn daysInMonth(self: Self, month: u16) u16 {
|
||||
return time.daysInMonth(self.years, month);
|
||||
}
|
||||
|
||||
pub fn dayOfThisYear(self: Self) u16 {
|
||||
var ret: u16 = 0;
|
||||
for (0..self.months) |item| {
|
||||
ret += self.daysInMonth(@intCast(item));
|
||||
}
|
||||
ret += self.days;
|
||||
return ret;
|
||||
}
|
||||
|
||||
pub fn toUnix(self: Self) u64 {
|
||||
const x = self.toUnixMilli();
|
||||
return x / 1000;
|
||||
}
|
||||
|
||||
pub fn toUnixMilli(self: Self) u64 {
|
||||
var res: u64 = 0;
|
||||
res += self.ms;
|
||||
res += @as(u64, self.seconds) * std.time.ms_per_s;
|
||||
res += @as(u64, self.minutes) * std.time.ms_per_min;
|
||||
res += @as(u64, self.hours) * std.time.ms_per_hour;
|
||||
res += self.daysSinceEpoch() * std.time.ms_per_day;
|
||||
return res;
|
||||
}
|
||||
|
||||
fn daysSinceEpoch(self: Self) u64 {
|
||||
var res: u64 = 0;
|
||||
res += self.days;
|
||||
for (0..self.years - epoch_unix.years) |i| res += time.daysInYear(@intCast(i));
|
||||
for (0..self.months) |i| res += self.daysInMonth(@intCast(i));
|
||||
return res;
|
||||
}
|
||||
|
||||
/// fmt is based on https://momentjs.com/docs/#/displaying/format/
|
||||
pub fn format(self: Self, comptime fmt: string, writer: anytype) !void {
|
||||
if (fmt.len == 0) @compileError("DateTime: format string can't be empty");
|
||||
|
||||
@setEvalBranchQuota(100000);
|
||||
|
||||
comptime var s = 0;
|
||||
comptime var e = 0;
|
||||
comptime var next: ?FormatSeq = null;
|
||||
inline for (fmt, 0..) |c, i| {
|
||||
e = i + 1;
|
||||
|
||||
if (comptime std.meta.stringToEnum(FormatSeq, fmt[s..e])) |tag| {
|
||||
next = tag;
|
||||
if (i < fmt.len - 1) continue;
|
||||
}
|
||||
|
||||
if (next) |tag| {
|
||||
switch (tag) {
|
||||
.MM => try writer.print("{:0>2}", .{self.months + 1}),
|
||||
.M => try writer.print("{}", .{self.months + 1}),
|
||||
.Mo => try printOrdinal(writer, self.months + 1),
|
||||
.MMM => try printLongName(writer, self.months, &[_]string{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }),
|
||||
.MMMM => try printLongName(writer, self.months, &[_]string{ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }),
|
||||
|
||||
.Q => try writer.print("{}", .{self.months / 3 + 1}),
|
||||
.Qo => try printOrdinal(writer, self.months / 3 + 1),
|
||||
|
||||
.D => try writer.print("{}", .{self.days + 1}),
|
||||
.Do => try printOrdinal(writer, self.days + 1),
|
||||
.DD => try writer.print("{:0>2}", .{self.days + 1}),
|
||||
|
||||
.DDD => try writer.print("{}", .{self.dayOfThisYear() + 1}),
|
||||
.DDDo => try printOrdinal(writer, self.dayOfThisYear() + 1),
|
||||
.DDDD => try writer.print("{:0>3}", .{self.dayOfThisYear() + 1}),
|
||||
|
||||
.d => try writer.print("{}", .{@intFromEnum(self.weekday())}),
|
||||
.do => try printOrdinal(writer, @intFromEnum(self.weekday())),
|
||||
.dd => try writer.writeAll(@tagName(self.weekday())[0..2]),
|
||||
.ddd => try writer.writeAll(@tagName(self.weekday())),
|
||||
.dddd => try printLongName(writer, @intFromEnum(self.weekday()), &[_]string{ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }),
|
||||
.e => try writer.print("{}", .{@intFromEnum(self.weekday())}),
|
||||
.E => try writer.print("{}", .{@intFromEnum(self.weekday()) + 1}),
|
||||
|
||||
.w => try writer.print("{}", .{self.dayOfThisYear() / 7 + 1}),
|
||||
.wo => try printOrdinal(writer, self.dayOfThisYear() / 7 + 1),
|
||||
.ww => try writer.print("{:0>2}", .{self.dayOfThisYear() / 7 + 1}),
|
||||
|
||||
.Y => try writer.print("{}", .{self.years + 10000}),
|
||||
.YY => try writer.print("{:0>2}", .{self.years % 100}),
|
||||
.YYY => try writer.print("{}", .{self.years}),
|
||||
.YYYY => try writer.print("{:0>4}", .{self.years}),
|
||||
|
||||
.N => try writer.writeAll(@tagName(self.era())),
|
||||
.NN => try writer.writeAll("Anno Domini"),
|
||||
|
||||
.A => try printLongName(writer, self.hours / 12, &[_]string{ "AM", "PM" }),
|
||||
.a => try printLongName(writer, self.hours / 12, &[_]string{ "am", "pm" }),
|
||||
|
||||
.H => try writer.print("{}", .{self.hours}),
|
||||
.HH => try writer.print("{:0>2}", .{self.hours}),
|
||||
.h => try writer.print("{}", .{wrap(self.hours, 12)}),
|
||||
.hh => try writer.print("{:0>2}", .{wrap(self.hours, 12)}),
|
||||
.k => try writer.print("{}", .{wrap(self.hours, 24)}),
|
||||
.kk => try writer.print("{:0>2}", .{wrap(self.hours, 24)}),
|
||||
|
||||
.m => try writer.print("{}", .{self.minutes}),
|
||||
.mm => try writer.print("{:0>2}", .{self.minutes}),
|
||||
|
||||
.s => try writer.print("{}", .{self.seconds}),
|
||||
.ss => try writer.print("{:0>2}", .{self.seconds}),
|
||||
|
||||
.S => try writer.print("{}", .{self.ms / 100}),
|
||||
.SS => try writer.print("{:0>2}", .{self.ms / 10}),
|
||||
.SSS => try writer.print("{:0>3}", .{self.ms}),
|
||||
|
||||
.z => try writer.writeAll(@tagName(self.timezone)),
|
||||
.Z => try writer.writeAll("+00:00"),
|
||||
.ZZ => try writer.writeAll("+0000"),
|
||||
|
||||
.x => try writer.print("{}", .{self.toUnixMilli()}),
|
||||
.X => try writer.print("{}", .{self.toUnix()}),
|
||||
}
|
||||
next = null;
|
||||
s = i;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
',',
|
||||
' ',
|
||||
':',
|
||||
'-',
|
||||
'.',
|
||||
'T',
|
||||
'W',
|
||||
'/',
|
||||
=> {
|
||||
try writer.writeAll(&.{c});
|
||||
s = i + 1;
|
||||
continue;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn formatAlloc(self: Self, alloc: std.mem.Allocator, comptime fmt: string) !string {
|
||||
var list = std.ArrayList(u8).init(alloc);
|
||||
defer list.deinit();
|
||||
|
||||
try self.format(fmt, .{}, list.writer());
|
||||
return list.toOwnedSlice();
|
||||
}
|
||||
|
||||
const FormatSeq = enum {
|
||||
M, // 1 2 ... 11 12
|
||||
Mo, // 1st 2nd ... 11th 12th
|
||||
MM, // 01 02 ... 11 12
|
||||
MMM, // Jan Feb ... Nov Dec
|
||||
MMMM, // January February ... November December
|
||||
Q, // 1 2 3 4
|
||||
Qo, // 1st 2nd 3rd 4th
|
||||
D, // 1 2 ... 30 31
|
||||
Do, // 1st 2nd ... 30th 31st
|
||||
DD, // 01 02 ... 30 31
|
||||
DDD, // 1 2 ... 364 365
|
||||
DDDo, // 1st 2nd ... 364th 365th
|
||||
DDDD, // 001 002 ... 364 365
|
||||
d, // 0 1 ... 5 6
|
||||
do, // 0th 1st ... 5th 6th
|
||||
dd, // Su Mo ... Fr Sa
|
||||
ddd, // Sun Mon ... Fri Sat
|
||||
dddd, // Sunday Monday ... Friday Saturday
|
||||
e, // 0 1 ... 5 6 (locale)
|
||||
E, // 1 2 ... 6 7 (ISO)
|
||||
w, // 1 2 ... 52 53
|
||||
wo, // 1st 2nd ... 52nd 53rd
|
||||
ww, // 01 02 ... 52 53
|
||||
Y, // 11970 11971 ... 19999 20000 20001 (Holocene calendar)
|
||||
YY, // 70 71 ... 29 30
|
||||
YYY, // 1 2 ... 1970 1971 ... 2029 2030
|
||||
YYYY, // 0001 0002 ... 1970 1971 ... 2029 2030
|
||||
N, // BC AD
|
||||
NN, // Before Christ ... Anno Domini
|
||||
A, // AM PM
|
||||
a, // am pm
|
||||
H, // 0 1 ... 22 23
|
||||
HH, // 00 01 ... 22 23
|
||||
h, // 1 2 ... 11 12
|
||||
hh, // 01 02 ... 11 12
|
||||
k, // 1 2 ... 23 24
|
||||
kk, // 01 02 ... 23 24
|
||||
m, // 0 1 ... 58 59
|
||||
mm, // 00 01 ... 58 59
|
||||
s, // 0 1 ... 58 59
|
||||
ss, // 00 01 ... 58 59
|
||||
S, // 0 1 ... 8 9 (second fraction)
|
||||
SS, // 00 01 ... 98 99
|
||||
SSS, // 000 001 ... 998 999
|
||||
z, // EST CST ... MST PST
|
||||
Z, // -07:00 -06:00 ... +06:00 +07:00
|
||||
ZZ, // -0700 -0600 ... +0600 +0700
|
||||
x, // unix milli
|
||||
X, // unix
|
||||
};
|
||||
|
||||
pub fn since(self: Self, other_in_the_past: Self) Duration {
|
||||
return Duration{
|
||||
.ms = self.toUnixMilli() - other_in_the_past.toUnixMilli(),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const format = struct {
|
||||
pub const LT = "h:mm A";
|
||||
pub const LTS = "h:mm:ss A";
|
||||
pub const L = "MM/DD/YYYY";
|
||||
pub const l = "M/D/YYY";
|
||||
pub const LL = "MMMM D, YYYY";
|
||||
pub const ll = "MMM D, YYY";
|
||||
pub const LLL = LL ++ " " ++ LT;
|
||||
pub const lll = ll ++ " " ++ LT;
|
||||
pub const LLLL = "dddd, " ++ LLL;
|
||||
pub const llll = "ddd, " ++ lll;
|
||||
};
|
||||
|
||||
pub fn isLeapYear(year: u16) bool {
|
||||
var ret = false;
|
||||
if (year % 4 == 0) ret = true;
|
||||
if (year % 100 == 0) ret = false;
|
||||
if (year % 400 == 0) ret = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
pub fn daysInYear(year: u16) u16 {
|
||||
return if (isLeapYear(year)) 366 else 365;
|
||||
}
|
||||
|
||||
fn daysInMonth(year: u16, month: u16) u16 {
|
||||
const norm = [12]u16{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
const leap = [12]u16{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
const month_days = if (!isLeapYear(year)) norm else leap;
|
||||
return month_days[month];
|
||||
}
|
||||
|
||||
fn printOrdinal(writer: anytype, num: u16) !void {
|
||||
try writer.print("{}", .{num});
|
||||
try writer.writeAll(switch (num) {
|
||||
1 => "st",
|
||||
2 => "nd",
|
||||
3 => "rd",
|
||||
else => "th",
|
||||
});
|
||||
}
|
||||
|
||||
fn printLongName(writer: anytype, index: u16, names: []const string) !void {
|
||||
try writer.writeAll(names[index]);
|
||||
}
|
||||
|
||||
fn wrap(val: u16, at: u16) u16 {
|
||||
const tmp = val % at;
|
||||
return if (tmp == 0) at else tmp;
|
||||
}
|
||||
|
||||
pub const Duration = struct {
|
||||
ms: u64,
|
||||
};
|
||||
@@ -1,37 +0,0 @@
|
||||
// This file is just to expose what I need to grab
|
||||
|
||||
pub const UUID = @import("uuid.zig").UUID;
|
||||
pub const Zero = @import("uuid.zig").zero;
|
||||
pub const DateTime = @import("date.zig").DateTime;
|
||||
pub const OR = @import("uuid.zig").OR;
|
||||
pub const AND = @import("uuid.zig").AND;
|
||||
pub const s2t = @import("stringToType.zig");
|
||||
|
||||
/// Suported dataType for the DB
|
||||
/// Maybe start using a unionenum
|
||||
pub const DataType = enum {
|
||||
int,
|
||||
float,
|
||||
str,
|
||||
bool,
|
||||
link,
|
||||
self, // self represent itself, it is the id
|
||||
date,
|
||||
time,
|
||||
datetime,
|
||||
int_array,
|
||||
float_array,
|
||||
str_array,
|
||||
bool_array,
|
||||
date_array,
|
||||
time_array,
|
||||
datetime_array,
|
||||
link_array,
|
||||
|
||||
pub fn is_array(self: DataType) bool {
|
||||
return switch (self) {
|
||||
.int_array, .float_array, .str_array, .bool_array, .date_array, .time_array, .datetime_array, .link_array => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
};
|
||||