like_query 0.0.6 → 0.0.8
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/README.md +160 -48
- data/lib/like_query/collect.rb +146 -93
- data/lib/like_query/model_extensions.rb +24 -21
- data/lib/like_query/version.rb +1 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c46b541528f87a7bd078c47eaa7bc264503ff6b1c333af0caf18aacb2beea24c
         | 
| 4 | 
            +
              data.tar.gz: 8d5d867c0707f5cfe827a4d55082434d5e02bec45528f04737a8927746388fcd
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: aaf145febd6f66ee1549dd8d2d5b5285d1c191f6e5759519ec5053eb88a6055c087411ab3d4962afb282d3c208f439f9a7fad5f852797a3466e93c22238f6aba
         | 
| 7 | 
            +
              data.tar.gz: 7097e44705ad35add8233002e3db0e0b20330525197a3dcc4d15070e43d38f03221c3f2e9902e8677ee6e273e68e6eaf4490d6bc825ce82fdce2722d0301dd2d
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,10 +1,13 @@ | |
| 1 1 | 
             
            # like_query
         | 
| 2 2 |  | 
| 3 | 
            -
            For my  | 
| 3 | 
            +
            For my clients' newly built applications with Turbo, search queries mostly serve two purposes:
         | 
| 4 4 |  | 
| 5 | 
            -
            Index view callable by a url like `/customers?find=müller screw`  | 
| 5 | 
            +
            - Index view callable by a url like `/customers?find=müller screw` 
         | 
| 6 | 
            +
            - javascript component / dropdown on the front, in our case built with svelte, which receives a json and renders a table in a dropdown.
         | 
| 6 7 |  | 
| 7 | 
            -
            This query generator is built for  | 
| 8 | 
            +
            This query generator is built for these two purposes
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            Modules like one of the svelte components mentioned above have a total response time (from pressing a key until the result is rendered) of about 60 msec, while with turbo the same time is mostly around 140-160 msec. The gem itself, from querying the database to producing a hash, has a time of about 3 msec. These results are for small data sets (e.g. 30 records found).
         | 
| 8 11 |  | 
| 9 12 | 
             
            ## Installation
         | 
| 10 13 |  | 
| @@ -14,18 +17,28 @@ add | |
| 14 17 |  | 
| 15 18 | 
             
            to Gemfile
         | 
| 16 19 |  | 
| 17 | 
            -
            this adds the methods `#like` and `# | 
| 20 | 
            +
            this adds the methods `#like` and `#generate_hash` to all models.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            **Config**
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            You can set a default limit by
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            ```ruby
         | 
| 27 | 
            +
              config.x.like_query.limit = 20
         | 
| 28 | 
            +
            ```
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            This can be overriden by calling the methods
         | 
| 18 31 |  | 
| 19 32 | 
             
            ## Usage
         | 
| 20 33 |  | 
| 21 | 
            -
             | 
| 34 | 
            +
            **#like**
         | 
| 22 35 |  | 
| 23 36 | 
             
            ```ruby
         | 
| 24 37 | 
             
            customer = Customer.create(name: 'Ambühl')
         | 
| 25 | 
            -
             | 
| 38 | 
            +
            Article.create(name: 'first', number: '01', customer: customer)
         | 
| 26 39 |  | 
| 27 40 | 
             
            Article.like('fir', :name, :number)
         | 
| 28 | 
            -
            # =>  | 
| 41 | 
            +
            # => <Article:0x00000001067107a8 id: ...>
         | 
| 29 42 | 
             
            # => searches by: "where name like '%fir%' or number like '%fir%'"
         | 
| 30 43 | 
             
            # => queries are built with Article.arel_table[:name].matches('%fir%')
         | 
| 31 44 |  | 
| @@ -35,75 +48,174 @@ Article.like(['fir', 'ambühl'], :name, :number, customer: :name) | |
| 35 48 | 
             
            # => would also find art1
         | 
| 36 49 | 
             
            ```
         | 
| 37 50 |  | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
            returns a hash that can easily be transformed by `#to_json` for a javascript-frontend, by example
         | 
| 51 | 
            +
            **#generate_hash**
         | 
| 41 52 |  | 
| 42 | 
            -
            can  | 
| 53 | 
            +
            returns a hash that can easily be transformed by `#to_json` for a javascript frontend, for example
         | 
