File: aggregable.rb

package info (click to toggle)
ruby-origin 2.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 248 kB
  • sloc: ruby: 1,196; makefile: 3
file content (116 lines) | stat: -rw-r--r-- 3,139 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# encoding: utf-8
module Origin

  # Provides a DSL around crafting aggregation framework commands.
  #
  # @since 2.0.0
  module Aggregable
    extend Macroable

    # @attribute [r] pipeline The aggregation pipeline.
    attr_reader :pipeline

    # @attribute [rw] aggregating Flag for whether or not we are aggregating.
    attr_writer :aggregating

    # Has the aggregable enter an aggregation state. Ie, are only aggregation
    # operations allowed at this point on.
    #
    # @example Is the aggregable aggregating?
    #   aggregable.aggregating?
    #
    # @return [ true, false ] If the aggregable is aggregating.
    #
    # @since 2.0.0
    def aggregating?
      !!@aggregating
    end

    # Add a group ($group) operation to the aggregation pipeline.
    #
    # @example Add a group operation being verbose.
    #   aggregable.group(count: { "$sum" => 1 }, max: { "$max" => "likes" })
    #
    # @example Add a group operation using symbol shortcuts.
    #   aggregable.group(:count.sum => 1, :max.max => "likes")
    #
    # @param [ Hash ] operation The group operation.
    #
    # @return [ Aggregable ] The aggregable.
    #
    # @since 2.0.0
    def group(operation)
      aggregation(operation) do |pipeline|
        pipeline.group(operation)
      end
    end
    key :avg, :override, "$avg"
    key :max, :override, "$max"
    key :min, :override, "$min"
    key :sum, :override, "$sum"
    key :last, :override, "$last"
    key :push, :override, "$push"
    key :first, :override, "$first"
    key :add_to_set, :override, "$addToSet"

    # Add a projection ($project) to the aggregation pipeline.
    #
    # @example Add a projection to the pipeline.
    #   aggregable.project(author: 1, name: 0)
    #
    # @param [ Hash ] criterion The projection to make.
    #
    # @return [ Aggregable ] The aggregable.
    #
    # @since 2.0.0
    def project(operation = nil)
      aggregation(operation) do |pipeline|
        pipeline.project(operation)
      end
    end

    # Add an unwind ($unwind) to the aggregation pipeline.
    #
    # @example Add an unwind to the pipeline.
    #   aggregable.unwind(:field)
    #
    # @param [ String, Symbol ] field The name of the field to unwind.
    #
    # @return [ Aggregable ] The aggregable.
    #
    # @since 2.0.0
    def unwind(field)
      aggregation(field) do |pipeline|
        pipeline.unwind(field)
      end
    end

    private

    # Add the aggregation operation.
    #
    # @api private
    #
    # @example Aggregate on the operation.
    #   aggregation(operation) do |pipeline|
    #     pipeline.push("$project" => operation)
    #   end
    #
    # @param [ Hash ] operation The operation for the pipeline.
    #
    # @return [ Aggregable ] The cloned aggregable.
    #
    # @since 2.0.0
    def aggregation(operation)
      return self unless operation
      clone.tap do |query|
        unless aggregating?
          query.pipeline.concat(query.selector.to_pipeline)
          query.pipeline.concat(query.options.to_pipeline)
          query.aggregating = true
        end
        yield(query.pipeline)
      end
    end
  end
end