Add query module for searching

This commit is contained in:
Joakim Soderlund 2019-08-10 21:06:34 +00:00
parent aa619e862d
commit 36f182620b
6 changed files with 419 additions and 22 deletions

129
Cargo.lock generated
View file

@ -10,11 +10,6 @@ name = "autocfg"
version = "0.1.5" version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "0.1.9" version = "0.1.9"
@ -28,7 +23,7 @@ dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -46,7 +41,8 @@ version = "0.1.0"
dependencies = [ dependencies = [
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "nom 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"zip 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -61,6 +57,18 @@ name = "itoa"
version = "0.4.4" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lexical-core"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"stackvector 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.60" version = "0.2.60"
@ -68,16 +76,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "libflate" name = "libflate"
version = "0.1.25" version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "memchr"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nom"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lexical-core 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.41" version = "0.1.41"
@ -126,27 +148,48 @@ name = "rle-decode-fast"
version = "1.0.1" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "serde" name = "semver"
version = "1.0.97" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.97" version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -156,12 +199,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "stackvector"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "static_assertions"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "syn" name = "syn"
version = "0.15.40" version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
@ -189,6 +246,24 @@ name = "unicode-xid"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unreachable"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.7" version = "0.3.7"
@ -214,21 +289,23 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libflate 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "libflate 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[metadata] [metadata]
"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" "checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" "checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum lexical-core 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b0f90c979adde96d19eb10eb6431ba0c441e2f9e9bdff868b2f6f5114ff519"
"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" "checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
"checksum libflate 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "90c6f86f4b0caa347206f916f8b687b51d77c6ef8ff18d52dd007491fd580529" "checksum libflate 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "45c97cf62125b79dcac52d506acdc4799f21a198597806947fd5f40dc7b93412"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum nom 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9761d859320e381010a4f7f8ed425f2c924de33ad121ace447367c713ad561b"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd" "checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd"
@ -236,14 +313,22 @@ dependencies = [
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" "checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
"checksum serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "d46b3dfedb19360a74316866cef04687cd4d6a70df8e6a506c63512790769b72" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "c22a0820adfe2f257b098714323563dd06426502abbbce4f51b72ef544c5027f" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113"
"checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c"
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
"checksum syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)" = "bc945221ccf4a7e8c31222b9d1fc77aefdd6638eb901a6ce457a3dc29d4c31e8" "checksum stackvector 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1c4725650978235083241fab0fdc8e694c3de37821524e7534a1a9061d1068af"
"checksum static_assertions 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4f8de36da215253eb5f24020bfaa0646613b48bf7ebe36cdfa37c3b3b33b241"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View file

@ -14,6 +14,9 @@ features = ["serde"]
[dependencies.hex] [dependencies.hex]
version = "*" version = "*"
[dependencies.nom]
version = "5"
[dependencies.serde] [dependencies.serde]
version = "*" version = "*"
features = ["derive"] features = ["derive"]

View file

@ -2,6 +2,7 @@
pub mod archive; pub mod archive;
pub mod error; pub mod error;
pub mod query;
use std::env::args; use std::env::args;
use std::time::Instant; use std::time::Instant;

6
src/query/mod.rs Normal file
View file

@ -0,0 +1,6 @@
//! Query module.
mod optimizer;
mod parser;
pub use self::parser::parse;

87
src/query/optimizer.rs Normal file
View file

@ -0,0 +1,87 @@
//! Query optimizer.
use std::str::FromStr;
use chrono::prelude::*;
use super::parser::{Operator, Source};
use crate::archive::Story;
use crate::error::{Error, Result};
use Operator::*;
use Source::*;
type Filter = Box<dyn Fn(&Story) -> bool + Sync>;
type IntFn = Box<dyn Fn(&Story) -> i64 + Sync>;
type StrFn = Box<dyn Fn(&Story) -> &str + Sync>;
type DtuFn = Box<dyn Fn(&Story) -> &Option<DateTime<Utc>> + Sync>;
macro_rules! ok {
($func:expr) => {
Ok(Box::new($func))
};
}
pub fn optimize(src: Source, op: Operator, value: &str) -> Result<Filter> {
match src {
StrFn(f) => strfn(f, op, value),
IntFn(f) => intfn(f, op, value),
DtuFn(f) => dtufn(f, op, value),
}
}
fn strfn(f: StrFn, op: Operator, value: &str) -> Result<Filter> {
let value: String = match op {
Fuzzy => value.to_lowercase(),
_ => value.to_owned(),
};
match op {
Exact => ok!(move |s| f(s) == &value),
Fuzzy => ok!(move |s| f(s).to_lowercase().contains(&value)),
_ => Err(Error::query("Invalid operation for text type")),
}
}
fn intfn(f: IntFn, op: Operator, value: &str) -> Result<Filter> {
let value: i64 = value.parse().map_err(|e| match e {
_ => Error::query("Invalid value for number type"),
})?;
match op {
Exact => ok!(move |s| f(s) == value),
Fuzzy => ok!(move |s| f(s) == value),
LessThan => ok!(move |s| f(s) < value),
MoreThan => ok!(move |s| f(s) > value),
}
}
fn dtufn(f: DtuFn, op: Operator, value: &str) -> Result<Filter> {
let parsed = DateTime::from_str(value);
let value: DateTime<Utc> = parsed.map_err(|e| match e {
_ => Error::query("Invalid value for date type"),
})?;
let date = value.date();
match op {
Exact => ok!(move |s| match f(s) {
Some(dt) => dt == &value,
None => false,
}),
Fuzzy => ok!(move |s| match f(s) {
Some(dt) => dt.date() == date,
None => false,
}),
LessThan => ok!(move |s| match f(s) {
Some(dt) => dt < &value,
None => false,
}),
MoreThan => ok!(move |s| match f(s) {
Some(dt) => dt > &value,
None => false,
}),
}
}

215
src/query/parser.rs Normal file
View file

@ -0,0 +1,215 @@
//! Query parser.
use chrono::prelude::*;
use nom::character::complete::*;
use nom::error::ErrorKind as NomErrorKind;
use nom::sequence::*;
use nom::*;
use super::optimizer::optimize;
use crate::archive::Story;
use crate::error::*;
type Filter = Box<dyn Fn(&Story) -> bool + Sync>;
pub enum Source {
IntFn(Box<dyn Fn(&Story) -> i64 + Sync>),
StrFn(Box<dyn Fn(&Story) -> &str + Sync>),
DtuFn(Box<dyn Fn(&Story) -> &Option<DateTime<Utc>> + Sync>),
}
pub enum Operator {
Exact,
Fuzzy,
LessThan,
MoreThan,
}
macro_rules! sfn {
($func:expr) => {
|_| Source::StrFn(Box::new($func))
};
}
macro_rules! ifn {
($func:expr) => {
|_| Source::IntFn(Box::new($func))
};
}
macro_rules! dfn {
($func:expr) => {
|_| Source::DtuFn(Box::new($func))
};
}
named!(source<&str, Source>, preceded!(space0, alt!(
tag!("id") => { ifn!(|s| s.id as i64) } |
tag!("story") => { sfn!(|s| &s.title) } |
tag!("title") => { sfn!(|s| &s.title) } |
tag!("description") => { sfn!(|s| &s.description_html) } |
tag!("short description") => { sfn!(|s| &s.short_description) } |
tag!("url") => { sfn!(|s| &s.url) } |
tag!("modified") => { dfn!(|s| &s.date_modified) } |
tag!("published") => { dfn!(|s| &s.date_published) } |
tag!("updated") => { dfn!(|s| &s.date_updated) } |
tag!("chapters") => { ifn!(|s| s.num_chapters as i64) } |
tag!("comments") => { ifn!(|s| s.num_comments as i64) } |
tag!("dislikes") => { ifn!(|s| s.num_dislikes as i64) } |
tag!("likes") => { ifn!(|s| s.num_likes as i64) } |
tag!("total views") => { ifn!(|s| s.total_num_views as i64) } |
tag!("views") => { ifn!(|s| s.num_views as i64) } |
tag!("words") => { ifn!(|s| s.num_words as i64) } |
tag!("author") => { sfn!(|s| &s.author.name) } |
tag!("author name") => { sfn!(|s| &s.author.name) } |
tag!("author id") => { ifn!(|s| s.author.id as i64) } |
tag!("author joined") => { dfn!(|s| &s.author.date_joined) } |
tag!("path") => { sfn!(|s| &s.archive.path) } |
tag!("archive") => { sfn!(|s| &s.archive.path) } |
tag!("archive path") => { sfn!(|s| &s.archive.path) } |
tag!("entry checked") => { dfn!(|s| &s.archive.date_checked) } |
tag!("entry created") => { dfn!(|s| &s.archive.date_created) } |
tag!("entry fetched") => { dfn!(|s| &s.archive.date_fetched) } |
tag!("entry updated") => { dfn!(|s| &s.archive.date_updated) }
)));
named!(operator<&str, Operator>, preceded!(space0, alt!(
tag!("=") => { |_| Operator::Exact } |
tag!(":") => { |_| Operator::Fuzzy } |
tag!("<") => { |_| Operator::LessThan } |
tag!(">") => { |_| Operator::MoreThan }
)));
fn unescape(input: &str) -> String {
input
.replace("\\)", ")")
.replace("\\,", ",")
.replace("\\|", "|")
.replace("\\\\", "\\")
}
named!(value<&str, &str>,
escaped!(none_of!("),|\\"), '\\', one_of!("),|\\"))
);
named!(target<&str, String>, preceded!(space0,
map!(value, |value| unescape(value.trim()))
));
fn item(input: &str) -> IResult<&str, Filter> {
let result = tuple((source, operator, target))(input)?;
let (left, (src, op, value)) = result;
let filter = optimize(src, op, &value).map_err(|e| match e {
_ => Err::Failure((input, NomErrorKind::Permutation)),
})?;
Ok((left, filter))
}
named!(parens<&str, Filter>, alt!(
delimited!(
preceded!(space0, tag!("(")),
preceded!(space0, call!(ofunc)),
preceded!(space0, tag!(")"))
) |
call!(item)
));
fn negate(input: &str) -> IResult<&str, Filter> {
let (left, filter) = parens(input)?;
Ok((left, Box::new(move |s| !filter(s))))
}
named!(nlist<&str, Filter>, preceded!(space0, alt!(
preceded!(char('!'), call!(negate)) | call!(parens)
)));
named!(alist<&str, Vec<Filter>>, separated_nonempty_list!(
preceded!(space0, char(',')), call!(nlist)
));
fn afunc(input: &str) -> IResult<&str, Filter> {
let (left, mut filters) = alist(input)?;
if filters.len() == 1 {
return Ok((left, filters.remove(0)));
}
let filter: Filter = Box::new(move |story| {
for filter in filters.iter() {
if !filter(story) {
return false;
}
}
true
});
Ok((left, filter))
}
named!(olist<&str, Vec<Filter>>, separated_nonempty_list!(
preceded!(space0, char('|')), call!(afunc)
));
fn ofunc(input: &str) -> IResult<&str, Filter> {
let (left, mut filters) = olist(input)?;
if filters.len() == 1 {
return Ok((left, filters.remove(0)));
}
let filter: Filter = Box::new(move |story| {
for filter in filters.iter() {
if filter(story) {
return true;
}
}
false
});
Ok((left, filter))
}
fn format_error(query: &str, input: &str, error: NomErrorKind) -> String {
let description = error.description().to_lowercase();
let position = query.len() - input.len();
format!("Invalid {} at {}", description, position)
}
fn translate_error(query: &str, error: Err<(&str, NomErrorKind)>) -> Error {
let message = match error {
Err::Error((i, e)) => format_error(query, i, e),
Err::Failure((i, e)) => format_error(query, i, e),
Err::Incomplete(_) => String::from("Incomplete input"),
};
Error::query(message)
}
fn translate_incomplete(query: &str, input: &str) -> Error {
let position = query.len() - input.len();
Error::query(format!("Incomplete input at {}", position))
}
pub fn parse(query: &str) -> Result<Filter> {
match ofunc(query.trim()) {
Ok(("", filter)) => Ok(filter),
Ok((i, _)) => Err(translate_incomplete(query, i)),
Err(e) => Err(translate_error(query, e)),
}
}