manifold-cli 0.0.17 → 0.0.18

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61582d1f6df6c8a674f9ef9b2374ae231fc98da47435ea5893d5077cb4dad34e
4
- data.tar.gz: ab91d3938b7a382ac003a467cd04d19cc6059804fe21e099e7e2aa60675eed3a
3
+ metadata.gz: 26f9112132a14f5bbb3cd123dc4d399ed9d618ec41638eaf43b5bbb0f870b6dd
4
+ data.tar.gz: cc8bc857ca5163f2e86ffe8656fe48b8fb46c3295bfa7f3ffad531597e0b15df
5
5
  SHA512:
6
- metadata.gz: 5cc06d2a611b1b29edbb466ab20cf8b82d4b99d609f57b71bd5e7f6098e7fcbd636c46a662306b8318c429148fbba3b4b6d6ddc3c603cddcb53ff81c9fe50f4c
7
- data.tar.gz: b8e44688d8e47628dc718bf992eb28114fde80a7cd60975e7a49cf91ce05fdf3ed2b6bc349c73332801ed5934b0a56a6f71ca100ad4b02df763c2f67cd2a3f8b
6
+ metadata.gz: dba055e83e3ef141fd49c8af5d7079d33a81ac6a54539c32270e86ecbd73840ee183f611e99f7c985c1b7c5cbb7bd32b2ac650abc8faa85946600a2ddf10af1b
7
+ data.tar.gz: d44010ad67f25f6ee9bd4762ee34a319062ebb82d68af81192bdba8becebad6850fd65e3e5e12f628114dd19ba17378bbecf196320e226613bb29e4062b3a80d
@@ -172,11 +172,7 @@ module Manifold
172
172
  return unless manifold_file
173
173
 
174
174
  sql_builder = Terraform::SQLBuilder.new(name, manifold_yaml)
175
- metrics_builder = Terraform::MetricsBuilder.new(manifold_yaml)
176
- sql = sql_builder.build_manifold_merge_sql(metrics_builder) do
177
- metrics_builder.build_metrics_struct
178
- end
179
-
175
+ sql = sql_builder.build_manifold_merge_sql
180
176
  routines_directory.join("merge_manifold.sql").write(sql)
181
177
  end
182
178
 
@@ -24,19 +24,5 @@ metrics:
24
24
  sequenceSum:
25
25
  field: context.sequence
26
26
 
27
- source: my_project.my_dataset.my_table
28
- filter: timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)
29
-
30
- taps:
31
- breakouts:
32
- paid: IS_PAID(context.location)
33
- organic: IS_ORGANIC(context.location)
34
-
35
- aggregations:
36
- countif: tapCount
37
- sumif:
38
- sequenceSum:
39
- field: context.sequence
40
-
41
- source: my_project.my_dataset.my_table
27
+ source: my_project.render_metrics
42
28
  filter: timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)
@@ -3,110 +3,40 @@
3
3
  module Manifold
4
4
  module Terraform
5
5
  # Handles building metrics SQL for manifold routines
6
- class MetricsBuilder
7
- def initialize(manifold_config)
6
+ class MetricsSQLBuilder
7
+ def initialize(name, manifold_config)
8
+ @name = name
8
9
  @manifold_config = manifold_config
9
10
  end
10
11
 
11
- def build_metrics_struct
12
- return "" unless @manifold_config["metrics"]
13
-
14
- metric_groups = @manifold_config["metrics"].map do |group_name, group_config|
15
- build_group_struct(group_name, group_config)
16
- end
17
-
18
- metric_groups.join(",\n")
12
+ def build_metrics_select
13
+ <<~SQL
14
+ SELECT
15
+ id,
16
+ timestamp,
17
+ #{build_metrics_struct}
18
+ FROM #{build_metric_joins}
19
+ SQL
19
20
  end
20
21
 
21
22
  private
22
23
 
