groonga-client-rails 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +6 -0
- data/Gemfile +21 -0
- data/README.md +57 -0
- data/Rakefile +44 -0
- data/doc/text/lgpl-2.1.txt +502 -0
- data/doc/text/news.md +5 -0
- data/groonga-client-rails.gemspec +52 -0
- data/lib/groonga-client-rails.rb +23 -0
- data/lib/groonga/client/rails/fixture.rb +35 -0
- data/lib/groonga/client/rails/groonga_server_runner.rb +164 -0
- data/lib/groonga/client/rails/spec_helper.rb +39 -0
- data/lib/groonga/client/rails/test_helper.rb +39 -0
- data/lib/groonga/client/rails/version.rb +23 -0
- data/lib/groonga/client/railtie.rb +70 -0
- data/lib/groonga/client/searcher.rb +165 -0
- data/lib/groonga/client/searcher/error.rb +37 -0
- data/lib/groonga/client/searcher/raw_request.rb +85 -0
- data/lib/groonga/client/searcher/schema.rb +74 -0
- data/lib/groonga/client/searcher/schema_synchronizer.rb +137 -0
- data/lib/groonga/client/searcher/select.rb +18 -0
- data/lib/groonga/client/searcher/select/request.rb +266 -0
- data/lib/groonga/client/searcher/select/result_set.rb +117 -0
- data/lib/groonga/client/searcher/source.rb +59 -0
- data/test/apps/rails4-mongoid/Gemfile +50 -0
- data/test/apps/rails4-mongoid/Gemfile.lock +190 -0
- data/test/apps/rails4-mongoid/README.rdoc +28 -0
- data/test/apps/rails4-mongoid/Rakefile +6 -0
- data/test/apps/rails4-mongoid/app/assets/javascripts/application.js +16 -0
- data/test/apps/rails4-mongoid/app/assets/javascripts/posts.coffee +3 -0
- data/test/apps/rails4-mongoid/app/assets/stylesheets/application.css +15 -0
- data/test/apps/rails4-mongoid/app/assets/stylesheets/posts.scss +3 -0
- data/test/apps/rails4-mongoid/app/assets/stylesheets/scaffolds.scss +73 -0
- data/test/apps/rails4-mongoid/app/controllers/application_controller.rb +5 -0
- data/test/apps/rails4-mongoid/app/controllers/posts_controller.rb +74 -0
- data/test/apps/rails4-mongoid/app/helpers/application_helper.rb +2 -0
- data/test/apps/rails4-mongoid/app/helpers/posts_helper.rb +2 -0
- data/test/apps/rails4-mongoid/app/models/post.rb +12 -0
- data/test/apps/rails4-mongoid/app/searchers/application_searcher.rb +2 -0
- data/test/apps/rails4-mongoid/app/searchers/posts_searcher.rb +16 -0
- data/test/apps/rails4-mongoid/app/views/layouts/application.html.erb +14 -0
- data/test/apps/rails4-mongoid/app/views/posts/_form.html.erb +25 -0
- data/test/apps/rails4-mongoid/app/views/posts/edit.html.erb +6 -0
- data/test/apps/rails4-mongoid/app/views/posts/index.html.erb +29 -0
- data/test/apps/rails4-mongoid/app/views/posts/index.json.jbuilder +4 -0
- data/test/apps/rails4-mongoid/app/views/posts/new.html.erb +5 -0
- data/test/apps/rails4-mongoid/app/views/posts/show.html.erb +14 -0
- data/test/apps/rails4-mongoid/app/views/posts/show.json.jbuilder +1 -0
- data/test/apps/rails4-mongoid/bin/bundle +3 -0
- data/test/apps/rails4-mongoid/bin/rails +4 -0
- data/test/apps/rails4-mongoid/bin/rake +4 -0
- data/test/apps/rails4-mongoid/bin/setup +29 -0
- data/test/apps/rails4-mongoid/config.ru +4 -0
- data/test/apps/rails4-mongoid/config/application.rb +32 -0
- data/test/apps/rails4-mongoid/config/boot.rb +3 -0
- data/test/apps/rails4-mongoid/config/environment.rb +5 -0
- data/test/apps/rails4-mongoid/config/environments/development.rb +38 -0
- data/test/apps/rails4-mongoid/config/environments/production.rb +76 -0
- data/test/apps/rails4-mongoid/config/environments/test.rb +42 -0
- data/test/apps/rails4-mongoid/config/groonga_client.yml +22 -0
- data/test/apps/rails4-mongoid/config/initializers/assets.rb +11 -0
- data/test/apps/rails4-mongoid/config/initializers/backtrace_silencers.rb +7 -0
- data/test/apps/rails4-mongoid/config/initializers/cookies_serializer.rb +3 -0
- data/test/apps/rails4-mongoid/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/apps/rails4-mongoid/config/initializers/inflections.rb +16 -0
- data/test/apps/rails4-mongoid/config/initializers/mime_types.rb +4 -0
- data/test/apps/rails4-mongoid/config/initializers/session_store.rb +3 -0
- data/test/apps/rails4-mongoid/config/initializers/wrap_parameters.rb +9 -0
- data/test/apps/rails4-mongoid/config/locales/en.yml +23 -0
- data/test/apps/rails4-mongoid/config/mongoid.yml +142 -0
- data/test/apps/rails4-mongoid/config/routes.rb +57 -0
- data/test/apps/rails4-mongoid/config/secrets.yml +22 -0
- data/test/apps/rails4-mongoid/db/seeds.rb +7 -0
- data/test/apps/rails4-mongoid/log/development.log +764 -0
- data/test/apps/rails4-mongoid/log/test.log +15736 -0
- data/test/apps/rails4-mongoid/public/404.html +67 -0
- data/test/apps/rails4-mongoid/public/422.html +67 -0
- data/test/apps/rails4-mongoid/public/500.html +66 -0
- data/test/apps/rails4-mongoid/public/favicon.ico +0 -0
- data/test/apps/rails4-mongoid/public/robots.txt +5 -0
- data/test/apps/rails4-mongoid/test/controllers/posts_controller_test.rb +51 -0
- data/test/apps/rails4-mongoid/test/factories/posts.rb +6 -0
- data/test/apps/rails4-mongoid/test/models/post_test.rb +9 -0
- data/test/apps/rails4-mongoid/test/searchers/posts_searcher_test.rb +119 -0
- data/test/apps/rails4-mongoid/test/test_helper.rb +9 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/-Xhj-Mbb82rk571sDsQxrdCywGX36vsenBH1RUlK-LY.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/0f_MbWM7kHYaEii2fU46RtcPM1c5AvKKzZXw_HiM0CE.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/2PZE0O2lwq-MOTwxKTZxLxQwY8_QyhrbRsthl3Lc4lQ.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/5dV_yE4FDckg8xSumojLvTuflbNyhpApq7LPOy-e1X0.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/7efkcYvlMpIQU8kuDy1jAKDLjakVGoH6N5V-AuzuTZc.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/8Zm1d9-lBPsGG_HUw8FP2OCCVucGDVhWAOGaopvOdss.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/9B_fDWO-7yTtWLP7C6kgtW5LN2zlpAqr1km-1jSQx2w.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/9X7nmZiJ1BxgVp80vJFjKw2uuEfdS1ik3B66O4_iWPo.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/APY89OAPJx9A3D3xcCoktvEvQUs7NcWChYXnjjjPzz0.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/CWMzfW8FmEfR6gB4BwariPLjTZTtLc4bCVc0r0m2VV4.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/C_ZXB0e-P6-9Ty60eBWeAui5uzzA0NzDW8amqmtTk9g.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/Cg1VzEm4v80ed-e0X3WGAHJWYiC_ybnfBrRrIvltPXc.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/Cjhm36F4tzUHdc1e0Bho51N0H4HYybVTrxTmbtiqih4.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/DSOLSc6A5RVSmvM415eEWAWG_AgOvZcLZOXQjsXyWQA.cache +2 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/EBtbhweQl74JQNkwFL3ahZH_9x44ceqa9hOT8lQ_SfM.cache +2 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/EQICjEOYeXNTngMqEgET0L1SuE4AVuoKyJgio4ks43A.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/Edyy4hZsoEraZijGtQOEBXtG2121KJUoZeUxxPjVoD8.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/HfA_T6XraGo2Ny22jLyDJkU33FwcVIBOxUIXJAfTZnw.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/I-oUhfEICgXeCJ30YmQbpoYtgGAJK0-Pql8kOvfHUIs.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/ITBgBGR9-8E08Y63Vjo65c8DzPESTHJuYCXZp0y6k_I.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/JImLmTmbMkDKlN30hse8U-u0IV8hvfdebOL3EFz71FE.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/Joxxq6tZo5Z61fNSWcPCGgCyehta1sNKXM0i53ziK0o.cache +2 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/KPHQh44WoGRX0SuVORNxUqq129kPRQ4Sfwr0MgBGTWg.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/MQWJrWW-vCooFa9lpB2Z7KDIE9ilL54d5Sf_SRtQhTM.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/Olyga_OJ5Sz5He_RVZLO_BraSHgGvt9BG0ORecSD4A4.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/OoG10cMLeO2eGZxk483Gx75vNDQz7Id8sxVt3g26jQE.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/P2sNuT6usNXi8DQFFQ2SMByy1v98zmNdwdx6wduUQDg.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/Pm3ENYpCrQMOJGd-d8lACN_nbGZWiivq_KyPLJoD9Xk.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/PrxeUFTxE6CmNlJ4CQLxcmAQKwOGBKNCFYluKNhVPdI.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/PuNKoh-EB-UU-NnPetIEhS3emExlV586tfFJnBFhaxo.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/QyBzeHR44VD1fMDrJcMOaVyyn1xgHnmhPX2VL3R6EdE.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/QyU_Bdj5YdiIQef2XhSDP5MQf7l3u_A81md3KFPQ2N4.cache +2 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/R9YbLXVmFuZvXntmUsVoP9gdFgZaoKuww_0l-ulu_Sw.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/RbDvgwCB1ggHONj2Gglg9cljN_KExx-gHiSiItOFBVw.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/Rkd99KDYtUtVb3U566M9L4YD2Kh-Qp147dHVmyXnDhg.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/Sin6bEoASrNa45108CpfgF2jcifz-KpbsvvZJtqVZ68.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/SuhtC6f7E2-1SXl4bkRvOKqhzFKTjPvbglVtjbjV6WQ.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/WDXpPe61HDYBIqMMzcYJWujunl4HLJBvhn0OOP1yQso.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/Y2HHx2PygDVpbc258EY6XyZq_3ocHy5fEq-5UHSNfh0.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/Zot5Dwe9yQ1wvCpegdXXjC8DUGHfH1xLxerosBjUsns.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/ZwSejSAeaXOqaevCGNDw6GT4jzf6iGxiDfUGqtjYqxE.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/bsYyBqujQ9Bb_NkqKjx8J9lC8MPb-Ed59b__aV46Bic.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/cnfLEWE92uT-WDII157E3Z5XISKK99q6__D2IiTRhOM.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/cnk28xBZ2NhIHyeh4bImJu1D8MsQZksGaVeYZSDL-Mw.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/cyuaVF0ZckKku_VGsQYOntnl3oNlSP381WW5VhCMbE4.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/ee9ZqYM3D8GORlAyhQhVVtyNcEArBAXuuAcPhnfTNT8.cache +5 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/fQe7NSWabAv2wB6jtw0Tjp5CT06xwpla822ipJiUCy0.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/fme939QD_yb-kVcNE40VAdyOZYRTHgZCxYLVDZLuzF0.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/gl7MP7d46hviHXVnGFYORtcWessT58E75rSQUFjfiII.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/hHOboG408ksat1oQaCWVNxzf-FIyTREQFXHdFZurlZQ.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/i5GV8tvuWRKqi-plBB0bdaAqfdW_CpIMlk_3qZYyask.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/ioEvK0rblqqEotrMItm0VrKhWOXnC3vwC-CIU9UCZEg.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/ivzms341pOxkVrOTXM3Yog9cLwq3SmsXcwGMbRGmM6s.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/j0l28m8jfc6vnBWrkD0zWt2ELCJfEOMeEjW0Q4GADNY.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/jPuyl--LQd6DGNNoxSkPhBGx_ul_1kfka93EDJmnc8c.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/jaYo3RHF_E7SipTqBJcsnR0JcOOa0rFpEHmp3nLDrQI.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/kSkCWaAJCcTgZ_AhrRCjZhNtkE12cubiq70uNtditqk.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/mXFXPQpdpe6VdLyG_ATkrFvhK-DzKohwq6B2GOQo9R8.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/q2eC-e4sz4yzY37JZQfdjar0jjp4v7rHuGin5JEKV7Q.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/s6DK-YkFoxYJMKXt21m9PdMtZi3TJhRoHIi0R5i69Zs.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/sLDAakEn7_JrPiyZe0ZUsCLDnaTAal-5HajraaAgdhE.cache +2 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/teXpzhiur3Mnn2KsTY8q4HhEqpbdmKBfBW2iS5-MvUI.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/tgZjQMFX0Ebx2i8ovlwnvwULhvrhFNJLAIQjUNZN1RM.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/tihMlIo90U72qN2BzGajipIJOWppg8OIJuVnnluwVJM.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/vpD8YcdUFmWVggV1ANqLIWcTbMItiGv1aOUd3i_Sf_w.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/wBoZhq66JcV9m6-FvOoZ-Q3Cy9mgT-ynjPWZWZdafLw.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/wTWJ6pQBopl4RdCt1QzngFCI6BQsl97QiZJO8bkGZd4.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/wjVbFqqSw39d-ryprJ1NYmKProunHG47jEI6RFHcLM4.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/wm5Vu6DEN0ZExnKV0oAADsKfEn3yvO4aBQJwp6b8FbU.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/x0qPZqkeQj_x2GoHegxhwuHhPMrz8iHGdALgbSEtYB0.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/xESXQaQoarUInNLmS7yPvF7D9FlSfaR8n8CsT6vIfmU.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/xJpeFclkEQS028sCHKPl9C6EyiAcTgUW_lBAqjRuP_c.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/yinyMcV6eKC4p76ZeetFBkRq8qYD5b8fWOHbukaCUNk.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/ytg8J2fjBhc978nkpdl0f5cBPdcKpig523h4O4eN664.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/z5Cl2oKorg00CGt089PLdPdoE1ELvsz4CdtXnlUk7KM.cache +0 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/z6uhOy1uoRnC6c9iKrzc1vRqGH1KQrhArDe51rZL1_k.cache +1 -0
- data/test/apps/rails4-mongoid/tmp/cache/assets/sprockets/v3.0/zIFdfoc8nFjrQhTXHyamSnNA6CVVrOcsP4qfDQhOcVI.cache +1 -0
- data/test/run-test.rb +43 -0
- data/test/unit/run-test.rb +25 -0
- data/test/unit/searcher/select/filter_parameter_test.rb +99 -0
- data/test/unit/searcher/select/match_columns_parameter_test.rb +59 -0
- data/test/unit/searcher/select/output_columns_parameter_test.rb +68 -0
- data/test/unit/searcher/select/sortby_parameter_test.rb +63 -0
- data/test/unit/test_helper.rb +19 -0
- metadata +480 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
|
|
2
|
+
#
|
|
3
|
+
# This library is free software; you can redistribute it and/or
|
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
5
|
+
# License as published by the Free Software Foundation; either
|
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
11
|
+
# Lesser General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
14
|
+
# License along with this library; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
16
|
+
|
|
17
|
+
require "groonga/client"
|
|
18
|
+
|
|
19
|
+
require "groonga/client/searcher/error"
|
|
20
|
+
require "groonga/client/searcher/select"
|
|
21
|
+
require "groonga/client/searcher/schema"
|
|
22
|
+
require "groonga/client/searcher/schema_synchronizer"
|
|
23
|
+
require "groonga/client/searcher/source"
|
|
24
|
+
|
|
25
|
+
module Groonga
|
|
26
|
+
class Client
|
|
27
|
+
class Searcher
|
|
28
|
+
class << self
|
|
29
|
+
def schema
|
|
30
|
+
@schema ||= Schema.new(default_table_name)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def source(model_class)
|
|
34
|
+
sources[model_class] ||= create_source(model_class)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def sync
|
|
38
|
+
sync_schema
|
|
39
|
+
sync_records
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def sync_schema
|
|
43
|
+
current_schema = Client.open do |client|
|
|
44
|
+
client.schema
|
|
45
|
+
end
|
|
46
|
+
syncher = SchemaSynchronizer.new(schema, current_schema)
|
|
47
|
+
syncher.sync
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def sync_records
|
|
51
|
+
ensure_model_classes_loaded
|
|
52
|
+
sources.each do |model_class, definition|
|
|
53
|
+
all_records = model_class.all
|
|
54
|
+
if all_records.respond_to?(:find_each)
|
|
55
|
+
enumerator = all_records.find_each
|
|
56
|
+
else
|
|
57
|
+
enumerator = all_records.each
|
|
58
|
+
end
|
|
59
|
+
searcher = new
|
|
60
|
+
enumerator.each do |model|
|
|
61
|
+
searcher.upsert(model)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
def sources
|
|
68
|
+
@sources ||= {}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def create_source(model_class)
|
|
72
|
+
source = Source.new(schema, model_class)
|
|
73
|
+
|
|
74
|
+
searcher_class = self
|
|
75
|
+
model_class.after_create do |model|
|
|
76
|
+
searcher = searcher_class.new
|
|
77
|
+
searcher.create(model)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
model_class.after_update do |model|
|
|
81
|
+
searcher = searcher_class.new
|
|
82
|
+
searcher.update(model)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
model_class.after_destroy do |model|
|
|
86
|
+
searcher = searcher_class.new
|
|
87
|
+
searcher.destroy(model)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
source
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def default_table_name
|
|
94
|
+
name.gsub(/Searcher\z/, "").tableize
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def ensure_model_classes_loaded
|
|
98
|
+
::Rails.application.eager_load!
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def inititalize
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def upsert(model)
|
|
106
|
+
source = self.class.source(model.class)
|
|
107
|
+
record = {}
|
|
108
|
+
source.columns.each do |name, reader|
|
|
109
|
+
case reader
|
|
110
|
+
when Symbol
|
|
111
|
+
value = model.__send__(reader)
|
|
112
|
+
when TrueClass
|
|
113
|
+
value = model.__send__(name)
|
|
114
|
+
when NilClass
|
|
115
|
+
next
|
|
116
|
+
else
|
|
117
|
+
value = reader.call(model)
|
|
118
|
+
end
|
|
119
|
+
record[name] = value
|
|
120
|
+
end
|
|
121
|
+
record["_key"] = model_key(model)
|
|
122
|
+
Client.open do |client|
|
|
123
|
+
client.load(:table => self.class.schema.table,
|
|
124
|
+
:values => [record])
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def create(model)
|
|
129
|
+
upsert(model)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def update(model)
|
|
133
|
+
upsert(model)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def destroy(model)
|
|
137
|
+
Client.open do |client|
|
|
138
|
+
client.delete(table: self.class.schema.table,
|
|
139
|
+
key: model_key(model))
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def search
|
|
144
|
+
select
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def select
|
|
148
|
+
schema = self.class.schema
|
|
149
|
+
full_text_searchable_column_names = []
|
|
150
|
+
schema.columns.each do |name, column|
|
|
151
|
+
if column.have_full_text_search_index?
|
|
152
|
+
full_text_searchable_column_names << name
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
Select::Request.new(schema.table).
|
|
156
|
+
match_columns(full_text_searchable_column_names)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
private
|
|
160
|
+
def model_key(model)
|
|
161
|
+
"#{model.class.name}-#{model.id}"
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
|
|
2
|
+
#
|
|
3
|
+
# This library is free software; you can redistribute it and/or
|
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
5
|
+
# License as published by the Free Software Foundation; either
|
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
11
|
+
# Lesser General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
14
|
+
# License along with this library; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
16
|
+
|
|
17
|
+
module Groonga
|
|
18
|
+
class Client
|
|
19
|
+
class Searcher
|
|
20
|
+
class Error < Client::Error
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class ErrorResponse < Error
|
|
24
|
+
attr_reader :response
|
|
25
|
+
def initialize(response)
|
|
26
|
+
@response = response
|
|
27
|
+
command = @response.command
|
|
28
|
+
status_code = @response.status_code
|
|
29
|
+
error_message = @response.error_message
|
|
30
|
+
message = "failed to execute: #{command.name}: #{status_code}: "
|
|
31
|
+
message << "<#{error_message}>"
|
|
32
|
+
super(message)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
|
|
2
|
+
#
|
|
3
|
+
# This library is free software; you can redistribute it and/or
|
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
5
|
+
# License as published by the Free Software Foundation; either
|
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
11
|
+
# Lesser General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
14
|
+
# License along with this library; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
16
|
+
|
|
17
|
+
module Groonga
|
|
18
|
+
class Client
|
|
19
|
+
class Searcher
|
|
20
|
+
class RawRequest
|
|
21
|
+
def initialize(command_name, parameters=nil)
|
|
22
|
+
@command_name = command_name
|
|
23
|
+
@parameters = parameters
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def response
|
|
27
|
+
@reponse ||= Client.open do |client|
|
|
28
|
+
response = client.execute(@command_name, to_parameters)
|
|
29
|
+
raise ErrorResponse.new(response) unless response.success?
|
|
30
|
+
response
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def parameter(name, value)
|
|
35
|
+
add_parameter(OverwriteMerger,
|
|
36
|
+
RequestParameter.new(name, value))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_parameters
|
|
40
|
+
if @parameters.nil?
|
|
41
|
+
{}
|
|
42
|
+
else
|
|
43
|
+
@parameters.to_parameters
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
def add_parameter(merger_class, parameter)
|
|
49
|
+
merger = merger_class.new(@parameters, parameter)
|
|
50
|
+
create_request(merger)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def create_request(parameters)
|
|
54
|
+
self.class.new(@command_name, parameters)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
class RequestParameter
|
|
59
|
+
def initialize(name, value)
|
|
60
|
+
@name = name
|
|
61
|
+
@value = value
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def to_parameters
|
|
65
|
+
{
|
|
66
|
+
@name => @value,
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class ParameterMerger
|
|
72
|
+
def initialize(parameters1, parameters2)
|
|
73
|
+
@parameters1 = parameters1
|
|
74
|
+
@parameters2 = parameters2
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
class OverwriteMerger < ParameterMerger
|
|
79
|
+
def to_parameters
|
|
80
|
+
@parameters1.to_parameters.merge(@parameters2.to_parameters)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
|
|
2
|
+
#
|
|
3
|
+
# This library is free software; you can redistribute it and/or
|
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
5
|
+
# License as published by the Free Software Foundation; either
|
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
11
|
+
# Lesser General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
14
|
+
# License along with this library; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
16
|
+
|
|
17
|
+
module Groonga
|
|
18
|
+
class Client
|
|
19
|
+
class Searcher
|
|
20
|
+
class Schema
|
|
21
|
+
attr_reader :table
|
|
22
|
+
attr_reader :columns
|
|
23
|
+
def initialize(table)
|
|
24
|
+
@table = table
|
|
25
|
+
@columns = {}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def table=(name)
|
|
29
|
+
name = name.to_s if name.is_a?(Symbol)
|
|
30
|
+
@table = name
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def column(name, options)
|
|
34
|
+
name = normalize_name(name)
|
|
35
|
+
@columns[name] = Column.new(name, options)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def have_column?(name)
|
|
39
|
+
name = normalize_name(name)
|
|
40
|
+
@columns.key?(name)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
def normalize_name(name)
|
|
45
|
+
if name.is_a?(Symbol)
|
|
46
|
+
name.to_s
|
|
47
|
+
else
|
|
48
|
+
name
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class Column
|
|
53
|
+
attr_reader :name
|
|
54
|
+
def initialize(name, options)
|
|
55
|
+
@name = name
|
|
56
|
+
@options = options
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def type
|
|
60
|
+
@options[:type] || "Text"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def have_index?
|
|
64
|
+
@options[:index]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def have_full_text_search_index?
|
|
68
|
+
have_index? and @options[:index_type] == :full_text_search
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
|
|
2
|
+
#
|
|
3
|
+
# This library is free software; you can redistribute it and/or
|
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
5
|
+
# License as published by the Free Software Foundation; either
|
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
11
|
+
# Lesser General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
14
|
+
# License along with this library; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
16
|
+
|
|
17
|
+
module Groonga
|
|
18
|
+
class Client
|
|
19
|
+
class Searcher
|
|
20
|
+
class SchemaSynchronizer
|
|
21
|
+
def initialize(schema, current_schema)
|
|
22
|
+
@schema = schema
|
|
23
|
+
@current_schema = current_schema
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def sync
|
|
27
|
+
sync_table
|
|
28
|
+
sync_columns
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
def sync_table
|
|
33
|
+
current_table = find_current_table
|
|
34
|
+
return if current_table # TODO: validation
|
|
35
|
+
|
|
36
|
+
Client.open do |client|
|
|
37
|
+
client.table_create(:name => @schema.table,
|
|
38
|
+
:flags => "TABLE_PAT_KEY",
|
|
39
|
+
:key_type => "ShortText")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def sync_columns
|
|
44
|
+
current_columns = find_current_columns
|
|
45
|
+
@schema.columns.each do |_, column|
|
|
46
|
+
sync_column(column, current_columns[column.name])
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def sync_column(column, current_column)
|
|
51
|
+
if current_column.nil?
|
|
52
|
+
Client.open do |client|
|
|
53
|
+
client.column_create(:table => @schema.table,
|
|
54
|
+
:name => column.name,
|
|
55
|
+
:type => column.type)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
sync_column_index(column, current_column)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def sync_column_index(column, current_column)
|
|
63
|
+
if column.have_index?
|
|
64
|
+
lexicon_name = "lexicon_#{@schema.table}_#{column.name}"
|
|
65
|
+
index_column_name = "index"
|
|
66
|
+
if current_column
|
|
67
|
+
indexes = current_column.indexes
|
|
68
|
+
else
|
|
69
|
+
indexes = []
|
|
70
|
+
end
|
|
71
|
+
indexes.each do |index|
|
|
72
|
+
return if index.full_name == "#{lexicon_name}.#{index_column_name}"
|
|
73
|
+
end
|
|
74
|
+
sync_lexicon(column, lexicon_name)
|
|
75
|
+
create_index_column(column, lexicon_name, index_column_name)
|
|
76
|
+
else
|
|
77
|
+
remove_indexes(current_column)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def sync_lexicon(column, lexicon_name)
|
|
82
|
+
return if @current_schema.tables[lexicon_name]
|
|
83
|
+
|
|
84
|
+
parameters = {
|
|
85
|
+
:name => lexicon_name,
|
|
86
|
+
:flags => "TABLE_PAT_KEY",
|
|
87
|
+
}
|
|
88
|
+
if column.have_full_text_search_index?
|
|
89
|
+
parameters[:key_type] = "ShortText"
|
|
90
|
+
parameters[:default_tokenizer] = "TokenBigram"
|
|
91
|
+
parameters[:normalizer] = "NormalizerAuto"
|
|
92
|
+
else
|
|
93
|
+
parameters[:key_type] = column.type
|
|
94
|
+
end
|
|
95
|
+
Client.open do |client|
|
|
96
|
+
client.table_create(parameters)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def create_index_column(column, lexicon_name, index_column_name)
|
|
101
|
+
flags = "COLUMN_INDEX"
|
|
102
|
+
flags += "|WITH_POSITION" if column.have_full_text_search_index?
|
|
103
|
+
Client.open do |client|
|
|
104
|
+
client.column_create(:table => lexicon_name,
|
|
105
|
+
:name => index_column_name,
|
|
106
|
+
:flags => flags,
|
|
107
|
+
:type => @schema.table,
|
|
108
|
+
:source => column.name)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def remove_indexes(current_column)
|
|
113
|
+
return if current_column.nil?
|
|
114
|
+
current_column.indexes.each do |index|
|
|
115
|
+
Client.open do |client|
|
|
116
|
+
clinet.column_remove(:table => index.table.name,
|
|
117
|
+
:name => index.name)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def find_current_table
|
|
123
|
+
@current_schema.tables[@schema.table]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def find_current_columns
|
|
127
|
+
current_table = find_current_table
|
|
128
|
+
if current_table.nil?
|
|
129
|
+
{}
|
|
130
|
+
else
|
|
131
|
+
current_table.columns
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|