| 43 54 |  | 
| 44 55 | 
             
            ```ruby
         | 
| 45 56 | 
             
            customer = Customer.create(name: 'Ambühl')
         | 
| 46 57 | 
             
            art1 = Article.create(name: 'first', number: '01', customer: customer)
         | 
| 47 58 |  | 
| 48 | 
            -
            Article.like('fir', :name). | 
| 59 | 
            +
            Article.like('fir', :name).generate_hash(limit: 10)
         | 
| 49 60 | 
             
            # returns: 
         | 
| 50 | 
            -
            { | 
| 51 | 
            -
              : | 
| 52 | 
            -
                 | 
| 53 | 
            -
                   | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 61 | 
            +
            {
         | 
| 62 | 
            +
              data: 
         | 
| 63 | 
            +
                [
         | 
| 64 | 
            +
                  {
         | 
| 65 | 
            +
                    values: ["Müller"], 
         | 
| 66 | 
            +
                    attributes: {"customer.name": "Müller"}, 
         | 
| 67 | 
            +
                    id: 1, 
         | 
| 68 | 
            +
                    model: "Article"
         | 
| 69 | 
            +
                  }, 
         | 
| 70 | 
            +
                  ...
         | 
| 71 | 
            +
                ], 
         | 
| 72 | 
            +
              length: 4, 
         | 
| 73 | 
            +
              overflow: true, 
         | 
| 74 | 
            +
              columns_count: 2, 
         | 
| 75 | 
            +
              sub_records_columns_count: 0, 
         | 
| 76 | 
            +
              image: false, 
         | 
| 77 | 
            +
              time: 18.282996
         | 
| 59 78 | 
             
            }
         | 
| 60 79 |  | 
| 61 | 
            -
            Article.like('fir', :name). | 
| 80 | 
            +
            Article.like('fir', :name).generate_hash(:number, limit: 10)
         | 
| 62 81 | 
             
            # would query like the above example: Search scope is only :name
         | 
| 63 82 | 
             
            # but would return article-number instead of article-name inside the data block
         | 
| 64 83 | 
             
            ```
         | 
| 65 84 |  | 
| 66 | 
            -
            `# | 
| 85 | 
            +
            `#generate_hash` uses `LikeQuery::Collect`, functionality is the same.
         | 
| 67 86 |  | 
| 68 | 
            -
            **Class LikeQuery::Collect** | 
| 87 | 
            +
            **Class LikeQuery::Collect**
         | 
| 69 88 |  | 
| 70 89 | 
             
            ```ruby
         | 
| 71 | 
            -
            cust = Customer.create(name: ' | 
| 72 | 
            -
             | 
| 90 | 
            +
            cust = Customer.create(name: 'cust')
         | 
| 91 | 
            +
            Article.create(name: 'screw', customer: cust)
         | 
| 73 92 |  | 
| 74 93 | 
             
            c = LikeQuery::Collect.new(4)
         | 
| 75 94 | 
             
            # => 4 is the limit
         | 
| 76 95 |  | 
| 77 | 
            -
            c. | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
            c.receive { Customer.like('any-art', :name, image: :image_column, articles: :name) }
         | 
| 81 | 
            -
            # => limit is already exhausted: does nothing
         | 
| 82 | 
            -
            # => otherwise it would add Customers to the result hash
         | 
| 83 | 
            -
             | 
| 96 | 
            +
            c.set_schema(Customer, :name)
         | 
| 97 | 
            +
            c.collect(parent: :customer) { Article.like('screw', :name) }
         | 
| 98 | 
            +
            c.generate_json
         | 
| 84 99 | 
             
            c.result
         | 
| 85 | 
            -
             | 
| 100 | 
            +
             | 
| 101 | 
            +
            # => 
         | 
| 86 102 | 
             
            {
         | 
| 87 | 
            -
              : | 
| 88 | 
            -
                { | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 103 | 
            +
              "data": [
         | 
| 104 | 
            +
                {
         | 
| 105 | 
            +
                  "values": [
         | 
| 106 | 
            +
                    "cust"
         | 
| 107 | 
            +
                  ],
         | 
| 108 | 
            +
                  "attributes": {
         | 
| 109 | 
            +
                    "name": "cust"
         | 
| 110 | 
            +
                  },
         | 
| 111 | 
            +
                  "id": 1,
         | 
| 112 | 
            +
                  "model": "Customer",
         | 
| 113 | 
            +
                  "children": [
         | 
| 114 | 
            +
                    {
         | 
| 115 | 
            +
                      "values": [
         | 
| 116 | 
            +
                        "screw"
         | 
| 117 | 
            +
                      ],
         | 
| 118 | 
            +
                      "attributes": {
         | 
| 119 | 
            +
                        "name": "screw"
         | 
| 120 | 
            +
                      },
         | 
| 121 | 
            +
                      "id": 1,
         | 
| 122 | 
            +
                      "model": "Customer.Article",
         | 
| 123 | 
            +
                      "parent_id": 1,
         | 
| 124 | 
            +
                    }
         | 
| 125 | 
            +
                  ]
         | 
| 95 126 | 
             
                }
         | 
| 96 | 
            -
              ], | 
| 97 | 
            -
              : | 
| 98 | 
            -
              : | 
| 99 | 
            -
              : | 
| 100 | 
            -
              : | 
| 127 | 
            +
              ],
         | 
| 128 | 
            +
              "length": 2,
         | 
| 129 | 
            +
              "overflow": false,
         | 
| 130 | 
            +
              "columns_count": 1,
         | 
| 131 | 
            +
              "sub_records_columns_count": 0,
         | 
| 132 | 
            +
              "image": false,
         | 
| 133 | 
            +
              "time": 0.0075
         | 
| 134 | 
            +
            }
         | 
| 135 | 
            +
            ```
         | 