23
- def build_group_struct(group_name, group_config)
24
- return "" unless valid_group_config?(group_config)
25
-
26
- breakout_structs = build_breakout_structs(group_config)
27
- return "" if breakout_structs.empty?
28
-
29
- "\tSTRUCT(\n#{breakout_structs.join(",\n")}\n\t) AS #{group_name}"
30
- end
31
-
32
- def valid_group_config?(group_config)
33
- group_config["breakouts"] &&
34
- group_config["aggregations"] &&
35
- !group_config["breakouts"].empty? &&
36
- !group_config["aggregations"].empty?
37
- end
38
-
39
- def build_breakout_structs(group_config)
40
- group_config["breakouts"].map do |name, config|
41
- build_breakout_struct(name, config, group_config)
42
- end.compact
43
- end
44
-
45
- def build_breakout_struct(name, config, group_config)
46
- condition = build_breakout_condition(name, config, group_config)
47
- metrics = build_breakout_metrics(group_config, condition)
48
- return if metrics.empty?
49
-
50
- "\t\tSTRUCT(\n\t\t\t#{metrics}\n\t\t) AS #{name}"
51
- end
52
-
53
- def build_breakout_metrics(group_config, condition)
54
- metrics = []
55
- add_count_metrics(metrics, group_config, condition)
56
- add_sum_metrics(metrics, group_config, condition)
57
- metrics.join(",\n\t\t\t")
58
- end
59
-
60
- def add_count_metrics(metrics, group_config, condition)
61
- return unless group_config.dig("aggregations", "countif")
62
-
63
- metrics << "COUNTIF(#{condition}) AS #{group_config["aggregations"]["countif"]}"
64
- end
65
-
66
- def add_sum_metrics(metrics, group_config, condition)
67
- group_config.dig("aggregations", "sumif")&.each do |name, config|
68
- metrics << "SUM(IF(#{condition}, #{config["field"]}, 0)) AS #{name}"
69
- end
70
- end
71
-
72
- def build_breakout_condition(_name, config, group_config)
73
- return config unless config.is_a?(Hash)
74
-
75
- operator = config["operator"]
76
- fields = config["fields"]
77
- build_operator_condition(operator, fields, group_config)
78
- end
79
-
80
- def build_operator_condition(operator, fields, group_config)
81
- conditions = fields.map { |f| group_config["breakouts"][f] }
82
- case operator
83
- when "AND", "OR" then join_conditions(conditions, operator)
84
- when "NOT" then negate_condition(conditions.first)
85
- when "NAND", "NOR" then negate_joined_conditions(conditions, operator[1..])
86
- when "XOR" then build_xor_condition(conditions)
87
- when "XNOR" then build_xnor_condition(conditions)
88
- else config
89
- end
90
- end
91
-
92
- def join_conditions(conditions, operator)
93
- conditions.join(" #{operator} ")
94
- end
95
-
96
- def negate_condition(condition)
97
- "NOT (#{condition})"
24
+ def build_metrics_struct
25
+ metric_groups = @manifold_config["metrics"].keys
26
+ metric_groups.map { |group| "#{group}.metrics #{group}" }.join(",\n ")
98
27
  end
99
28
 
100
- def negate_joined_conditions(conditions, operator)
101
- "NOT (#{join_conditions(conditions, operator)})"
102
- end
29
+ def build_metric_joins
30
+ metric_groups = @manifold_config["metrics"]
31
+ joins = metric_groups.map { |group, config| "#{config["source"]} AS #{group}" }
32
+ first = joins.shift
33
+ return first if joins.empty?
103
34
 
104
- def build_xor_condition(conditions)
105
- "(#{conditions[0]} AND NOT #{conditions[1]}) OR (NOT #{conditions[0]} AND #{conditions[1]})"
35
+ "#{first}\n #{joins.map { |table| "FULL OUTER JOIN #{table} USING (id, timestamp)" }.join("\n ")}"
106
36
  end
107
37
 
