super 0.0.16 → 0.17.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 +4 -4
- data/app/assets/javascripts/super/application.js +146 -13
- data/app/assets/stylesheets/super/application.css +0 -1
- data/app/controllers/super/application_controller.rb +15 -2
- data/app/controllers/super/substructure_controller.rb +19 -8
- data/app/views/super/application/_display_actions.html.erb +1 -1
- data/app/views/super/application/_filter.html.erb +62 -2
- data/app/views/super/application/_member_header.html.erb +1 -1
- data/app/views/super/application/_sort_expression.html.erb +2 -2
- data/frontend/super-frontend/dist/application.css +0 -1
- data/frontend/super-frontend/dist/application.js +146 -13
- data/lib/super.rb +1 -0
- data/lib/super/display/guesser.rb +1 -1
- data/lib/super/display/schema_types.rb +0 -1
- data/lib/super/error.rb +2 -0
- data/lib/super/filter.rb +1 -1
- data/lib/super/filter/form_object.rb +74 -48
- data/lib/super/filter/guesser.rb +2 -0
- data/lib/super/filter/operator.rb +90 -64
- data/lib/super/filter/schema_types.rb +63 -80
- data/lib/super/form/builder.rb +6 -3
- data/lib/super/form/field_transcript.rb +43 -0
- data/lib/super/form/guesser.rb +1 -1
- data/lib/super/form/schema_types.rb +11 -20
- data/lib/super/link.rb +1 -1
- data/lib/super/schema.rb +4 -0
- data/lib/super/version.rb +1 -1
- metadata +4 -7
- data/app/views/super/application/_filter_type_select.html.erb +0 -21
- data/app/views/super/application/_filter_type_text.html.erb +0 -18
- data/app/views/super/application/_filter_type_timestamp.html.erb +0 -24
- data/app/views/super/application/_form_field_select.html.erb +0 -1
| @@ -413,7 +413,7 @@ var Super = (function (exports) { | |
| 413 413 | 
             
                    }).call(this);
         | 