| 136 | 
            +
             | 
| 137 | 
            +
            **query schema and result_schema**
         | 
| 138 | 
            +
             | 
| 139 | 
            +
            The resulting hash for a record looks like this:
         | 
| 140 | 
            +
             | 
| 141 | 
            +
            ```ruby
         | 
| 142 | 
            +
            {
         | 
| 143 | 
            +
              :values => ["abc", "123"],
         | 
| 144 | 
            +
              :id => 456,
         | 
| 145 | 
            +
              :model => "article",
         | 
| 146 | 
            +
              :image => "src:img..."
         | 
| 147 | 
            +
            }
         | 
| 148 | 
            +
            ```
         | 
| 149 | 
            +
             | 
| 150 | 
            +
            The resulting hash or json is built from the schema, which can look like this:
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            ```ruby
         | 
| 153 | 
            +
            :number
         | 
| 154 | 
            +
            ```
         | 
| 155 | 
            +
             | 
| 156 | 
            +
            or
         | 
| 157 | 
            +
             | 
| 158 | 
            +
            ```ruby
         | 
| 159 | 
            +
            [:number, :name]
         | 
| 160 | 
            +
            ```
         | 
| 161 | 
            +
             | 
| 162 | 
            +
            or
         | 
| 163 | 
            +
             | 
| 164 | 
            +
            ```ruby
         | 
| 165 | 
            +
            {
         | 
| 166 | 
            +
              values: [:number, :name],
         | 
| 167 | 
            +
              image: :name_of_a_column_or_method
         | 
| 101 168 | 
             
            }
         | 
| 102 169 | 
             
            ```
         | 
| 103 170 |  | 
| 171 | 
            +
            There is a query schema and an output schema.
         | 
| 172 | 
            +
            If no output schema is defined, the query schema is used for both.
         | 
| 173 | 
            +
             | 
| 174 | 
            +
            ```ruby
         | 
| 175 | 
            +
            Article.like('first', :name).generate_hash
         | 
| 176 | 
            +
            # => :values => ["first"]
         | 
| 177 | 
            +
            ```
         | 
| 178 | 
            +
             | 
| 179 | 
            +
            If an output schema is specified, the result may differ from the search scope:
         | 
| 180 | 
            +
             | 
| 181 | 
            +
            ```ruby
         | 
| 182 | 
            +
            Article.like('first', :name).generate_hash(:number, :name)
         | 
| 183 | 
            +
            # => :values => ["012", "first"]
         | 
| 184 | 
            +
            ```
         | 
| 185 | 
            +
             | 
| 186 | 
            +
            The collect class remembers the schema for a model:
         | 
| 187 | 
            +
             | 
| 188 | 
            +
            ```ruby
         | 
| 189 | 
            +
            c = LikeQuery::Collect.new
         | 
| 190 | 
            +
            c.collect([:name]) { Article.like('x') }
         | 
| 191 | 
            +
            c.collect { Article.like('x') } #=> schema [:name] is used
         | 
| 192 | 
            +
            c.collect { Article.like('x', :number) } # => schema [:number] is used
         | 
| 193 | 
            +
            ```
         | 
| 194 | 
            +
             | 
