Module: Igniter::Extensions::Contracts::AggregatePack

Defined in:
lib/igniter/extensions/contracts/aggregate_pack.rb

Constant Summary collapse

AGGREGATE_KEYWORDS =
%i[count sum avg].freeze

Class Method Summary collapse

Class Method Details

.avg_keywordObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/igniter/extensions/contracts/aggregate_pack.rb', line 65

def avg_keyword
  Igniter::Contracts::DslKeyword.new(:avg) do |name, from:, builder:, using: nil|
    builder.add_operation(
      kind: :compute,
      name: name,
      depends_on: [from.to_sym],
      callable: lambda do |**values|
        items = AggregatePack.enumerable_source(values.fetch(from.to_sym), source_name: from.to_sym,
                                                                           operation_name: :avg)
        projected = items.map { |item| AggregatePack.extract_value(item, using) }
        next nil if projected.empty?

        projected.sum.to_f / projected.length
      end
    )
  end
end

.count_keywordObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/igniter/extensions/contracts/aggregate_pack.rb', line 28

def count_keyword
  Igniter::Contracts::DslKeyword.new(:count) do |name, from:, builder:, matching: nil|
    builder.add_operation(
      kind: :compute,
      name: name,
      depends_on: [from.to_sym],
      callable: lambda do |**values|
        items = AggregatePack.enumerable_source(values.fetch(from.to_sym), source_name: from.to_sym,
                                                                           operation_name: :count)

        if matching
          items.count { |item| matching.call(item) }
        else
          items.count
        end
      end
    )
  end
end

.enumerable_source(source, source_name:, operation_name:) ⇒ Object

Raises:

  • (TypeError)


83
84
85
86
87
# File 'lib/igniter/extensions/contracts/aggregate_pack.rb', line 83

def enumerable_source(source, source_name:, operation_name:)
  return source.to_a if source.respond_to?(:to_a)

  raise TypeError, "#{operation_name} source #{source_name} is not enumerable"
end

.extract_value(item, projection) ⇒ Object



89
90
91
92
93
94
95
96
97
98
# File 'lib/igniter/extensions/contracts/aggregate_pack.rb', line 89

def extract_value(item, projection)
  return item if projection.nil?
  return projection.call(item) if projection.respond_to?(:call)

  key = projection.to_sym
  return item.fetch(key) if item.respond_to?(:key?) && item.key?(key)
  return item.fetch(key.to_s) if item.respond_to?(:key?) && item.key?(key.to_s)

  item.public_send(key)
end

.install_dsl_keywords(kernel) ⇒ Object



22
23
24
25
26
# File 'lib/igniter/extensions/contracts/aggregate_pack.rb', line 22

def install_dsl_keywords(kernel)
  kernel.dsl_keywords.register(:count, count_keyword)
  kernel.dsl_keywords.register(:sum, sum_keyword)
  kernel.dsl_keywords.register(:avg, avg_keyword)
end

.install_into(kernel) ⇒ Object



17
18
19
20
# File 'lib/igniter/extensions/contracts/aggregate_pack.rb', line 17

def install_into(kernel)
  install_dsl_keywords(kernel)
  kernel
end

.manifestObject



10
11
12
13
14
15
# File 'lib/igniter/extensions/contracts/aggregate_pack.rb', line 10

def manifest
  Igniter::Contracts::PackManifest.new(
    name: :extensions_aggregate,
    registry_contracts: AGGREGATE_KEYWORDS.map { |kind| Igniter::Contracts::PackManifest.dsl_keyword(kind) }
  )
end

.sum_keywordObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/igniter/extensions/contracts/aggregate_pack.rb', line 48

def sum_keyword
  Igniter::Contracts::DslKeyword.new(:sum) do |name, from:, builder:, using: nil|
    builder.add_operation(
      kind: :compute,
      name: name,
      depends_on: [from.to_sym],
      callable: lambda do |**values|
        items = AggregatePack.enumerable_source(values.fetch(from.to_sym), source_name: from.to_sym,
                                                                           operation_name: :sum)
        items.reduce(0) do |total, item|
          total + AggregatePack.extract_value(item, using)
        end
      end
    )
  end
end