Module: Spider::Model::Storage::Document::Mongodb::MapperExtension

Defined in:
lib/spiderfw/model/storage/document/adapters/mongodb.rb

Overview

Mapper extension

Instance Method Summary collapse

Instance Method Details

#fetch(query) ⇒ Object



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/spiderfw/model/storage/document/adapters/mongodb.rb', line 253

def fetch(query)
    condition = prepare_condition(query.condition)
    request = prepare_request(query.request)
    options = {}
    options[:limit] = query.limit if query.limit
    options[:skip] = query.offset if query.offset
    if query.order
        order_array = []
        query.order.each do |order|
            order_element, direction = order
            dir_str = direction == :desc ? 'descending' : 'ascending'
            order_array << [order_element.to_s, dir_str]
        end
        options[:sort] = order_array unless order_array.empty?
    end
    res = storage.find(@model.name, condition, request, options)
    r = res.map{ |row| postprocess_result(row) }
    r.extend(Storage::StorageResult) # FIXME: avoid doing this twice
    r.total_rows = res.total_rows
    r
end

#postprocess_result(h, model = nil) ⇒ Object



275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/spiderfw/model/storage/document/adapters/mongodb.rb', line 275

def postprocess_result(h, model=nil)
    model ||= @model
    sh = {}
    h.each do |k, v|
        if k == :_id
            pks = model.split_keys_string(v)
            model.primary_keys.each_with_index do |pk, i|
                pkval = pks[i]
                pkval = storage_value_to_mapper(pk.type, pkval)
                sh[pk.name] = pks[i]
            end
        else
            el = model.elements[k]
            v = if v.is_a?(Hash)
                postprocess_result(v, el.model)
            elsif v.is_a?(Array)
                v.map{ |row| postprocess_result(row, el.model) }
            else
                v
            end
            sh[k] = v
        end
    end
    sh
end

#prepare_condition(condition) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/spiderfw/model/storage/document/adapters/mongodb.rb', line 172

def prepare_condition(condition)
    cond_hash = {}
    pks = []
    condition.each_with_comparison do |k, v, comp|
        element = model.elements[k.to_sym]
        name = nil
        if element.primary_key?
            if @model.primary_keys.length == 1
                name = '_id'
            else
                raise "Mongo conditions for multiple primary keys are not supported yet"
            end
        else
            name = element.name.to_s
        end
        #next unless model.mapper.mapped?(element)
        if element.model?
            if element.attributes[:embedded]
                # TODO
            else
                pks = []
                element.model.primary_keys.each do |ek|
                    kv = v[ek.name]
                    raise "Document mapper can't join #{element.name}: condition #{condition}" unless kv
                    pks << element.mapper.map_condition_value(ek.type, kv)
                end
                hash_v = element.model.keys_string(pks)
                hash_v = {Mongodb::CONDITION_OPS[comp] => hash_v} unless comp == '='
                cond_hash[name] = hash_v
            end
        else
            hash_v = map_condition_value(element.type, v)
            comp ||= '='
            if comp != '='
                if comp == 'like' || comp == 'ilike'
                    options = comp == 'ilike' ? Regexp::IGNORECASE : nil
                    parts = hash_v.split('%')
                    parts << "" if hash_v[-1].chr == '%'
                    re_str = parts.map{ |p| p.blank? ? '' : Regexp.quote(p)}.join('.+') 
                    hash_v = Regexp.new(re_str, options)
                else
                    hash_v = {Mongodb::CONDITION_OPS[comp] => hash_v}
                end
            end
            cond_hash[name] = hash_v
        end
    end
    or_conds = []
    or_conds << cond_hash if condition.conjunction == :or && condition.subconditions.length > 0
    condition.subconditions.each do |sub|
        sub_res = self.prepare_condition(sub)
        if condition.conjunction == :and
            cond_hash.merge!(sub_res)
        elsif condition.conjunction == :or
            or_conds << sub_res
        end
    end
    unless or_conds.empty?
        cond_hash = { '$or' => or_conds }
    end
    cond_hash
end

#prepare_request(request) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/spiderfw/model/storage/document/adapters/mongodb.rb', line 235

def prepare_request(request)
    h = {}
    request.each do |k, v|
        element = @model.elements[k.to_sym]
        next unless element
        name = element.primary_key? ? '_id' : element.name.to_s
        if v.is_a?(Spider::Model::Request)
            sub = prepare_request(v)
            sub.each do |sk, sv|
                h["#{name}.#{sk}"] = sv
            end
        else
            h[name] = 1
        end
    end
    h
end