| 195 | 
            +
            **#set_schema**
         | 
| 196 | 
            +
             | 
| 197 | 
            +
            When a child returns its parent, the schema for the parent must be given.
         | 
| 198 | 
            +
            Otherwise `#generate_hash` would not know what values to return.
         | 
| 199 | 
            +
             | 
| 200 | 
            +
            ```ruby
         | 
| 201 | 
            +
                c = LikeQuery::Collect.new
         | 
| 202 | 
            +
                c.set_schema(Customer, :name)
         | 
| 203 | 
            +
                # => now the customer will be returned with { values: [<name>] }
         | 
| 204 | 
            +
                c.collect(parent: :customer) { Article.like('screw', :name) }
         | 
| 205 | 
            +
                # => this will add the customer (unless it exists in the list) and add the Article as a child to the customer
         | 
| 206 | 
            +
                r = c.generate_hash
         | 
| 207 | 
            +
            ```
         | 
| 208 | 
            +
             | 
| 209 | 
            +
            **Performance**
         | 
| 210 | 
            +
             | 
| 211 | 
            +
            Values defined by the schema are processed by the `#send` method, but recursively.
         | 
| 212 | 
            +
            This means, for example, that for an `article` with the given key `customer.employees.contact_details.email` in the schema would return the name of the associated customer.
         | 
| 213 | 
            +
             | 
| 214 | 
            +
            ATTENTION: This can trigger a lot of database queries, depending on your structure or if or which method is behind the called names.
         | 
| 215 | 
            +
             | 
| 104 216 | 
             
            ## Tests
         | 
| 105 217 |  | 
| 106 | 
            -
            Tests for this gem, by rspec, are included  | 