108
- def build_xnor_condition(conditions)
109
- "(#{conditions[0]} AND #{conditions[1]}) OR (NOT #{conditions[0]} AND NOT #{conditions[1]})"
38
+ def timestamp_field
39
+ @manifold_config&.dig("timestamp", "field")
110
40
  end
111
41
  end
112
42
 
@@ -115,17 +45,17 @@ module Manifold
115
45
  def initialize(name, manifold_config)
116
46
  @name = name
117
47
  @manifold_config = manifold_config
48
+ @metrics_builder = MetricsSQLBuilder.new(name, manifold_config)
118
49
  end
119
50
 
120
- def build_manifold_merge_sql(_metrics_builder, &)
51
+ def build_manifold_merge_sql
121
52
  return "" unless valid_config?
122
53
 
123
54
  <<~SQL
124
55
  MERGE #{@name}.Manifold AS target USING (
125
- #{build_metrics_cte(&)}
126
- #{build_final_select}
56
+ #{build_source_query}
127
57
  ) AS source
128
- ON source.id = target.id AND source.timestamp = target.timestamp
58
+ #{build_merge_conditions}
129
59
  #{build_merge_actions}
130
60
  SQL
131
61
  end
@@ -153,55 +83,30 @@ module Manifold
153
83
  first_group&.dig("source")
154
84
  end
155
85
 
156
- def interval
157
- @manifold_config&.dig("timestamp", "interval") || "DAY"
158
- end
159
-
160
- def where_clause
161
- first_group = @manifold_config["metrics"]&.values&.first
162
- return "" unless first_group&.dig("filter")
163
-
164
- "WHERE #{first_group["filter"]}"
165
- end
166
-
167
86
  def timestamp_field
168
87
  @manifold_config&.dig("timestamp", "field")
169
88
  end
170
89
 
171
- def build_metrics_cte(&)
90
+ def build_source_query
172
91
  <<~SQL
173
92
  WITH Metrics AS (
174
- #{build_metrics_select(&)}
93
+ #{@metrics_builder.build_metrics_select}
175
94
  )
176
- SQL
177
- end
178
95
 
179
- def build_metrics_select(&block)
180
- <<~SQL
181
- SELECT
182
- id,
183
- TIMESTAMP_TRUNC(#{timestamp_field}, #{interval}) timestamp,
184
- STRUCT(
185
- #{block.call}
186
- ) AS metrics
187
- FROM #{source_table}
188
- #{where_clause}
189
- GROUP BY 1, 2
190
- SQL
191
- end
192
-
193
- def build_final_select
194
- <<~SQL
195
96
  SELECT
196
97
  id,
197
98
  timestamp,
198
99
  Dimensions.dimensions,
199
- Metrics.metrics
100
+ (SELECT AS STRUCT Metrics.* EXCEPT(id, timestamp)) metrics
200
101
  FROM Metrics
201
- LEFT JOIN #{@name}.Dimensions USING (id)
102
+ JOIN #{@name}.Dimensions USING (id)
202
103
  SQL
203
104
  end
204
105
 
106
+ def build_merge_conditions
107
+ "ON source.id = target.id AND source.timestamp = target.timestamp"
108
+ end
109
+
205
110
  def build_merge_actions
206
111
  <<~SQL
207
112
  WHEN MATCHED THEN
@@ -298,8 +203,8 @@ module Manifold
298
203
 
299
204
  def routine_config
300
205
  routines = {
301
- "merge_dimensions" => dimensions_routine_attributes
302
- # "merge_manifold" => manifold_routine_attributes
206
+ "merge_dimensions" => dimensions_routine_attributes,
207
+ "merge_manifold" => manifold_routine_attributes
303
208
  }.compact
304
209
 
305
210
  routines.empty? ? nil : routines
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Manifold
4
- VERSION = "0.0.17"
4
+ VERSION = "0.0.18"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manifold-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.17
4
+ version: 0.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - claytongentry
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-18 00:00:00.000000000 Z
10
+ date: 2025-02-19 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: thor