| 414 414 | 
             
                    (function () {
         | 
| 415 415 | 
             
                      var AcceptHeaders, CSRFProtection, createXHR, cspNonce, prepareOptions, processResponse;
         | 
| 416 | 
            -
                      cspNonce = Rails.cspNonce, CSRFProtection = Rails.CSRFProtection | 
| 416 | 
            +
                      cspNonce = Rails.cspNonce, CSRFProtection = Rails.CSRFProtection;
         | 
| 417 417 | 
             
                      AcceptHeaders = {
         | 
| 418 418 | 
             
                        '*': '*/*',
         | 
| 419 419 | 
             
                        text: 'text/plain',
         | 
| @@ -3975,7 +3975,7 @@ var Super = (function (exports) { | |
| 3975 3975 | 
             
                };
         | 
| 3976 3976 | 
             
              }
         | 
| 3977 3977 |  | 
| 3978 | 
            -
              var _default$ | 
| 3978 | 
            +
              var _default$8 = /*#__PURE__*/function (_Controller) {
         | 
| 3979 3979 | 
             
                _inherits(_default, _Controller);
         | 
| 3980 3980 |  | 
| 3981 3981 | 
             
                var _super = _createSuper(_default);
         | 
| @@ -4004,7 +4004,7 @@ var Super = (function (exports) { | |
| 4004 4004 | 
             
                return _default;
         | 
| 4005 4005 | 
             
              }(Controller);
         | 
| 4006 4006 |  | 
| 4007 | 
            -
              var _default$ | 
| 4007 | 
            +
              var _default$7 = /*#__PURE__*/function (_Controller) {
         | 
| 4008 4008 | 
             
                _inherits(_default, _Controller);
         | 
| 4009 4009 |  | 
| 4010 4010 | 
             
                var _super = _createSuper(_default);
         | 
| @@ -4040,7 +4040,7 @@ var Super = (function (exports) { | |
| 4040 4040 | 
             
                return _default;
         | 
| 4041 4041 | 
             
              }(Controller);
         | 
| 4042 4042 |  | 
| 4043 | 
            -
              var _default$ | 
| 4043 | 
            +
              var _default$6 = /*#__PURE__*/function (_Controller) {
         | 
| 4044 4044 | 
             
                _inherits(_default, _Controller);
         | 
| 4045 4045 |  | 
| 4046 4046 | 
             
                var _super = _createSuper(_default);
         | 
| @@ -4064,7 +4064,7 @@ var Super = (function (exports) { | |
| 4064 4064 | 
             
                return _default;
         | 
| 4065 4065 | 
             
              }(Controller);
         | 
| 4066 4066 |  | 
| 4067 | 
            -
              var _default$ | 
| 4067 | 
            +
              var _default$5 = /*#__PURE__*/function (_Controller) {
         | 
| 4068 4068 | 
             
                _inherits(_default, _Controller);
         | 
| 4069 4069 |  | 
| 4070 4070 | 
             
                var _super = _createSuper(_default);
         | 
| @@ -4094,7 +4094,7 @@ var Super = (function (exports) { | |
| 4094 4094 | 
             
                return _default;
         | 
| 4095 4095 | 
             
              }(Controller);
         | 
| 4096 4096 |  | 
| 4097 | 
            -
              var _default$ | 
| 4097 | 
            +
              var _default$4 = /*#__PURE__*/function (_Controller) {
         | 
| 4098 4098 | 
             
                _inherits(_default, _Controller);
         | 
| 4099 4099 |  | 
| 4100 4100 | 
             
                var _super = _createSuper(_default);
         | 
| @@ -6354,7 +6354,7 @@ var Super = (function (exports) { | |
| 6354 6354 | 
             
                window.flatpickr = flatpickr;
         | 
| 6355 6355 | 
             
              }
         | 
| 6356 6356 |  | 
| 6357 | 
            -
              var _default$ | 
| 6357 | 
            +
              var _default$3 = /*#__PURE__*/function (_Controller) {
         | 
| 6358 6358 | 
             
                _inherits(_default, _Controller);
         | 
| 6359 6359 |  | 
| 6360 6360 | 
             
                var _super = _createSuper(_default);
         | 
| @@ -6382,6 +6382,137 @@ var Super = (function (exports) { | |
| 6382 6382 | 
             
                return _default;
         | 
| 6383 6383 | 
             
              }(Controller);
         | 
| 6384 6384 |  | 
| 6385 | 
            +
              var _default$2 = /*#__PURE__*/function (_Controller) {
         | 
| 6386 | 
            +
                _inherits(_default, _Controller);
         | 
| 6387 | 
            +
             | 
| 6388 | 
            +
                var _super = _createSuper(_default);
         | 
| 6389 | 
            +
             | 
| 6390 | 
            +
                function _default() {
         | 
| 6391 | 
            +
                  _classCallCheck(this, _default);
         | 
| 6392 | 
            +
             | 
| 6393 | 
            +
                  return _super.apply(this, arguments);
         | 
| 6394 | 
            +
                }
         | 
| 6395 | 
            +
             | 
| 6396 | 
            +
                _createClass(_default, [{
         | 
| 6397 | 
            +
                  key: "connect",
         | 
| 6398 | 
            +
                  value: function connect() {
         | 
| 6399 | 
            +
                    var _this = this;
         | 
| 6400 | 
            +
             | 
| 6401 | 
            +
                    this.tabTargets.forEach(function (tab) {
         | 
| 6402 | 
            +
                      tab.tabContainer = _this;
         | 
| 6403 | 
            +
                    });
         | 
| 6404 | 
            +
                  }
         | 
| 6405 | 
            +
                }, {
         | 
| 6406 | 
            +
                  key: "activeTabIdentifier",
         | 
| 6407 | 
            +
                  get: function get() {
         | 
| 6408 | 
            +
                    return this.controlTarget.value;
         | 
| 6409 | 
            +
                  }
         | 
| 6410 | 
            +
                }, {
         | 
| 6411 | 
            +
                  key: "change",
         | 
| 6412 | 
            +
                  value: function change(event) {
         | 
| 6413 | 
            +
                    this.update(event.target.value);
         | 
| 6414 | 
            +
                  }
         | 
| 6415 | 
            +
                }, {
         | 
| 6416 | 
            +
                  key: "update",
         | 
| 6417 | 
            +
                  value: function update(newActiveTabIdentifier) {
         | 
| 6418 | 
            +
                    var _this2 = this;
         | 
| 6419 | 
            +
             | 
| 6420 | 
            +
                    this.tabTargets.forEach(function (tab) {
         | 
| 6421 | 
            +
                      var tabController = _this2.application.getControllerForElementAndIdentifier(tab, _this2.tabControllerNameValue);
         | 
| 6422 | 
            +
             | 
| 6423 | 
            +
                      if (tab.dataset[_this2.tabIdentifierGetterValue] == newActiveTabIdentifier) {
         | 
| 6424 | 
            +
                        tabController.show();
         | 
| 6425 | 
            +
                      } else {
         | 
| 6426 | 
            +
                        tabController.hide();
         | 
| 6427 | 
            +
                      }
         | 
| 6428 | 
            +
                    });
         | 
| 6429 | 
            +
                  }
         | 
| 6430 | 
            +
                }], [{
         | 
| 6431 | 
            +
                  key: "targets",
         | 
| 6432 | 
            +
                  get: function get() {
         | 
| 6433 | 
            +
                    return ["control", "tab"];
         | 
| 6434 | 
            +
                  }
         | 
| 6435 | 
            +
                }, {
         | 
| 6436 | 
            +
                  key: "values",
         | 
| 6437 | 
            +
                  get: function get() {
         | 
| 6438 | 
            +
                    return {
         | 
| 6439 | 
            +
                      tabIdentifierGetter: String,
         | 
| 6440 | 
            +
                      tabControllerName: String
         | 
| 6441 | 
            +
                    };
         | 
| 6442 | 
            +
                  }
         | 
| 6443 | 
            +
                }]);
         | 
| 6444 | 
            +
             | 
| 6445 | 
            +
                return _default;
         | 
| 6446 | 
            +
              }(Controller);
         | 
| 6447 | 
            +
             | 
| 6448 | 
            +
              var _default$1 = /*#__PURE__*/function (_Controller) {
         | 
| 6449 | 
            +
                _inherits(_default, _Controller);
         | 
| 6450 | 
            +
             | 
| 6451 | 
            +
                var _super = _createSuper(_default);
         | 
| 6452 | 
            +
             | 
| 6453 | 
            +
                function _default() {
         | 
| 6454 | 
            +
                  _classCallCheck(this, _default);
         | 
| 6455 | 
            +
             | 
| 6456 | 
            +
                  return _super.apply(this, arguments);
         | 
| 6457 | 
            +
                }
         | 
| 6458 | 
            +
             | 
| 6459 | 
            +
                _createClass(_default, [{
         | 
| 6460 | 
            +
                  key: "connect",
         | 
| 6461 | 
            +
                  value: function connect() {
         | 
| 6462 | 
            +
                    var tabContainer = this.element[this.tabContainerGetterValue];
         | 
| 6463 | 
            +
             | 
| 6464 | 
            +
                    if (tabContainer.activeTabIdentifier === this.identifierValue) {
         | 
| 6465 | 
            +
                      this.show();
         | 
| 6466 | 
            +
                    } else {
         | 
| 6467 | 
            +
                      this.hide();
         | 
| 6468 | 
            +
                    }
         | 
| 6469 | 
            +
                  }
         | 
| 6470 | 
            +
                }, {
         | 
| 6471 | 
            +
                  key: "toggle",
         | 
| 6472 | 
            +
                  value: function toggle() {
         | 
| 6473 | 
            +
                    if (this.hasContentTarget) {
         | 
| 6474 | 
            +
                      this.hide();
         | 
| 6475 | 
            +
                    } else {
         | 
| 6476 | 
            +
                      this.show();
         | 
| 6477 | 
            +
                    }
         | 
| 6478 | 
            +
                  }
         | 
| 6479 | 
            +
                }, {
         | 
| 6480 | 
            +
                  key: "show",
         | 
| 6481 | 
            +
                  value: function show() {
         | 
| 6482 | 
            +
                    if (this.hasContentTarget) {
         | 
| 6483 | 
            +
                      return;
         | 
| 6484 | 
            +
                    }
         | 
| 6485 | 
            +
             | 
| 6486 | 
            +
                    var pocketContent = this.pocketTarget.content.cloneNode(true);
         | 
| 6487 | 
            +
                    this.element.appendChild(pocketContent);
         | 
| 6488 | 
            +
                  }
         | 
| 6489 | 
            +
                }, {
         | 
| 6490 | 
            +
                  key: "hide",
         | 
| 6491 | 
            +
                  value: function hide() {
         | 
| 6492 | 
            +
                    if (!this.hasContentTarget) {
         | 
| 6493 | 
            +
                      return;
         | 
| 6494 | 
            +
                    }
         | 
| 6495 | 
            +
             | 
| 6496 | 
            +
                    this.contentTarget.remove();
         | 
| 6497 | 
            +
                  }
         | 
| 6498 | 
            +
                }], [{
         | 
| 6499 | 
            +
                  key: "targets",
         | 
| 6500 | 
            +
                  get: function get() {
         | 
| 6501 | 
            +
                    return ["pocket", "content"];
         | 
| 6502 | 
            +
                  }
         | 
| 6503 | 
            +
                }, {
         | 
| 6504 | 
            +
                  key: "values",
         | 
| 6505 | 
            +
                  get: function get() {
         | 
| 6506 | 
            +
                    return {
         | 
| 6507 | 
            +
                      identifier: String,
         | 
| 6508 | 
            +
                      tabContainerGetter: String
         | 
| 6509 | 
            +
                    };
         | 
| 6510 | 
            +
                  }
         | 
| 6511 | 
            +
                }]);
         | 
| 6512 | 
            +
             | 
| 6513 | 
            +
                return _default;
         | 
| 6514 | 
            +
              }(Controller);
         | 
| 6515 | 
            +
             | 
| 6385 6516 | 
             
              var _default = /*#__PURE__*/function (_Controller) {
         | 
| 6386 6517 | 
             
                _inherits(_default, _Controller);
         | 
| 6387 6518 |  | 
| @@ -6412,12 +6543,14 @@ var Super = (function (exports) { | |
| 6412 6543 | 
             
              }(Controller);
         | 
| 6413 6544 |  | 
| 6414 6545 | 
             
              var StimulusApplication = Application.start();
         | 
| 6415 | 
            -
              StimulusApplication.register("apply-template", _default$ | 
| 6416 | 
            -
              StimulusApplication.register("clean-filter-param", _default$ | 
| 6417 | 
            -
              StimulusApplication.register("clean-filter-params", _default$ | 
| 6418 | 
            -
              StimulusApplication.register("click-outside-to-close", _default$ | 
| 6419 | 
            -
              StimulusApplication.register("delete", _default$ | 
| 6420 | 
            -
              StimulusApplication.register("flatpickr", _default$ | 
| 6546 | 
            +
              StimulusApplication.register("apply-template", _default$8);
         | 
| 6547 | 
            +
              StimulusApplication.register("clean-filter-param", _default$7);
         | 
| 6548 | 
            +
              StimulusApplication.register("clean-filter-params", _default$6);
         | 
| 6549 | 
            +
              StimulusApplication.register("click-outside-to-close", _default$5);
         | 
| 6550 | 
            +
              StimulusApplication.register("delete", _default$4);
         | 
| 6551 | 
            +
              StimulusApplication.register("flatpickr", _default$3);
         | 
| 6552 | 
            +
              StimulusApplication.register("tab-container", _default$2);
         | 
| 6553 | 
            +
              StimulusApplication.register("tab", _default$1);
         | 
| 6421 6554 | 
             
              StimulusApplication.register("toggle-pending-destruction", _default);
         | 
| 6422 6555 |  | 
| 6423 6556 | 
             
              exports.StimulusApplication = StimulusApplication;
         | 
    
        data/lib/super.rb
    CHANGED
    
    | @@ -25,6 +25,7 @@ require "super/filter/operator" | |
| 25 25 | 
             
            require "super/filter/schema_types"
         | 
| 26 26 | 
             
            require "super/form"
         | 
| 27 27 | 
             
            require "super/form/builder"
         | 
| 28 | 
            +
            require "super/form/field_transcript"
         | 
| 28 29 | 
             
            require "super/form/guesser"
         | 
| 29 30 | 
             
            require "super/form/inline_errors"
         | 
| 30 31 | 
             
            require "super/form/schema_types"
         | 
    
        data/lib/super/error.rb
    CHANGED
    
    
    
        data/lib/super/filter.rb
    CHANGED
    
    
| @@ -3,58 +3,95 @@ | |
| 3 3 | 
             
            module Super
         | 
| 4 4 | 
             
              class Filter
         | 
| 5 5 | 
             
                class FormObject
         | 
| 6 | 
            -
                  class  | 
| 7 | 
            -
                    def initialize( | 
| 8 | 
            -
                      @ | 
| 6 | 
            +
                  class AttributeForm
         | 
| 7 | 
            +
                    def initialize(model:, field_name:, operators:, params:)
         | 
| 8 | 
            +
                      @model = model
         | 
| 9 9 | 
             
                      @field_name = field_name
         | 
| 10 | 
            -
                      @ | 
| 11 | 
            -
                      @params = params
         | 
| 10 | 
            +
                      @operators = operators
         | 
| 11 | 
            +
                      @params = params || {}
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    attr_reader :model
         | 
| 15 | 
            +
                    attr_reader :field_name
         | 
| 16 | 
            +
                    attr_reader :operators
         | 
| 17 | 
            +
                    attr_reader :params
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    def each_operator
         | 
| 20 | 
            +
                      return enum_for(:each_operator) if !block_given?
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                      @operators.each do |operator|
         | 
| 23 | 
            +
                        operator_form = OperatorForm.new(
         | 
| 24 | 
            +
                          operator: operator,
         | 
| 25 | 
            +
                          params: @params[operator.identifier]
         | 
| 26 | 
            +
                        )
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                        yield(operator_form)
         | 
| 29 | 
            +
                      end
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    def humanized_attribute_name
         | 
| 33 | 
            +
                      @model.human_attribute_name(@field_name)
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  class OperatorForm
         | 
| 38 | 
            +
                    NULLARY = :_apply
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    def initialize(operator:, params:)
         | 
| 41 | 
            +
                      @operator = operator
         | 
| 42 | 
            +
                      @params = params || {}
         | 
| 43 | 
            +
                      query_parameter_keys = operator.query_parameter_keys
         | 
| 44 | 
            +
                      query_parameter_keys = [NULLARY] if query_parameter_keys.empty?
         | 
| 12 45 | 
             
                      @specified_values =
         | 
| 13 | 
            -
                         | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
                              query_field_name,
         | 
| 17 | 
            -
                              (params || {})[query_field_name],
         | 
| 18 | 
            -
                            ]
         | 
| 19 | 
            -
                          end
         | 
| 20 | 
            -
                          .to_h
         | 
| 46 | 
            +
                        query_parameter_keys
         | 
| 47 | 
            +
                        .map { |key| [key, @params[key].presence&.strip] }
         | 
| 48 | 
            +
                        .to_h
         | 
| 21 49 |  | 
| 22 50 | 
             
                      @specified_values.each do |key, value|
         | 
| 23 51 | 
             
                        define_singleton_method(key) { value }
         | 
| 24 52 | 
             
                      end
         | 
| 25 53 | 
             
                    end
         | 
| 26 54 |  | 
| 27 | 
            -
                     | 
| 28 | 
            -
             | 
| 29 | 
            -
                     | 
| 55 | 
            +
                    def specified?
         | 
| 56 | 
            +
                      @specified_values.any? { |_key, value| value }
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    attr_reader :operator
         | 
| 30 60 | 
             
                    attr_reader :specified_values
         | 
| 31 61 |  | 
| 32 | 
            -
                    def  | 
| 33 | 
            -
                       | 
| 62 | 
            +
                    def identifier
         | 
| 63 | 
            +
                      @operator.identifier
         | 
| 34 64 | 
             
                    end
         | 
| 35 65 |  | 
| 36 | 
            -
                    def  | 
| 37 | 
            -
                       | 
| 38 | 
            -
                        .map { |o| [o.name, o.identifier] }
         | 
| 39 | 
            -
                        .to_h
         | 
| 40 | 
            -
                    end
         | 
| 66 | 
            +
                    def each_field
         | 
| 67 | 
            +
                      return enum_for(:each_field) if !block_given?
         | 
| 41 68 |  | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 69 | 
            +
                      @specified_values.each do |key, _value|
         | 
| 70 | 
            +
                        yield(key)
         | 
| 71 | 
            +
                      end
         | 
| 44 72 | 
             
                    end
         | 
| 45 73 | 
             
                  end
         | 
| 46 74 |  | 
| 47 75 | 
             
                  def initialize(model:, params:, schema:)
         | 
| 48 76 | 
             
                    @model = model
         | 
| 49 | 
            -
                    @params = params
         | 
| 77 | 
            +
                    @params = params || {}
         | 
| 50 78 | 
             
                    @schema = schema
         | 
| 51 79 |  | 
| 52 80 | 
             
                    @form_fields = {}
         | 
| 53 81 | 
             
                  end
         | 
| 54 82 |  | 
| 55 | 
            -
                  def  | 
| 56 | 
            -
                     | 
| 57 | 
            -
             | 
| 83 | 
            +
                  def each_attribute
         | 
| 84 | 
            +
                    return enum_for(:each_attribute) if !block_given?
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                    @schema.fields.each do |field_name, field_operators|
         | 
| 87 | 
            +
                      attribute_form = AttributeForm.new(
         | 
| 88 | 
            +
                        model: @model,
         | 
| 89 | 
            +
                        field_name: field_name,
         | 
| 90 | 
            +
                        operators: field_operators,
         | 
| 91 | 
            +
                        params: @params[field_name]
         | 
| 92 | 
            +
                      )
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                      yield(attribute_form)
         | 
| 58 95 | 
             
                    end
         | 
| 59 96 | 
             
                  end
         | 
| 60 97 |  | 
| @@ -63,32 +100,21 @@ module Super | |
| 63 100 | 
             
                  end
         | 
| 64 101 |  | 
| 65 102 | 
             
                  def apply_changes(relation)
         | 
| 66 | 
            -
                     | 
| 67 | 
            -
                       | 
| 68 | 
            -
             | 
| 103 | 
            +
                    each_attribute do |attribute_form|
         | 
| 104 | 
            +
                      attribute_form.each_operator do |operator_form|
         | 
| 105 | 
            +
                        next if operator_form.specified_values.values.map(&:to_s).map(&:presence).none?
         | 
| 69 106 |  | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 107 | 
            +
                        operator_behavior = operator_form.operator.behavior
         | 
| 108 | 
            +
                        updated_relation = operator_behavior.call(relation, attribute_form.field_name, **operator_form.specified_values)
         | 
| 72 109 |  | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 110 | 
            +
                        if updated_relation.is_a?(ActiveRecord::Relation)
         | 
| 111 | 
            +
                          relation = updated_relation
         | 
| 112 | 
            +
                        end
         | 
| 75 113 | 
             
                      end
         | 
| 76 114 | 
             
                    end
         | 
| 77 115 |  | 
| 78 116 | 
             
                    relation
         | 
| 79 117 | 
             
                  end
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                  private
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                  def form_field_for(field_name)
         | 
| 84 | 
            -
                    @form_fields[field_name] ||=
         | 
| 85 | 
            -
                      FilterFormField.new(
         | 
| 86 | 
            -
                        humanized_field_name: @model.human_attribute_name(field_name),
         | 
| 87 | 
            -
                        field_name: field_name,
         | 
| 88 | 
            -
                        type: @schema.fields[field_name],
         | 
| 89 | 
            -
                        params: (@params || {})[field_name]
         | 
| 90 | 
            -
                      )
         | 
| 91 | 
            -
                  end
         | 
| 92 118 | 
             
                end
         | 
| 93 119 | 
             
              end
         | 
| 94 120 | 
             
            end
         | 
    
        data/lib/super/filter/guesser.rb
    CHANGED
    
    
| @@ -2,100 +2,126 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module Super
         | 
| 4 4 | 
             
              class Filter
         | 
| 5 | 
            -
                 | 
| 6 | 
            -
                  class Definition
         | 
| 7 | 
            -
                    def initialize(identifier, name, filter)
         | 
| 8 | 
            -
                      @identifier = identifier
         | 
| 9 | 
            -
                      @name = name
         | 
| 10 | 
            -
                      @filter = filter
         | 
| 11 | 
            -
                    end
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                    attr_reader :identifier
         | 
| 14 | 
            -
                    attr_reader :name
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                    def filter(*args)
         | 
| 17 | 
            -
                      @filter.call(args)
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
                  end
         | 
| 20 | 
            -
             | 
| 5 | 
            +
                class Operator
         | 
| 21 6 | 
             
                  class << self
         | 
| 22 7 | 
             
                    def registry
         | 
| 23 8 | 
             
                      @registry ||= {}
         | 
| 24 9 | 
             
                    end
         | 
| 25 10 |  | 
| 26 | 
            -
                    def  | 
| 27 | 
            -
                       | 
| 28 | 
            -
                        registry["between"],
         | 
| 29 | 
            -
                      ]
         | 
| 11 | 
            +
                    def [](key)
         | 
| 12 | 
            +
                      registry.fetch(key.to_s)
         | 
| 30 13 | 
             
                    end
         | 
| 31 14 |  | 
| 32 | 
            -
                    def  | 
| 33 | 
            -
                       | 
| 34 | 
            -
             | 
| 35 | 
            -
                         | 
| 36 | 
            -
                       | 
| 15 | 
            +
                    def register(identifier, operator)
         | 
| 16 | 
            +
                      identifier = identifier.to_s
         | 
| 17 | 
            +
                      if registry.key?(identifier)
         | 
| 18 | 
            +
                        raise Error::AlreadyRegistered, "Already registered: #{identifier}"
         | 
| 19 | 
            +
                      end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                      registry[identifier] = operator
         | 
| 37 22 | 
             
                    end
         | 
| 38 23 |  | 
| 39 | 
            -
                    def  | 
| 40 | 
            -
                       | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
                        registry["contain"],
         | 
| 44 | 
            -
                        registry["ncontain"],
         | 
| 45 | 
            -
                        registry["start"],
         | 
| 46 | 
            -
                        registry["end"],
         | 
| 47 | 
            -
                      ]
         | 
| 24 | 
            +
                    def define(identifier, display, &block)
         | 
| 25 | 
            +
                      operator = new(identifier, display, &block).freeze
         | 
| 26 | 
            +
                      register(identifier, operator)
         | 
| 27 | 
            +
                      operator
         | 
| 48 28 | 
             
                    end
         | 
| 29 | 
            +
                  end
         | 
| 49 30 |  | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 31 | 
            +
                  def initialize(identifier, display, &behavior)
         | 
| 32 | 
            +
                    @identifier = identifier.to_s
         | 
| 33 | 
            +
                    @humanized_operator_name = display
         | 
| 34 | 
            +
                    self.behavior = behavior
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def behavior=(behavior)
         | 
| 38 | 
            +
                    behavior_params = behavior.parameters
         | 
| 39 | 
            +
                    if behavior_params.size < 2
         | 
| 40 | 
            +
                      raise Error::ArgumentError, "Operator behavior must include `column_name` and `relation`"
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                    if behavior_params[0][0] != :req && behavior_params[0][0] != :opt
         | 
| 43 | 
            +
                      raise Error::ArgumentError, "First argument `relation` must be a required, positional argument"
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                    if behavior_params[1][0] != :req && behavior_params[1][0] != :opt
         | 
| 46 | 
            +
                      raise Error::ArgumentError, "Second argument `column_name` must be a required, positional argument"
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
                    if !behavior_params[2..-1].all? { |(type, _name)| type == :keyreq }
         | 
| 49 | 
            +
                      raise Error::ArgumentError, "All query parameter keys must be required, keyword arguments"
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
                    @behavior = behavior
         | 
| 52 | 
            +
                    @query_parameter_keys = behavior_params[2..-1].map(&:last)
         | 
| 53 | 
            +
                  end
         | 
| 53 54 |  | 
| 54 | 
            -
             | 
| 55 | 
            +
                  attr_reader :identifier
         | 
| 56 | 
            +
                  attr_reader :query_parameter_keys
         | 
| 57 | 
            +
                  attr_reader :humanized_operator_name
         | 
| 55 58 |  | 
| 56 | 
            -
             | 
| 59 | 
            +
                  def behavior(&block)
         | 
| 60 | 
            +
                    self.behavior = block if block_given?
         | 
| 61 | 
            +
                    @behavior
         | 
| 62 | 
            +
                  end
         | 
| 57 63 |  | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
                      end
         | 
| 61 | 
            -
                    end
         | 
| 64 | 
            +
                  define("eq", "Equals") do |relation, field, q:|
         | 
| 65 | 
            +
                    relation.where(field => q)
         | 
| 62 66 | 
             
                  end
         | 
| 63 67 |  | 
| 64 | 
            -
                  define(" | 
| 65 | 
            -
                    relation.where(field =>  | 
| 68 | 
            +
                  define("neq", "Doesn't equal") do |relation, field, q:|
         | 
| 69 | 
            +
                    relation.where.not(field => q)
         | 
| 66 70 | 
             
                  end
         | 
| 67 71 |  | 
| 68 | 
            -
                  define(" | 
| 69 | 
            -
                    relation.where | 
| 72 | 
            +
                  define("null", "Is NULL") do |relation, field|
         | 
| 73 | 
            +
                    relation.where(field => nil)
         | 
| 70 74 | 
             
                  end
         | 
| 71 75 |  | 
| 72 | 
            -
                  define(" | 
| 73 | 
            -
                     | 
| 74 | 
            -
                    relation.where("#{field} LIKE ?", "%#{query}%")
         | 
| 76 | 
            +
                  define("nnull", "Isn't NULL") do |relation, field|
         | 
| 77 | 
            +
                    relation.where.not(field => nil)
         | 
| 75 78 | 
             
                  end
         | 
| 76 79 |  | 
| 77 | 
            -
                  define(" | 
| 78 | 
            -
                     | 
| 79 | 
            -
             | 
| 80 | 
            +
                  define("true", "Is true") do |relation, field|
         | 
| 81 | 
            +
                    relation.where(field => true)
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  define("false", "Is false") do |relation, field|
         | 
| 85 | 
            +
                    relation.where(field => false)
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  define("empty", "Is empty") do |relation, field|
         | 
| 89 | 
            +
                    relation.where(field => "")
         | 
| 80 90 | 
             
                  end
         | 
| 81 91 |  | 
| 82 | 
            -
                  define(" | 
| 83 | 
            -
                     | 
| 84 | 
            -
                    relation.where("#{field} LIKE ?", query)
         | 
| 92 | 
            +
                  define("nempty", "Isn't empty") do |relation, field|
         | 
| 93 | 
            +
                    relation.where.not(field => "")
         | 
| 85 94 | 
             
                  end
         | 
| 86 95 |  | 
| 87 | 
            -
                  define(" | 
| 88 | 
            -
                     | 
| 89 | 
            -
             | 
| 96 | 
            +
                  define("blank", "Is blank") do |relation, field|
         | 
| 97 | 
            +
                    relation.where(field => [nil, ""])
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  define("nblank", "Isn't blank") do |relation, field|
         | 
| 101 | 
            +
                    relation.where.not(field => [nil, ""])
         | 
| 102 | 
            +
                  end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  define("contain", "Contains") do |relation, field, q:|
         | 
| 105 | 
            +
                    query = "%#{Compatability.sanitize_sql_like(q)}%"
         | 
| 106 | 
            +
                    if relation.connection.adapter_name == "PostgreSQL"
         | 
| 107 | 
            +
                      relation.where("#{field} ILIKE ?", query)
         | 
| 108 | 
            +
                    else
         | 
| 109 | 
            +
                      relation.where("#{field} LIKE ?", query)
         | 
| 110 | 
            +
                    end
         | 
| 111 | 
            +
                  end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  define("ncontain", "Doesn't contain") do |relation, field, q:|
         | 
| 114 | 
            +
                    query = "%#{Compatability.sanitize_sql_like(q)}%"
         | 
| 115 | 
            +
                    relation.where("#{field} NOT LIKE ?", query)
         | 
| 90 116 | 
             
                  end
         | 
| 91 117 |  | 
| 92 | 
            -
                  define("between", " | 
| 93 | 
            -
                    if  | 
| 94 | 
            -
                      relation = relation.where("#{field} >= ?",  | 
| 118 | 
            +
                  define("between", "Between") do |relation, field, q0:, q1:|
         | 
| 119 | 
            +
                    if q0.present?
         | 
| 120 | 
            +
                      relation = relation.where("#{field} >= ?", q0)
         | 
| 95 121 | 
             
                    end
         | 
| 96 122 |  | 
| 97 | 
            -
                    if  | 
| 98 | 
            -
                      relation = relation.where("#{field} <= ?",  | 
| 123 | 
            +
                    if q1.present?
         | 
| 124 | 
            +
                      relation = relation.where("#{field} <= ?", q1)
         | 
| 99 125 | 
             
                    end
         | 
| 100 126 |  | 
| 101 127 | 
             
                    relation
         |