| 218 | 
            +
            Tests for this gem, by rspec, are not included in this gem, they can be found in [test project](https://gitlab.com/sedl/like_query_project)
         | 
| 107 219 |  | 
| 108 220 | 
             
            - [ ] [Set up project integrations](https://gitlab.com/sedl/like_query/-/settings/integrations)
         | 
| 109 221 |  | 
    
        data/lib/like_query/collect.rb
    CHANGED
    
    | @@ -1,116 +1,86 @@ | |
| 1 1 | 
             
            module LikeQuery
         | 
| 2 2 | 
             
              class Collect
         | 
| 3 | 
            -
                def initialize(limit =  | 
| 4 | 
            -
                   | 
| 3 | 
            +
                def initialize(limit = nil)
         | 
| 4 | 
            +
                  if limit
         | 
| 5 | 
            +
                    @limit = limit
         | 
| 6 | 
            +
                  elsif Rails.configuration.x.like_query.limit
         | 
| 7 | 
            +
                    @limit = Rails.configuration.x.like_query.limit
         | 
| 8 | 
            +
                  else
         | 
| 9 | 
            +
                    @limit = nil
         | 
| 10 | 
            +
                  end
         | 
| 5 11 | 
             
                  @length = 0
         | 
| 6 | 
            -
                  @data =  | 
| 12 | 
            +
                  @data = {}
         | 
| 7 13 | 
             
                  @overflow = false
         | 
| 8 14 | 
             
                  @columns_count = 0
         | 
| 9 15 | 
             
                  @sub_records_columns_count = 0
         | 
| 10 16 | 
             
                  @image = false
         | 
| 11 | 
            -
                   | 
| 17 | 
            +
                  #@sub_records_image = false
         | 
| 18 | 
            +
                  @start_time = Time.now
         | 
| 19 | 
            +
                  @schemes = {}
         | 
| 20 | 
            +
                  @images = {}
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def set_schema(model, schema)
         | 
| 24 | 
            +
                  @schemes[model.to_s] = schema_to_hash(schema)
         | 
| 12 25 | 
             
                end
         | 
| 13 26 |  | 
| 14 | 
            -
                def  | 
| 27 | 
            +
                def collect(output_schema = nil, limit: nil, parent: nil, image: nil, &block)
         | 
| 15 28 |  | 
| 16 | 
            -
                   | 
| 29 | 
            +
                  _limit = (limit ? (@limit && @limit < limit ? @limit : limit) : @limit)
         | 
| 30 | 
            +
                  return false if @length >= _limit
         | 
| 17 31 | 
             
                  length = 0
         | 
| 18 | 
            -
                  @image = image.present?
         | 
| 19 32 |  | 
| 20 | 
            -
                  recs = yield
         | 
| 33 | 
            +
                  recs = yield.includes(parent).limit(_limit)
         | 
| 21 34 |  | 
| 22 | 
            -
                   | 
| 23 | 
            -
                  if  | 
| 24 | 
            -
                     | 
| 25 | 
            -
             | 
| 26 | 
            -
                   | 
| 27 | 
            -
             | 
| 35 | 
            +
                  scm = (output_schema.present? ? output_schema : recs.like_query_schema)
         | 
| 36 | 
            +
                  if scm.present?
         | 
| 37 | 
            +
                    @schemes[recs.klass.to_s] = schema_to_hash(scm)
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                  model_name = recs.klass.to_s
         | 
| 40 | 
            +
                  schema = @schemes[model_name] || schema_to_hash(nil)
         | 
| 41 | 
            +
                  _img = image || schema[:image]
         | 
| 42 | 
            +
                  if _img.present?
         | 
| 43 | 
            +
                    @images[model_name] = _img
         | 
| 44 | 
            +
                    @image = true
         | 
| 28 45 | 
             
                  end
         | 
| 29 46 |  | 
| 30 | 
            -
                   | 
| 31 | 
            -
             | 
| 32 | 
            -
                    if  | 
| 33 | 
            -
                       | 
| 47 | 
            +
                  if parent
         | 
| 48 | 
            +
                    parent_assoc = recs.klass.reflect_on_association(parent)
         | 
| 49 | 
            +
                    if !parent_assoc
         | 
| 50 | 
            +
                      raise "parent «#{parent}» is not a valid association"
         | 
| 34 51 | 
             
                    end
         | 
| 35 52 | 
             
                  end
         | 
| 36 53 |  | 
| 37 | 
            -
                  recs. | 
| 38 | 
            -
                    rec_attr = {}
         | 
| 39 | 
            -
                    pattern.each do |p|
         | 
| 40 | 
            -
                      if p.is_a?(Hash)
         | 
| 54 | 
            +
                  recs.each do |rec|
         | 
| 41 55 |  | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
                            # raise 'Missing input: image column for given key :image' unless cols.present?
         | 
| 47 | 
            -
                            #
         | 
| 48 | 
            -
                            # # IMAGE COLUMN
         | 
| 49 | 
            -
                            #
         | 
| 50 | 
            -
                            # rec_attr[:image] = get_column_value(r, cols)
         | 
| 51 | 
            -
                            # @image = true
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                          else
         | 
| 56 | 
            +
                    if @length >= _limit
         | 
| 57 | 
            +
                      @overflow = true
         | 
| 58 | 
            +
                      break
         | 
| 59 | 
            +
                    else
         | 
| 54 60 |  | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
                                      [cols]
         | 
| 67 | 
            -
                                    end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                            (sub_records.is_a?(Enumerable) ? sub_records : [sub_records]).each do |sub_record|
         | 
| 70 | 
            -
                              sub_attr = []
         | 
| 71 | 
            -
                              _cols.each do |c|
         | 
| 72 | 
            -
                                sub_attr.push(get_column_value(sub_record, c))
         | 
| 73 | 
            -
                              end
         | 
| 74 | 
            -
             | 
| 75 | 
            -
                              if @length >= @limit || (limit && length >= limit)
         | 
| 76 | 
            -
                                @overflow = true
         | 
| 77 | 
            -
                                break
         | 
| 78 | 
            -
                              else
         | 
| 79 | 
            -
                                c = sub_attr.length
         | 
| 80 | 
            -
                                @sub_records_columns_count = c if c > @sub_records_columns_count
         | 
| 81 | 
            -
                                rec_attr[:associations] ||= {}
         | 
| 82 | 
            -
                                rec_attr[:associations][assoc] ||= []
         | 
| 83 | 
            -
                                sub_hash = { values: sub_attr, id: sub_record.id, model: sub_record.class.to_s.underscore }
         | 
| 84 | 
            -
                                if image_column
         | 
| 85 | 
            -
                                  sub_hash[:image] = get_column_value(sub_record, image_column)
         | 
| 86 | 
            -
                                  @sub_records_image = true
         | 
| 87 | 
            -
                                end
         | 
| 88 | 
            -
                                rec_attr[:associations][assoc].push(sub_hash)
         | 
| 89 | 
            -
                                @length += 1
         | 
| 90 | 
            -
                                length += 1
         | 
| 91 | 
            -
                              end
         | 
| 92 | 
            -
                            end
         | 
| 61 | 
            +
                      if parent
         | 
| 62 | 
            +
                        parent_record = rec.send(parent)
         | 
| 63 | 
            +
                        r = record_to_hash(rec, schema, image, parent_record)
         | 
| 64 | 
            +
                        parent_class_name = parent_record.class.to_s
         | 
| 65 | 
            +
                        parent_key = "#{parent_class_name}#{parent_record.id}"
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                        unless @data[parent_key]
         | 
| 68 | 
            +
                          parent_schema = @schemes[parent_class_name]
         | 
| 69 | 
            +
                          unless parent_schema
         | 
| 70 | 
            +
                            Rails.logger.debug("WARNING: NO SCHEMA GIVEN FOR «#{parent_class_name}»")
         | 
| 71 | 
            +
                            parent_schema = schema_to_hash(nil)
         | 
| 93 72 | 
             
                          end
         | 
| 73 | 
            +
                          @data[parent_key] = record_to_hash(parent_record, parent_schema, @images[parent_class_name])
         | 
| 74 | 
            +
                          @length += 1
         | 
| 94 75 | 
             
                        end
         | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
                         | 
| 100 | 
            -
                        rec_attr[:values].push(get_column_value(r, p))
         | 
| 101 | 
            -
                        rec_attr[:id] = r.id
         | 
| 102 | 
            -
                        rec_attr[:model] = r.class.to_s.underscore
         | 
| 103 | 
            -
                        rec_attr[:image] = r.send(image) if @image
         | 
| 104 | 
            -
             | 
| 76 | 
            +
                        @data[parent_key][:children] ||= []
         | 
| 77 | 
            +
                        @data[parent_key][:children].push(r)
         | 
| 78 | 
            +
                      else
         | 
| 79 | 
            +
                        r = record_to_hash(rec, schema, image)
         | 
| 80 | 
            +
                        @data["#{rec.class}#{rec.id}"] = r
         | 
| 105 81 | 
             
                      end
         | 
| 106 | 
            -
             | 
| 107 | 
            -
                    if @length >= @limit || (limit && length >= limit)
         | 
| 108 | 
            -
                      @overflow = true
         | 
| 109 | 
            -
                      break
         | 
| 110 | 
            -
                    else
         | 
| 111 | 
            -
                      c = (image ? 1 : 0) + rec_attr[:values].length
         | 
| 82 | 
            +
                      c = (@image ? 1 : 0) + r[:values].to_a.length
         | 
| 112 83 | 
             
                      @columns_count = c if c > @columns_count
         | 
| 113 | 
            -
                      @data.push(rec_attr)
         | 
| 114 84 | 
             
                      @length += 1
         | 
| 115 85 | 
             
                      length += 1
         | 
| 116 86 | 
             
                    end
         | 
| @@ -119,23 +89,106 @@ module LikeQuery | |
| 119 89 | 
             
                  true
         | 
| 120 90 | 
             
                end
         | 
| 121 91 |  | 
| 122 | 
            -
                def  | 
| 92 | 
            +
                def generate_hash
         | 
| 93 | 
            +
                  data = @data.map { |_, v| v }
         | 
| 123 94 | 
             
                  {
         | 
| 124 | 
            -
                    data:  | 
| 95 | 
            +
                    data: data,
         | 
| 125 96 | 
             
                    length: @length,
         | 
| 126 97 | 
             
                    overflow: @overflow,
         | 
| 127 98 | 
             
                    columns_count: @columns_count,
         | 
| 128 99 | 
             
                    sub_records_columns_count: @sub_records_columns_count,
         | 
| 129 100 | 
             
                    image: @image,
         | 
| 130 | 
            -
                    sub_records_image: @sub_records_image
         | 
| 101 | 
            +
                    # sub_records_image: @sub_records_image,
         | 
| 102 | 
            +
                    time: Time.now - @start_time
         | 
| 131 103 | 
             
                  }
         | 
| 132 104 | 
             
                end
         | 
| 133 105 |  | 
| 106 | 
            +
                def generate_json
         | 
| 107 | 
            +
                  generate_hash.to_json
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
             | 
| 134 110 | 
             
                private
         | 
| 135 111 |  | 
| 112 | 
            +
                def record_to_hash(record, schema, image, parent = nil)
         | 
| 113 | 
            +
                  r = {}
         | 
| 114 | 
            +
                  schema[:values].each do |k|
         | 
| 115 | 
            +
                    v = get_column_value(record, k)
         | 
| 116 | 
            +
                    r[:values] ||= []
         | 
| 117 | 
            +
                    r[:values].push(v)
         | 
| 118 | 
            +
                    r[:attributes] ||= {}
         | 
| 119 | 
            +
                    r[:attributes][k] = v
         | 
| 120 | 
            +
                  end
         | 
| 121 | 
            +
                  r[:id] = record.id
         | 
| 122 | 
            +
                  if parent
         | 
| 123 | 
            +
                    r[:model] = "#{parent.class.to_s}.#{record.class}"
         | 
| 124 | 
            +
                    r[:parent_id] = parent.id
         | 
| 125 | 
            +
                  else
         | 
| 126 | 
            +
                    r[:model] = record.class.to_s
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
                  r[:image] = record.send(image) if image
         | 
| 129 | 
            +
                  r
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                def schema_to_hash(schema)
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                  if schema.is_a?(Array) && schema.first.is_a?(Array)
         | 
| 135 | 
            +
                    _schema = schema.first
         | 
| 136 | 
            +
                    raise 'invalid schema format' if schema.length >= 2
         | 
| 137 | 
            +
                  else
         | 
| 138 | 
            +
                    _schema = schema
         | 
| 139 | 
            +
                  end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  if _schema.is_a?(String) || _schema.is_a?(Symbol)
         | 
| 142 | 
            +
                    { values: [_schema.to_sym] }
         | 
| 143 | 
            +
                  elsif _schema.is_a?(Array)
         | 
| 144 | 
            +
                    r = {}
         | 
| 145 | 
            +
                    _schema.each do |s|
         | 
| 146 | 
            +
                      if s.is_a?(String) || s.is_a?(Symbol)
         | 
| 147 | 
            +
                        r[:values] ||= []
         | 
| 148 | 
            +
                        r[:values].push(s.to_sym)
         | 
| 149 | 
            +
                      elsif s.is_a?(Hash)
         | 
| 150 | 
            +
                        s.each do |k, v|
         | 
| 151 | 
            +
                          if k.to_sym == :image
         | 
| 152 | 
            +
                            r[:image] = v
         | 
| 153 | 
            +
                          end
         | 
| 154 | 
            +
                        end
         | 
| 155 | 
            +
                      else
         | 
| 156 | 
            +
                        raise "invalid schema format (#{s}) in schema => «#{schema}»"
         | 
| 157 | 
            +
                      end
         | 
| 158 | 
            +
                    end
         | 
| 159 | 
            +
                    r
         | 
| 160 | 
            +
                  elsif _schema.is_a?(Hash)
         | 
| 161 | 
            +
                    _schema
         | 
| 162 | 
            +
                  elsif !schema.present?
         | 
| 163 | 
            +
                    { values: [] }
         | 
| 164 | 
            +
                  else
         | 
| 165 | 
            +
                    raise "invalid schema format => «#{schema}»"
         | 
| 166 | 
            +
                  end
         | 
| 167 | 
            +
                end
         | 
| 168 | 
            +
             | 
| 136 169 | 
             
                def get_column_value(record, column)
         | 
| 137 170 | 
             
                  val = nil
         | 
| 138 | 
            -
                  column. | 
| 171 | 
            +
                  if column.is_a?(Hash)
         | 
| 172 | 
            +
                    r = []
         | 
| 173 | 
            +
                    column.each do |k, v|
         | 
| 174 | 
            +
                      if v.is_a?(Array)
         | 
| 175 | 
            +
                        v.each do |_v|
         | 
| 176 | 
            +
                          if _v.is_a?(String) || _v.is_a?(Symbol)
         | 
| 177 | 
            +
                            r.push(get_column_value(record, "#{k}.#{_v}"))
         | 
| 178 | 
            +
                          else
         | 
| 179 | 
            +
                            raise "Too deeply nested objects: #{v}"
         | 
| 180 | 
            +
                          end
         | 
| 181 | 
            +
                        end
         | 
| 182 | 
            +
                      elsif v.is_a?(String) || v.is_a?(Symbol)
         | 
| 183 | 
            +
                        r.push(get_column_value(record, "#{k}.#{v}"))
         | 
| 184 | 
            +
                      else
         | 
| 185 | 
            +
                        raise "query column value can only be done by string or symbol, but given: #{v}"
         | 
| 186 | 
            +
                      end
         | 
| 187 | 
            +
                    end
         | 
| 188 | 
            +
                    val = r.join(', ')
         | 
| 189 | 
            +
                  else
         | 
| 190 | 
            +
                    column.to_s.split('.').each { |i| val = (val ? val : record).send(i) }
         | 
| 191 | 
            +
                  end
         | 
| 139 192 | 
             
                  (val ? val : '')
         | 
| 140 193 | 
             
                end
         | 
| 141 194 |  | 
| @@ -1,21 +1,21 @@ | |
| 1 1 | 
             
            module LikeQuery
         | 
| 2 2 | 
             
              module ModelExtensions
         | 
| 3 3 |  | 
| 4 | 
            -
                def like(search_string, * | 
| 4 | 
            +
                def like(search_string, *schema)
         | 
| 5 5 |  | 
| 6 6 | 
             
                  raise 'like can only be called from a model' if self == ApplicationRecord
         | 
| 7 7 |  | 
| 8 8 | 
             
                  queries = nil
         | 
| 9 9 | 
             
                  associations = []
         | 
| 10 | 
            -
                  @ | 
| 10 | 
            +
                  @like_query_schema = schema
         | 
| 11 11 |  | 
| 12 12 | 
             
                  (search_string.is_a?(String) ? search_string.split(' ') : search_string).each do |s|
         | 
| 13 13 | 
             
                    str = "%#{s}%"
         | 
| 14 14 | 
             
                    q = nil
         | 
| 15 | 
            -
                    if  | 
| 16 | 
            -
                      raise "only one array can be given: Either  | 
| 15 | 
            +
                    if schema.first.is_a?(Array) && schema.length >= 2
         | 
| 16 | 
            +
                      raise "only one array can be given: Either schema as one array or as multiple args, not as array"
         | 
| 17 17 | 
             
                    end
         | 
| 18 | 
            -
                    ( | 
| 18 | 
            +
                    (schema.first.is_a?(Array) ? schema.first : schema).each do |p|
         | 
| 19 19 | 
             
                      if p.is_a?(Symbol) || p.is_a?(String)
         | 
| 20 20 | 
             
                        _q = arel_table[p].matches(str)
         | 
| 21 21 | 
             
                        q = (q ? q.or(_q) : _q)
         | 
| @@ -42,28 +42,31 @@ module LikeQuery | |
| 42 42 | 
             
                    queries = (queries ? queries.and(q) : q)
         | 
| 43 43 | 
             
                  end
         | 
| 44 44 |  | 
| 45 | 
            -
                   | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 45 | 
            +
                  if associations.present?
         | 
| 46 | 
            +
                    left_outer_joins(associations).where(
         | 
| 47 | 
            +
                      queries
         | 
| 48 | 
            +
                    )
         | 
| 49 | 
            +
                  else
         | 
| 50 | 
            +
                    where(
         | 
| 51 | 
            +
                      queries
         | 
| 52 | 
            +
                    )
         | 
| 53 | 
            +
                  end
         | 
| 54 54 | 
             
                end
         | 
| 55 55 |  | 
| 56 | 
            -
                def  | 
| 57 | 
            -
             | 
| 56 | 
            +
                def generate_hash(output_schema = nil, limit: 50, image: nil)
         | 
| 57 | 
            +
                  c = LikeQuery::Collect.new(limit)
         | 
| 58 | 
            +
                  c.collect(output_schema, limit: limit, image: image) { all }
         | 
| 59 | 
            +
                  c.generate_hash
         | 
| 60 | 
            +
                end
         | 
| 58 61 |  | 
| 59 | 
            -
             | 
| 62 | 
            +
                def generate_json(output_schema = nil, limit: 50, image: nil)
         | 
| 60 63 | 
             
                  c = LikeQuery::Collect.new(limit)
         | 
| 61 | 
            -
                  c. | 
| 62 | 
            -
                  c. | 
| 64 | 
            +
                  c.collect(output_schema, limit: limit, image: image) { all }
         | 
| 65 | 
            +
                  c.generate_json
         | 
| 63 66 | 
             
                end
         | 
| 64 67 |  | 
| 65 | 
            -
                def  | 
| 66 | 
            -
                  @ | 
| 68 | 
            +
                def like_query_schema
         | 
| 69 | 
            +
                  @like_query_schema
         | 
| 67 70 | 
             
                end
         | 
| 68 71 |  | 
| 69 72 | 
             
              end
         | 
    
        data/lib/like_query/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: like_query
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.8
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - christian
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023- | 
| 11 | 
            +
            date: 2023-09-01 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rails
         |