wallaby 5.0.1 → 5.1.3
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 +4 -4
- data/Rakefile +1 -3
- data/app/assets/images/wallaby/404.png +0 -0
- data/app/assets/images/wallaby/422.png +0 -0
- data/app/assets/images/wallaby/500.png +0 -0
- data/app/assets/javascripts/wallaby/application.js +1 -15
- data/app/assets/javascripts/wallaby/auto_select.js +77 -0
- data/app/assets/javascripts/wallaby/base.js +17 -0
- data/app/assets/javascripts/wallaby/setup.js.erb +60 -0
- data/app/assets/stylesheets/wallaby/application.scss +1 -51
- data/app/assets/stylesheets/wallaby/base/_layout.scss +257 -9
- data/app/assets/stylesheets/wallaby/base/_layout_desktop.scss +53 -0
- data/app/assets/stylesheets/wallaby/base/_mixins.scss +119 -0
- data/app/assets/stylesheets/wallaby/base/_override.scss +10 -0
- data/app/assets/stylesheets/wallaby/base/_vars.scss +72 -2
- data/app/assets/stylesheets/wallaby/base.scss +27 -0
- data/app/assets/stylesheets/wallaby/components/_auto_select.scss +119 -0
- data/app/assets/stylesheets/wallaby/components/_auto_select_desktop.scss +7 -0
- data/app/assets/stylesheets/wallaby/components/_color_square.scss +8 -0
- data/app/assets/stylesheets/wallaby/components/_filters.scss +14 -0
- data/app/assets/stylesheets/wallaby/components/_links.scss +25 -0
- data/app/assets/stylesheets/wallaby/components/_pagination.scss +35 -91
- data/app/assets/stylesheets/wallaby/components/_query.scss +101 -0
- data/app/assets/stylesheets/wallaby/components/_text.scss +6 -6
- data/app/assets/stylesheets/wallaby/pages/_error.scss +108 -0
- data/app/assets/stylesheets/wallaby/pages/_form.scss +40 -0
- data/app/assets/stylesheets/wallaby/pages/_index.scss +193 -0
- data/app/assets/stylesheets/wallaby/pages/_index_desktop.scss +22 -0
- data/app/assets/stylesheets/wallaby/pages/_show.scss +21 -0
- data/app/controllers/wallaby/abstract_resources_controller.rb +334 -0
- data/app/controllers/wallaby/application_controller.rb +45 -15
- data/app/controllers/wallaby/base_controller.rb +30 -0
- data/app/controllers/wallaby/resources_controller.rb +2 -131
- data/app/controllers/wallaby/secure_controller.rb +38 -24
- data/app/routes/wallaby/resources_router.rb +40 -43
- data/app/security/ability.rb +4 -28
- data/app/views/layouts/wallaby/application.html.erb +11 -6
- data/app/views/layouts/wallaby/error.html.erb +26 -4
- data/app/views/wallaby/error.html.erb +11 -0
- data/app/views/wallaby/error.json.jbuilder +8 -0
- data/app/views/wallaby/{shared → resources}/_flash_messages.html.erb +0 -0
- data/app/views/wallaby/resources/_footer.html.erb +1 -0
- data/app/views/wallaby/resources/_form.html.erb +2 -2
- data/app/views/wallaby/resources/_header.html.erb +38 -0
- data/app/views/wallaby/resources/_imodal.html.erb +13 -0
- data/app/views/wallaby/resources/_index_actions.html.erb +4 -1
- data/app/views/wallaby/resources/_index_filters.html.erb +23 -0
- data/app/views/wallaby/resources/_index_pagination.html.erb +63 -0
- data/app/views/wallaby/resources/_index_query.html.erb +23 -0
- data/app/views/wallaby/resources/_logo.html.erb +1 -0
- data/app/views/wallaby/resources/_navs.html.erb +9 -0
- data/app/views/wallaby/resources/_resource_actions.html.erb +3 -3
- data/app/views/wallaby/resources/{shared/_resource_nav.html.erb → _resource_navs.html.erb} +6 -6
- data/app/views/wallaby/resources/_title.html.erb +1 -0
- data/app/views/wallaby/resources/_user_menu.html.erb +5 -0
- data/app/views/wallaby/resources/bad_request.json.jbuilder +7 -0
- data/app/views/wallaby/resources/edit.html.erb +16 -12
- data/app/views/wallaby/resources/form/_belongs_to.html.erb +63 -12
- data/app/views/wallaby/resources/form/_bigint.html.erb +10 -1
- data/app/views/wallaby/resources/form/_bigserial.html.erb +18 -0
- data/app/views/wallaby/resources/form/_binary.html.erb +11 -2
- data/app/views/wallaby/resources/form/_bit.html.erb +10 -1
- data/app/views/wallaby/resources/form/_bit_varying.html.erb +10 -1
- data/app/views/wallaby/resources/form/_blob.html.erb +21 -0
- data/app/views/wallaby/resources/form/_boolean.html.erb +9 -0
- data/app/views/wallaby/resources/form/_box.html.erb +21 -0
- data/app/views/wallaby/resources/form/_cidr.html.erb +13 -1
- data/app/views/wallaby/resources/form/_circle.html.erb +21 -0
- data/app/views/wallaby/resources/form/_citext.html.erb +11 -2
- data/app/views/wallaby/resources/form/_color.html.erb +11 -2
- data/app/views/wallaby/resources/form/_date.html.erb +12 -3
- data/app/views/wallaby/resources/form/_daterange.html.erb +14 -5
- data/app/views/wallaby/resources/form/_datetime.html.erb +12 -3
- data/app/views/wallaby/resources/form/_decimal.html.erb +10 -1
- data/app/views/wallaby/resources/form/_dropdown.html.erb +18 -0
- data/app/views/wallaby/resources/form/_email.html.erb +9 -0
- data/app/views/wallaby/resources/form/_file.html.erb +21 -0
- data/app/views/wallaby/resources/form/_float.html.erb +10 -1
- data/app/views/wallaby/resources/form/_has_and_belongs_to_many.html.erb +53 -7
- data/app/views/wallaby/resources/form/_has_many.html.erb +52 -7
- data/app/views/wallaby/resources/form/_has_one.html.erb +10 -2
- data/app/views/wallaby/resources/form/_hstore.html.erb +12 -5
- data/app/views/wallaby/resources/form/_inet.html.erb +13 -1
- data/app/views/wallaby/resources/form/_int4range.html.erb +11 -2
- data/app/views/wallaby/resources/form/_int8range.html.erb +11 -2
- data/app/views/wallaby/resources/form/_integer.html.erb +10 -1
- data/app/views/wallaby/resources/form/_json.html.erb +13 -6
- data/app/views/wallaby/resources/form/_jsonb.html.erb +13 -6
- data/app/views/wallaby/resources/form/_line.html.erb +21 -0
- data/app/views/wallaby/resources/form/_longblob.html.erb +21 -0
- data/app/views/wallaby/resources/form/_longtext.html.erb +30 -0
- data/app/views/wallaby/resources/form/_lseg.html.erb +21 -0
- data/app/views/wallaby/resources/form/_ltree.html.erb +17 -1
- data/app/views/wallaby/resources/form/_macaddr.html.erb +13 -1
- data/app/views/wallaby/resources/form/_markdown.html.erb +29 -0
- data/app/views/wallaby/resources/form/_mediumblob.html.erb +21 -0
- data/app/views/wallaby/resources/form/_mediumtext.html.erb +30 -0
- data/app/views/wallaby/resources/form/_money.html.erb +10 -1
- data/app/views/wallaby/resources/form/_numrange.html.erb +11 -2
- data/app/views/wallaby/resources/form/_password.html.erb +14 -1
- data/app/views/wallaby/resources/form/_path.html.erb +17 -0
- data/app/views/wallaby/resources/form/_point.html.erb +11 -2
- data/app/views/wallaby/resources/form/_polygon.html.erb +17 -0
- data/app/views/wallaby/resources/form/_serial.html.erb +18 -0
- data/app/views/wallaby/resources/form/_sti.html.erb +18 -0
- data/app/views/wallaby/resources/form/_string.html.erb +14 -1
- data/app/views/wallaby/resources/form/_text.html.erb +11 -2
- data/app/views/wallaby/resources/form/_time.html.erb +12 -3
- data/app/views/wallaby/resources/form/_tinyblob.html.erb +21 -0
- data/app/views/wallaby/resources/form/_tinytext.html.erb +30 -0
- data/app/views/wallaby/resources/form/_tsrange.html.erb +14 -5
- data/app/views/wallaby/resources/form/_tstzrange.html.erb +14 -5
- data/app/views/wallaby/resources/form/_tsvector.html.erb +9 -0
- data/app/views/wallaby/resources/form/_unsigned_bigint.html.erb +18 -0
- data/app/views/wallaby/resources/form/_unsigned_decimal.html.erb +18 -0
- data/app/views/wallaby/resources/form/_unsigned_float.html.erb +18 -0
- data/app/views/wallaby/resources/form/_unsigned_integer.html.erb +18 -0
- data/app/views/wallaby/resources/form/_uuid.html.erb +10 -1
- data/app/views/wallaby/resources/form/_xml.html.erb +11 -5
- data/app/views/wallaby/resources/form.json.jbuilder +5 -0
- data/app/views/wallaby/{core → resources}/home.html.erb +1 -1
- data/app/views/wallaby/resources/index/_belongs_to.html.erb +5 -1
- data/app/views/wallaby/resources/index/_bigint.html.erb +4 -0
- data/app/views/wallaby/resources/index/_bigserial.html.erb +5 -0
- data/app/views/wallaby/resources/index/_binary.html.erb +5 -1
- data/app/views/wallaby/resources/index/_bit.html.erb +4 -0
- data/app/views/wallaby/resources/index/_bit_varying.html.erb +4 -0
- data/app/views/wallaby/resources/index/_blob.html.erb +5 -0
- data/app/views/wallaby/resources/index/_boolean.html.erb +5 -1
- data/app/views/wallaby/resources/index/_box.html.erb +16 -0
- data/app/views/wallaby/resources/index/_cidr.html.erb +5 -1
- data/app/views/wallaby/resources/index/_circle.html.erb +16 -0
- data/app/views/wallaby/resources/index/_citext.html.erb +5 -1
- data/app/views/wallaby/resources/index/_color.html.erb +6 -1
- data/app/views/wallaby/resources/index/_date.html.erb +4 -0
- data/app/views/wallaby/resources/index/_daterange.html.erb +5 -1
- data/app/views/wallaby/resources/index/_datetime.html.erb +5 -1
- data/app/views/wallaby/resources/index/_decimal.html.erb +4 -0
- data/app/views/wallaby/resources/index/_email.html.erb +4 -0
- data/app/views/wallaby/resources/index/_float.html.erb +4 -0
- data/app/views/wallaby/resources/index/_has_and_belongs_to_many.html.erb +6 -2
- data/app/views/wallaby/resources/index/_has_many.html.erb +6 -2
- data/app/views/wallaby/resources/index/_has_one.html.erb +5 -1
- data/app/views/wallaby/resources/index/_hstore.html.erb +6 -2
- data/app/views/wallaby/resources/index/_inet.html.erb +5 -1
- data/app/views/wallaby/resources/index/_int4range.html.erb +4 -0
- data/app/views/wallaby/resources/index/_int8range.html.erb +4 -0
- data/app/views/wallaby/resources/index/_integer.html.erb +4 -0
- data/app/views/wallaby/resources/index/_json.html.erb +5 -2
- data/app/views/wallaby/resources/index/_jsonb.html.erb +5 -2
- data/app/views/wallaby/resources/index/_line.html.erb +16 -0
- data/app/views/wallaby/resources/index/_longblob.html.erb +5 -0
- data/app/views/wallaby/resources/index/_longtext.html.erb +16 -0
- data/app/views/wallaby/resources/index/_lseg.html.erb +16 -0
- data/app/views/wallaby/resources/index/_ltree.html.erb +5 -1
- data/app/views/wallaby/resources/index/_macaddr.html.erb +4 -0
- data/app/views/wallaby/resources/index/_mediumblob.html.erb +5 -0
- data/app/views/wallaby/resources/index/_mediumtext.html.erb +16 -0
- data/app/views/wallaby/resources/index/_money.html.erb +4 -0
- data/app/views/wallaby/resources/index/_numrange.html.erb +4 -0
- data/app/views/wallaby/resources/index/_password.html.erb +9 -0
- data/app/views/wallaby/resources/index/_path.html.erb +16 -0
- data/app/views/wallaby/resources/index/_point.html.erb +4 -0
- data/app/views/wallaby/resources/index/_polygon.html.erb +16 -0
- data/app/views/wallaby/resources/index/_raw.html.erb +9 -0
- data/app/views/wallaby/resources/index/_serial.html.erb +5 -0
- data/app/views/wallaby/resources/index/_sti.html.erb +16 -0
- data/app/views/wallaby/resources/index/_string.html.erb +5 -1
- data/app/views/wallaby/resources/index/_text.html.erb +5 -1
- data/app/views/wallaby/resources/index/_time.html.erb +4 -0
- data/app/views/wallaby/resources/index/_tinyblob.html.erb +5 -0
- data/app/views/wallaby/resources/index/_tinytext.html.erb +16 -0
- data/app/views/wallaby/resources/index/_tsrange.html.erb +5 -1
- data/app/views/wallaby/resources/index/_tstzrange.html.erb +5 -1
- data/app/views/wallaby/resources/index/_tsvector.html.erb +5 -1
- data/app/views/wallaby/resources/index/_unsigned_bigint.html.erb +5 -0
- data/app/views/wallaby/resources/index/_unsigned_decimal.html.erb +5 -0
- data/app/views/wallaby/resources/index/_unsigned_float.html.erb +5 -0
- data/app/views/wallaby/resources/index/_unsigned_integer.html.erb +5 -0
- data/app/views/wallaby/resources/index/_uuid.html.erb +5 -1
- data/app/views/wallaby/resources/index/_xml.html.erb +5 -1
- data/app/views/wallaby/resources/index.csv.erb +26 -0
- data/app/views/wallaby/resources/index.html.erb +47 -59
- data/app/views/wallaby/resources/index.json.jbuilder +5 -0
- data/app/views/wallaby/resources/new.html.erb +12 -11
- data/app/views/wallaby/resources/show/_belongs_to.html.erb +5 -1
- data/app/views/wallaby/resources/show/_bigint.html.erb +4 -0
- data/app/views/wallaby/resources/show/_bigserial.html.erb +5 -0
- data/app/views/wallaby/resources/show/_binary.html.erb +5 -1
- data/app/views/wallaby/resources/show/_bit.html.erb +4 -0
- data/app/views/wallaby/resources/show/_bit_varying.html.erb +4 -0
- data/app/views/wallaby/resources/show/_blob.html.erb +5 -0
- data/app/views/wallaby/resources/show/_boolean.html.erb +5 -1
- data/app/views/wallaby/resources/show/_box.html.erb +9 -0
- data/app/views/wallaby/resources/show/_cidr.html.erb +5 -1
- data/app/views/wallaby/resources/show/_circle.html.erb +9 -0
- data/app/views/wallaby/resources/show/_citext.html.erb +4 -0
- data/app/views/wallaby/resources/show/_color.html.erb +6 -1
- data/app/views/wallaby/resources/show/_date.html.erb +4 -0
- data/app/views/wallaby/resources/show/_daterange.html.erb +4 -0
- data/app/views/wallaby/resources/show/_datetime.html.erb +4 -0
- data/app/views/wallaby/resources/show/_decimal.html.erb +4 -0
- data/app/views/wallaby/resources/show/_email.html.erb +4 -0
- data/app/views/wallaby/resources/show/_float.html.erb +4 -0
- data/app/views/wallaby/resources/show/_has_and_belongs_to_many.html.erb +6 -2
- data/app/views/wallaby/resources/show/_has_many.html.erb +6 -2
- data/app/views/wallaby/resources/show/_has_one.html.erb +5 -1
- data/app/views/wallaby/resources/show/_hstore.html.erb +4 -0
- data/app/views/wallaby/resources/show/_image.html.erb +9 -0
- data/app/views/wallaby/resources/show/_inet.html.erb +5 -1
- data/app/views/wallaby/resources/show/_int4range.html.erb +4 -0
- data/app/views/wallaby/resources/show/_int8range.html.erb +4 -0
- data/app/views/wallaby/resources/show/_integer.html.erb +4 -0
- data/app/views/wallaby/resources/show/_json.html.erb +4 -0
- data/app/views/wallaby/resources/show/_jsonb.html.erb +4 -0
- data/app/views/wallaby/resources/show/_line.html.erb +9 -0
- data/app/views/wallaby/resources/show/_longblob.html.erb +5 -0
- data/app/views/wallaby/resources/show/_longtext.html.erb +5 -0
- data/app/views/wallaby/resources/show/_lseg.html.erb +9 -0
- data/app/views/wallaby/resources/show/_ltree.html.erb +4 -0
- data/app/views/wallaby/resources/show/_macaddr.html.erb +4 -0
- data/app/views/wallaby/resources/show/_mediumblob.html.erb +5 -0
- data/app/views/wallaby/resources/show/_mediumtext.html.erb +5 -0
- data/app/views/wallaby/resources/show/_money.html.erb +4 -0
- data/app/views/wallaby/resources/show/_numrange.html.erb +4 -0
- data/app/views/wallaby/resources/show/_password.html.erb +9 -0
- data/app/views/wallaby/resources/show/_path.html.erb +9 -0
- data/app/views/wallaby/resources/show/_point.html.erb +4 -0
- data/app/views/wallaby/resources/show/_polygon.html.erb +9 -0
- data/app/views/wallaby/resources/show/_raw.html.erb +9 -0
- data/app/views/wallaby/resources/show/_serial.html.erb +5 -0
- data/app/views/wallaby/resources/show/_sti.html.erb +5 -0
- data/app/views/wallaby/resources/show/_string.html.erb +4 -0
- data/app/views/wallaby/resources/show/_text.html.erb +4 -0
- data/app/views/wallaby/resources/show/_time.html.erb +4 -0
- data/app/views/wallaby/resources/show/_tinyblob.html.erb +5 -0
- data/app/views/wallaby/resources/show/_tinytext.html.erb +5 -0
- data/app/views/wallaby/resources/show/_tsrange.html.erb +4 -0
- data/app/views/wallaby/resources/show/_tstzrange.html.erb +4 -0
- data/app/views/wallaby/resources/show/_tsvector.html.erb +4 -0
- data/app/views/wallaby/resources/show/_unsigned_bigint.html.erb +5 -0
- data/app/views/wallaby/resources/show/_unsigned_decimal.html.erb +5 -0
- data/app/views/wallaby/resources/show/_unsigned_float.html.erb +5 -0
- data/app/views/wallaby/resources/show/_unsigned_integer.html.erb +5 -0
- data/app/views/wallaby/resources/show/_uuid.html.erb +4 -0
- data/app/views/wallaby/resources/show/_xml.html.erb +4 -0
- data/app/views/wallaby/resources/show.html.erb +14 -24
- data/app/views/wallaby/resources/show.json.jbuilder +5 -0
- data/config/brakeman.ignore +26 -0
- data/config/locales/wallaby.en.yml +91 -0
- data/config/massa.yml +45 -0
- data/config/rails_best_practices.yml +42 -0
- data/config/routes.rb +29 -23
- data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder/association_builder.rb +39 -0
- data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder/polymorphic_builder.rb +44 -0
- data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder/sti_builder.rb +42 -0
- data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder.rb +41 -94
- data/lib/adaptors/wallaby/active_record/model_decorator/title_field_finder.rb +24 -14
- data/lib/adaptors/wallaby/active_record/model_decorator.rb +118 -64
- data/lib/adaptors/wallaby/active_record/model_finder.rb +44 -15
- data/lib/adaptors/wallaby/active_record/model_pagination_provider.rb +30 -0
- data/lib/adaptors/wallaby/active_record/model_service_provider/normalizer.rb +42 -0
- data/lib/adaptors/wallaby/active_record/model_service_provider/permitter.rb +64 -0
- data/lib/adaptors/wallaby/active_record/model_service_provider/querier/transformer.rb +70 -0
- data/lib/adaptors/wallaby/active_record/model_service_provider/querier.rb +102 -0
- data/lib/adaptors/wallaby/active_record/model_service_provider/validator.rb +29 -0
- data/lib/adaptors/wallaby/active_record/model_service_provider.rb +137 -0
- data/lib/adaptors/wallaby/active_record.rb +4 -1
- data/lib/decorators/wallaby/abstract_resource_decorator.rb +74 -0
- data/lib/decorators/wallaby/resource_decorator.rb +5 -76
- data/lib/errors/wallaby/model_not_found.rb +5 -1
- data/lib/errors/wallaby/not_found.rb +4 -0
- data/lib/errors/wallaby/resource_not_found.rb +5 -1
- data/lib/forms/wallaby/form_builder.rb +42 -19
- data/lib/helpers/wallaby/application_helper.rb +34 -24
- data/lib/helpers/wallaby/base_helper.rb +52 -0
- data/lib/helpers/wallaby/form_helper.rb +40 -16
- data/lib/helpers/wallaby/index_helper.rb +59 -0
- data/lib/helpers/wallaby/links_helper.rb +150 -81
- data/lib/helpers/wallaby/resources_helper.rb +41 -46
- data/lib/helpers/wallaby/secure_helper.rb +36 -19
- data/lib/helpers/wallaby/styling_helper.rb +53 -44
- data/lib/interfaces/wallaby/mode.rb +19 -12
- data/lib/interfaces/wallaby/model_decorator.rb +176 -50
- data/lib/interfaces/wallaby/model_finder.rb +7 -3
- data/lib/interfaces/wallaby/model_pagination_provider.rb +104 -0
- data/lib/interfaces/wallaby/model_service_provider.rb +71 -0
- data/lib/paginators/wallaby/abstract_resource_paginator.rb +23 -0
- data/lib/paginators/wallaby/resource_paginator.rb +6 -0
- data/lib/parsers/wallaby/parser.rb +32 -0
- data/lib/responders/wallaby/abstract_responder.rb +68 -0
- data/lib/responders/wallaby/resources_responder.rb +6 -0
- data/lib/servicers/wallaby/abstract_model_servicer.rb +48 -0
- data/lib/servicers/wallaby/model_servicer.rb +5 -0
- data/lib/services/wallaby/link_options_normalizer.rb +16 -0
- data/lib/services/wallaby/lookup_context_wrapper.rb +23 -30
- data/lib/services/wallaby/map/mode_mapper.rb +19 -0
- data/lib/services/wallaby/map/model_class_collector.rb +41 -0
- data/lib/services/wallaby/map/model_class_mapper.rb +24 -0
- data/lib/services/wallaby/map.rb +76 -39
- data/lib/services/wallaby/partial_renderer.rb +60 -0
- data/lib/services/wallaby/prefixes_builder.rb +54 -0
- data/lib/services/wallaby/sorting/hash_builder.rb +16 -0
- data/lib/services/wallaby/sorting/link_builder.rb +45 -0
- data/lib/services/wallaby/sorting/next_builder.rb +54 -0
- data/lib/services/wallaby/url_for.rb +36 -0
- data/lib/tree/wallaby/node.rb +17 -0
- data/lib/utils/wallaby/utils.rb +67 -22
- data/lib/wallaby/configuration/features.rb +12 -0
- data/lib/wallaby/configuration/metadata.rb +12 -0
- data/lib/wallaby/configuration/models.rb +27 -12
- data/lib/wallaby/configuration/pagination.rb +12 -0
- data/lib/wallaby/configuration/security.rb +55 -24
- data/lib/wallaby/configuration.rb +38 -19
- data/lib/wallaby/engine.rb +84 -39
- data/lib/wallaby/version.rb +1 -1
- data/lib/wallaby.rb +22 -3
- metadata +200 -55
- data/app/assets/javascripts/wallaby/form.js +0 -8
- data/app/assets/stylesheets/wallaby/base/_functions.scss +0 -0
- data/app/assets/stylesheets/wallaby/base/_normalize.scss +0 -0
- data/app/assets/stylesheets/wallaby/base/_reset.scss +0 -0
- data/app/assets/stylesheets/wallaby/components/_forms.scss +0 -53
- data/app/assets/stylesheets/wallaby/components/_nav.scss +0 -19
- data/app/assets/stylesheets/wallaby/components/_tables.scss +0 -78
- data/app/assets/stylesheets/wallaby/form.scss +0 -11
- data/app/controllers/wallaby/core_controller.rb +0 -28
- data/app/views/layouts/wallaby/_footer.html.erb +0 -2
- data/app/views/layouts/wallaby/_header.html.erb +0 -57
- data/app/views/layouts/wallaby/_navs.html.erb +0 -1
- data/app/views/wallaby/errors/access_denied.html.erb +0 -1
- data/app/views/wallaby/errors/not_authenticated.html.erb +0 -1
- data/app/views/wallaby/errors/not_found.html.erb +0 -6
- data/app/views/wallaby/errors/unprocessable_entity.erb +0 -1
- data/config/locales/en.yml +0 -29
- data/lib/adaptors/wallaby/active_record/model_operator/normalizer.rb +0 -44
- data/lib/adaptors/wallaby/active_record/model_operator/permitter.rb +0 -50
- data/lib/adaptors/wallaby/active_record/model_operator/querier.rb +0 -47
- data/lib/adaptors/wallaby/active_record/model_operator/validator.rb +0 -16
- data/lib/adaptors/wallaby/active_record/model_operator.rb +0 -82
- data/lib/errors/wallaby/deprecated.rb +0 -4
- data/lib/errors/wallaby/operation_not_found.rb +0 -4
- data/lib/handlers/wallaby/cached_compiled_erb.rb +0 -14
- data/lib/helpers/wallaby/core_helper.rb +0 -50
- data/lib/helpers/wallaby/paginatable_helper.rb +0 -9
- data/lib/helpers/wallaby/sorting_helper.rb +0 -43
- data/lib/interfaces/wallaby/model_operator.rb +0 -31
- data/lib/services/wallaby/decorator_finder.rb +0 -16
- data/lib/services/wallaby/model_servicer.rb +0 -38
- data/lib/services/wallaby/servicer_finder.rb +0 -5
|
@@ -1,18 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
module Wallaby
|
|
2
|
+
class ActiveRecord
|
|
3
|
+
class ModelDecorator
|
|
4
|
+
# Try to find the field that can be used as title
|
|
5
|
+
class TitleFieldFinder
|
|
6
|
+
TITLE_FIELD_TYPES = %w(string).freeze
|
|
7
|
+
TITLE_NAMES = %w(name title string text).freeze
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
def initialize(model_class, fields)
|
|
10
|
+
@model_class = model_class
|
|
11
|
+
@fields = fields
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def find
|
|
15
|
+
possible_title_fields = @fields.select do |_field_name, metadata|
|
|
16
|
+
TITLE_FIELD_TYPES.include? metadata[:type]
|
|
17
|
+
end
|
|
18
|
+
target_field = possible_title_fields.values.find do |metadata|
|
|
19
|
+
TITLE_NAMES.any? { |v| metadata[:name].index v }
|
|
20
|
+
end
|
|
21
|
+
target_field ||= possible_title_fields.values.first
|
|
22
|
+
target_field ||= { name: @model_class.primary_key }
|
|
23
|
+
target_field[:name]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
13
26
|
end
|
|
14
|
-
target_field ||= possible_title_fields.values.first
|
|
15
|
-
target_field ||= { name: @model_class.primary_key }
|
|
16
|
-
target_field[:name]
|
|
17
27
|
end
|
|
18
28
|
end
|
|
@@ -1,81 +1,135 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
end
|
|
9
|
-
end.with_indifferent_access
|
|
10
|
-
end
|
|
1
|
+
module Wallaby
|
|
2
|
+
class ActiveRecord
|
|
3
|
+
# Modal decorator for Active Record
|
|
4
|
+
class ModelDecorator < ::Wallaby::ModelDecorator
|
|
5
|
+
# Data types to exclude for index page
|
|
6
|
+
INDEX_EXCLUSIVE_DATA_TYPES =
|
|
7
|
+
%w(binary citext hstore json jsonb text tsvector xml).freeze
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
end
|
|
9
|
+
# Data types to exclude for form page
|
|
10
|
+
FORM_EXCLUSIVE_DATA_TYPES = %w(created_at updated_at).freeze
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
# Origin metadata coming from data source.
|
|
13
|
+
# It needs to be frozen so that we can keep the metadata integrity
|
|
14
|
+
# @return [Hash]
|
|
15
|
+
# example:
|
|
16
|
+
# {
|
|
17
|
+
# # general field
|
|
18
|
+
# id: { name: 'id', type: 'integer', label: 'Id', is_origin: true },
|
|
19
|
+
# # association field
|
|
20
|
+
# category: {
|
|
21
|
+
# 'name' => 'category',
|
|
22
|
+
# 'type' => 'belongs_to',
|
|
23
|
+
# 'label' => 'Category',
|
|
24
|
+
# 'is_origin' => true,
|
|
25
|
+
# 'is_association' => true,
|
|
26
|
+
# 'is_through' => false,
|
|
27
|
+
# 'has_scope' => false,
|
|
28
|
+
# 'foreign_key' => 'category_id',
|
|
29
|
+
# 'class' => Category
|
|
30
|
+
# }
|
|
31
|
+
# }
|
|
32
|
+
def fields
|
|
33
|
+
@fields ||= ::ActiveSupport::HashWithIndifferentAccess.new.tap do |hash|
|
|
34
|
+
# NOTE: There is a chance that people create Active Record class
|
|
35
|
+
# before they do the migration, so initialising the fields will raise
|
|
36
|
+
# all kinds of error. Therefore, we need to check the table existence
|
|
37
|
+
if @model_class.table_exists?
|
|
38
|
+
hash.merge! general_fields
|
|
39
|
+
hash.merge! association_fields
|
|
40
|
+
hash.except!(*foreign_keys_from_associations)
|
|
41
|
+
end
|
|
42
|
+
end.freeze
|
|
43
|
+
end
|
|
19
44
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
45
|
+
# A copy of all the fields for index page
|
|
46
|
+
# @return [Hash]
|
|
47
|
+
def index_fields
|
|
48
|
+
@index_fields ||= Utils.clone fields
|
|
49
|
+
end
|
|
23
50
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
end
|
|
51
|
+
# A copy of all the fields for show page
|
|
52
|
+
# @return [Hash]
|
|
53
|
+
def show_fields
|
|
54
|
+
@show_fields ||= Utils.clone fields
|
|
55
|
+
end
|
|
30
56
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
end.keys
|
|
37
|
-
end
|
|
57
|
+
# A copy of all the fields for form page
|
|
58
|
+
# @return [Hash]
|
|
59
|
+
def form_fields
|
|
60
|
+
@form_fields ||= Utils.clone fields
|
|
61
|
+
end
|
|
38
62
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
63
|
+
# Fields name for index page
|
|
64
|
+
# @return [Array]
|
|
65
|
+
def index_field_names
|
|
66
|
+
@index_field_names ||= begin
|
|
67
|
+
index_fields.reject do |_field_name, metadata|
|
|
68
|
+
metadata[:is_association] \
|
|
69
|
+
|| INDEX_EXCLUSIVE_DATA_TYPES.include?(metadata[:type])
|
|
70
|
+
end.keys
|
|
71
|
+
end
|
|
72
|
+
end
|
|
42
73
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
74
|
+
# Fields name for form page
|
|
75
|
+
# @return [Array]
|
|
76
|
+
def form_field_names
|
|
77
|
+
@form_field_names ||= begin
|
|
78
|
+
form_fields.reject do |field_name, metadata|
|
|
79
|
+
field_name == primary_key \
|
|
80
|
+
|| FORM_EXCLUSIVE_DATA_TYPES.include?(field_name) \
|
|
81
|
+
|| metadata[:has_scope] || metadata[:is_through]
|
|
82
|
+
end.keys
|
|
83
|
+
end
|
|
84
|
+
end
|
|
46
85
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
86
|
+
# Errors for resource
|
|
87
|
+
# @return [ActiveModel::Errors]
|
|
88
|
+
def form_active_errors(resource)
|
|
89
|
+
resource.errors
|
|
90
|
+
end
|
|
50
91
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
92
|
+
# Primary key for the resource
|
|
93
|
+
# @return [String]
|
|
94
|
+
def primary_key
|
|
95
|
+
@model_class.primary_key
|
|
96
|
+
end
|
|
55
97
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
98
|
+
# To guess the title for resource.
|
|
99
|
+
# It will go through the fields and try to find out the one that looks
|
|
100
|
+
# like a name or text to represent this resource. Otherwise, it will fall
|
|
101
|
+
# back to primary key.
|
|
102
|
+
# @param resource [Object]
|
|
103
|
+
# @return [String] the title of given resource
|
|
104
|
+
def guess_title(resource)
|
|
105
|
+
resource.public_send title_field_finder.find
|
|
106
|
+
end
|
|
59
107
|
|
|
60
|
-
|
|
108
|
+
protected
|
|
61
109
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
keys
|
|
67
|
-
end
|
|
68
|
-
end
|
|
110
|
+
# @see Wallaby::ModelDecorator::FieldsBuilder
|
|
111
|
+
def field_builder
|
|
112
|
+
@field_builder ||= FieldsBuilder.new @model_class
|
|
113
|
+
end
|
|
69
114
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
115
|
+
# @see Wallaby::ModelDecorator::TitleFieldFinder
|
|
116
|
+
def title_field_finder
|
|
117
|
+
@title_field_finder ||=
|
|
118
|
+
TitleFieldFinder.new @model_class, general_fields
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
delegate :general_fields, :association_fields, to: :field_builder
|
|
75
122
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
123
|
+
# Find out all the foreign keys for a list of fields
|
|
124
|
+
# @param fields [Hash] metadata of fields
|
|
125
|
+
# @return [Array] a list of foreign keys
|
|
126
|
+
def foreign_keys_from_associations(fields = association_fields)
|
|
127
|
+
fields.each_with_object([]) do |(_field_name, metadata), keys|
|
|
128
|
+
keys << metadata[:foreign_key] if metadata[:foreign_key]
|
|
129
|
+
keys << metadata[:polymorphic_type] if metadata[:polymorphic_type]
|
|
130
|
+
keys
|
|
131
|
+
end
|
|
132
|
+
end
|
|
79
133
|
end
|
|
80
134
|
end
|
|
81
135
|
end
|
|
@@ -1,22 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
module Wallaby
|
|
2
|
+
class ActiveRecord
|
|
3
|
+
# Model finder
|
|
4
|
+
class ModelFinder < ::Wallaby::ModelFinder
|
|
5
|
+
# @return [Array] a list of ActiveRecord subclasses
|
|
6
|
+
def all
|
|
7
|
+
self.class.base.descendants.reject do |model_class|
|
|
8
|
+
abstract?(model_class) || anonymous?(model_class) \
|
|
9
|
+
|| schema?(model_class) || habtm?(model_class)
|
|
10
|
+
end.sort_by(&:to_s)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Base class should be either ApplicationRecord or ActiveRecord::Base
|
|
14
|
+
def self.base
|
|
15
|
+
return ::ApplicationRecord if defined? ::ApplicationRecord
|
|
7
16
|
::ActiveRecord::Base
|
|
8
17
|
end
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
18
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
# Is model class abstract?
|
|
22
|
+
# @param [Class] model class
|
|
23
|
+
# @return [Boolean]
|
|
24
|
+
def abstract?(model_class)
|
|
25
|
+
model_class.abstract_class?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Is model class anonymous?
|
|
29
|
+
# @param [Class] model class
|
|
30
|
+
# @return [Boolean]
|
|
31
|
+
def anonymous?(model_class)
|
|
32
|
+
model_class.to_s.start_with? '#<Class'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Is model class the shcema migration class?
|
|
36
|
+
# @param [Class] model class
|
|
37
|
+
# @return [Boolean]
|
|
38
|
+
def schema?(model_class)
|
|
39
|
+
model_class.name == 'ActiveRecord::SchemaMigration'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Check and see if given model class is intermediate class that generated
|
|
43
|
+
# for has and belongs to many assocation
|
|
44
|
+
# @param [Class] model class
|
|
45
|
+
# @return [Boolean]
|
|
46
|
+
def habtm?(model_class)
|
|
18
47
|
model_class.name.index('HABTM')
|
|
19
|
-
end
|
|
48
|
+
end
|
|
20
49
|
end
|
|
21
50
|
end
|
|
22
51
|
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Wallaby
|
|
2
|
+
class ActiveRecord
|
|
3
|
+
# Model pagination provider
|
|
4
|
+
class ModelPaginationProvider < ::Wallaby::ModelPaginationProvider
|
|
5
|
+
# Check if collection has pagination feature
|
|
6
|
+
# @return [Boolean]
|
|
7
|
+
def paginatable?
|
|
8
|
+
@collection.respond_to? :total_count
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Total count for the query
|
|
12
|
+
# @return [Integer]
|
|
13
|
+
def total
|
|
14
|
+
@collection.total_count
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Page size
|
|
18
|
+
# @return [Integer]
|
|
19
|
+
def page_size
|
|
20
|
+
@params[:per].try(:to_i) || Wallaby.configuration.pagination.page_size
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Page number
|
|
24
|
+
# @return [Integer]
|
|
25
|
+
def page_number
|
|
26
|
+
[@params[:page].to_i, 1].max
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Wallaby
|
|
2
|
+
class ActiveRecord
|
|
3
|
+
class ModelServiceProvider
|
|
4
|
+
# Normalizer
|
|
5
|
+
class Normalizer
|
|
6
|
+
def initialize(model_decorator)
|
|
7
|
+
@model_decorator = model_decorator
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def normalize(params)
|
|
11
|
+
params.each do |field_name, values|
|
|
12
|
+
metadata = @model_decorator.fields[field_name] || EMPTY_HASH
|
|
13
|
+
type = (metadata[:type] || EMPTY_STRING)[/range|point|binary/]
|
|
14
|
+
next unless type
|
|
15
|
+
send "normalize_#{type}_values", params, field_name, values
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def normalize_range_values(params, field_name, values)
|
|
20
|
+
normalized = Array(values).map(&:presence).compact
|
|
21
|
+
params[field_name] =
|
|
22
|
+
if normalized.present? && values.length == 2
|
|
23
|
+
values.first...values.last
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def normalize_point_values(params, field_name, values)
|
|
28
|
+
normalized = Array(values).map(&:presence).compact
|
|
29
|
+
params[field_name] =
|
|
30
|
+
normalized.present? &&
|
|
31
|
+
values.map(&:to_f) || nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def normalize_binary_values(params, field_name, values)
|
|
35
|
+
params[field_name] =
|
|
36
|
+
values.is_a?(::ActionDispatch::Http::UploadedFile) &&
|
|
37
|
+
values.read || nil
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module Wallaby
|
|
2
|
+
class ActiveRecord
|
|
3
|
+
class ModelServiceProvider
|
|
4
|
+
# Filter the params
|
|
5
|
+
class Permitter
|
|
6
|
+
def initialize(model_decorator)
|
|
7
|
+
@model_decorator = model_decorator
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def simple_field_names
|
|
11
|
+
field_names =
|
|
12
|
+
non_range_fields.keys +
|
|
13
|
+
belongs_to_fields.map do |_, metadata|
|
|
14
|
+
[metadata[:foreign_key], metadata[:polymorphic_type]]
|
|
15
|
+
end.flatten.compact
|
|
16
|
+
fields = [@model_decorator.primary_key, 'created_at', 'updated_at']
|
|
17
|
+
field_names.reject { |field_name| fields.include? field_name }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def compound_hashed_fields
|
|
21
|
+
field_names =
|
|
22
|
+
range_fields.keys +
|
|
23
|
+
many_association_fields.map { |_, metadata| metadata[:foreign_key] }
|
|
24
|
+
field_names.each_with_object({}) { |name, hash| hash[name] = [] }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
protected
|
|
28
|
+
|
|
29
|
+
def non_association_fields
|
|
30
|
+
@model_decorator
|
|
31
|
+
.fields.reject { |_, metadata| metadata[:is_association] }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def non_range_fields
|
|
35
|
+
non_association_fields
|
|
36
|
+
.reject { |_, metadata| /range|point/ =~ metadata[:type] }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def range_fields
|
|
40
|
+
non_association_fields.select do |_, metadata|
|
|
41
|
+
/range|point/ =~ metadata[:type]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def association_fields
|
|
46
|
+
@model_decorator.fields.select do |_, metadata|
|
|
47
|
+
metadata[:is_association] &&
|
|
48
|
+
!metadata[:has_scope] && !metadata[:is_through]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def many_association_fields
|
|
53
|
+
association_fields.select { |_, metadata| /many/ =~ metadata[:type] }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def belongs_to_fields
|
|
57
|
+
association_fields.select do |_field_name, metadata|
|
|
58
|
+
metadata[:type] == 'belongs_to'
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Wallaby
|
|
2
|
+
class ActiveRecord
|
|
3
|
+
class ModelServiceProvider
|
|
4
|
+
class Querier
|
|
5
|
+
# Build up query using the results
|
|
6
|
+
class Transformer < Parslet::Transform
|
|
7
|
+
SIMPLE_OPERATORS = {
|
|
8
|
+
':' => :eq,
|
|
9
|
+
':=' => :eq,
|
|
10
|
+
':!' => :not_eq,
|
|
11
|
+
':!=' => :not_eq,
|
|
12
|
+
':<>' => :not_eq,
|
|
13
|
+
':~' => :matches,
|
|
14
|
+
':^' => :matches,
|
|
15
|
+
':$' => :matches,
|
|
16
|
+
':!~' => :does_not_match,
|
|
17
|
+
':!^' => :does_not_match,
|
|
18
|
+
':!$' => :does_not_match,
|
|
19
|
+
':>' => :gt,
|
|
20
|
+
':>=' => :gteq,
|
|
21
|
+
':<' => :lt,
|
|
22
|
+
':<=' => :lteq
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
SEQUENCE_OPERATORS = {
|
|
26
|
+
':' => :in,
|
|
27
|
+
':=' => :in,
|
|
28
|
+
':!' => :not_in,
|
|
29
|
+
':!=' => :not_in,
|
|
30
|
+
':<>' => :not_in,
|
|
31
|
+
':()' => :between,
|
|
32
|
+
':!()' => :not_between
|
|
33
|
+
}.freeze
|
|
34
|
+
|
|
35
|
+
rule keyword: simple(:value) do
|
|
36
|
+
value.try :to_str
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
rule keyword: sequence(:value) do
|
|
40
|
+
value.presence.try :map, :to_str
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
rule left: simple(:left), op: simple(:op), right: simple(:right) do
|
|
44
|
+
oped = op.try :to_str
|
|
45
|
+
operator = SIMPLE_OPERATORS[oped]
|
|
46
|
+
next unless operator
|
|
47
|
+
lefted = left.try :to_str
|
|
48
|
+
convert = case oped
|
|
49
|
+
when ':~', ':!~' then "%#{right}%"
|
|
50
|
+
when ':^', ':!^' then "#{right}%"
|
|
51
|
+
when ':$', ':!$' then "%#{right}"
|
|
52
|
+
end
|
|
53
|
+
{ left: lefted, op: operator, right: convert || right }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
rule left: simple(:left), op: simple(:op), right: sequence(:right) do
|
|
57
|
+
oped = op.try :to_str
|
|
58
|
+
operator = SEQUENCE_OPERATORS[oped]
|
|
59
|
+
next unless operator
|
|
60
|
+
lefted = left.try :to_str
|
|
61
|
+
convert = if %w(:() :!()).include?(oped)
|
|
62
|
+
Range.new right.try(:first), right.try(:last)
|
|
63
|
+
end
|
|
64
|
+
{ left: lefted, op: operator, right: convert || right }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
module Wallaby
|
|
2
|
+
class ActiveRecord
|
|
3
|
+
class ModelServiceProvider
|
|
4
|
+
# Query builder
|
|
5
|
+
class Querier
|
|
6
|
+
TEXT_FIELDS = %w(string text citext).freeze
|
|
7
|
+
|
|
8
|
+
def initialize(model_decorator)
|
|
9
|
+
@model_decorator = model_decorator
|
|
10
|
+
@model_class = @model_decorator.model_class
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def search(params)
|
|
14
|
+
filter_name, keywords, field_queries = extract params
|
|
15
|
+
scope = filtered_by filter_name
|
|
16
|
+
query = text_search keywords
|
|
17
|
+
query = field_search field_queries, query
|
|
18
|
+
scope.where query
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def parser
|
|
24
|
+
@parser ||= Parser.new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def transformer
|
|
28
|
+
@transformer ||= Transformer.new
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def table
|
|
32
|
+
@model_class.arel_table
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def extract(params)
|
|
36
|
+
expressions = to_expressions params
|
|
37
|
+
keywords = expressions.select { |v| v.is_a? String }
|
|
38
|
+
field_queries = expressions.select { |v| v.is_a? Hash }
|
|
39
|
+
filter_name = params[:filter]
|
|
40
|
+
[filter_name, keywords, field_queries]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_expressions(params)
|
|
44
|
+
parsed = parser.parse(params[:q] || EMPTY_STRING)
|
|
45
|
+
converted = transformer.apply parsed
|
|
46
|
+
converted.is_a?(Array) ? converted : [converted]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def filtered_by(filter_name)
|
|
50
|
+
valid_filter_name =
|
|
51
|
+
Utils.find_filter_name(filter_name, @model_decorator.filters)
|
|
52
|
+
scope = find_scope(valid_filter_name)
|
|
53
|
+
if scope.blank? then unscoped
|
|
54
|
+
elsif scope.respond_to?(:call) then @model_class.instance_exec(&scope)
|
|
55
|
+
elsif @model_class.respond_to?(scope)
|
|
56
|
+
@model_class.public_send(scope)
|
|
57
|
+
else unscoped
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def find_scope(filter_name)
|
|
62
|
+
filter = @model_decorator.filters[filter_name] || {}
|
|
63
|
+
filter[:scope] || filter_name
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def unscoped
|
|
67
|
+
@model_class.where nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def text_search(keywords, query = nil)
|
|
71
|
+
return query if keywords.blank?
|
|
72
|
+
text_fields.each do |field_name|
|
|
73
|
+
sub_query = nil
|
|
74
|
+
keywords.each do |keyword|
|
|
75
|
+
exp = table[field_name].matches("%#{keyword}%")
|
|
76
|
+
sub_query = sub_query.try(:and, exp) || exp
|
|
77
|
+
end
|
|
78
|
+
query = query.try(:or, sub_query) || sub_query
|
|
79
|
+
end
|
|
80
|
+
query
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def field_search(field_queries, query)
|
|
84
|
+
field_queries.each do |exp|
|
|
85
|
+
next unless @model_decorator.fields[exp[:left]]
|
|
86
|
+
sub_query = table[exp[:left]].public_send(exp[:op], exp[:right])
|
|
87
|
+
query = query.try(:and, sub_query) || sub_query
|
|
88
|
+
end
|
|
89
|
+
query
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def text_fields
|
|
93
|
+
index_field_names = @model_decorator.index_field_names.map(&:to_s)
|
|
94
|
+
@model_decorator.fields.select do |field_name, metadata|
|
|
95
|
+
index_field_names.include?(field_name) &&
|
|
96
|
+
TEXT_FIELDS.include?(metadata[:type].to_s)
|
|
97
|
+
end.keys
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Wallaby
|
|
2
|
+
class ActiveRecord
|
|
3
|
+
class ModelServiceProvider
|
|
4
|
+
# Validator
|
|
5
|
+
class Validator
|
|
6
|
+
def initialize(model_decorator)
|
|
7
|
+
@model_decorator = model_decorator
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def valid?(resource)
|
|
11
|
+
resource.attributes.each do |field_name, values|
|
|
12
|
+
metadata = @model_decorator.fields[field_name]
|
|
13
|
+
next if valid_range_type? values, metadata
|
|
14
|
+
resource.errors.add field_name, 'required for range data'
|
|
15
|
+
end
|
|
16
|
+
resource.errors.blank?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def valid_range_type?(values, metadata)
|
|
22
|
+
!metadata \
|
|
23
|
+
|| !%w(daterange tsrange tstzrange).include?(metadata[:type]) \
|
|
24
|
+
|| !values.try(:any?, &:blank?)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|