From 1ada86bf7bd1a14231431a7fd2f5a96b66f0150a Mon Sep 17 00:00:00 2001 From: claytongentry Date: Sat, 19 Apr 2025 12:06:34 -0400 Subject: [PATCH 1/3] Generate scalar functions for each configured condition --- lib/manifold/templates/workspace_template.yml | 30 +++++++++-- .../terraform/workspace_configuration.rb | 51 ++++++++++++++++++- .../terraform/workspace_configuration_spec.rb | 50 ++++++++++++++++++ 3 files changed, 124 insertions(+), 7 deletions(-) diff --git a/lib/manifold/templates/workspace_template.yml b/lib/manifold/templates/workspace_template.yml index 38803a0..1e959cc 100644 --- a/lib/manifold/templates/workspace_template.yml +++ b/lib/manifold/templates/workspace_template.yml @@ -15,11 +15,31 @@ timestamp: metrics: renders: conditions: - mobile: IS_DESKTOP(context.device) - desktop: IS_MOBILE(context.device) - us: context.geo.country = 'US' - global: context.geo.country != 'US' - + mobile: + args: + device: STRING + body: device = 'mobile' + desktop: + args: + device: STRING + body: device = 'desktop' + us: + args: + country: STRING + body: country = 'US' + global: + args: + country: STRING + body: country != 'US' + organic: + args: + acquisition: STRING + body: acquisition = 'organic' + paid: + args: + acquisition: STRING + body: acquisition = 'paid' + breakouts: device: - mobile diff --git a/lib/manifold/terraform/workspace_configuration.rb b/lib/manifold/terraform/workspace_configuration.rb index 5cd7aa1..19c816b 100644 --- a/lib/manifold/terraform/workspace_configuration.rb +++ b/lib/manifold/terraform/workspace_configuration.rb @@ -162,7 +162,7 @@ def build_table_config(table_id, schema_path = nil) end # Represents a Terraform configuration for a Manifold workspace. - class WorkspaceConfiguration < Configuration + class WorkspaceConfiguration < Configuration # rubocop:disable Metrics/ClassLength attr_reader :name attr_writer :dimensions_config, :manifold_config @@ -214,7 +214,9 @@ def routine_config "merge_dimensions" => dimensions_routine_attributes, "merge_manifold" => manifold_routine_attributes }.compact - + # add user-defined condition routines, if any + conds = build_condition_routines + routines.merge!(conds) unless conds.empty? routines.empty? ? nil : routines end @@ -243,6 +245,51 @@ def manifold_routine_attributes "depends_on" => ["google_bigquery_dataset.#{name}"] } end + + # generate scalar function routines for defined conditions + def build_condition_routines + return {} unless @manifold_config.is_a?(Hash) && @manifold_config["metrics"].is_a?(Hash) + + @manifold_config["metrics"].each_with_object({}) do |(_grp, grp_cfg), routines| + next unless grp_cfg.is_a?(Hash) && grp_cfg["conditions"].is_a?(Hash) + + grp_cfg["conditions"].each do |cond_name, cond_cfg| + routines[build_routine_id(cond_name)] = condition_routine_attributes(build_routine_id(cond_name), cond_cfg) + end + end + end + + # build attributes for a single condition routine + def condition_routine_attributes(routine_id, cond_cfg) + attrs = { + "dataset_id" => name, "project" => "${var.project_id}", "routine_id" => routine_id, + "routine_type" => "SCALAR_FUNCTION", "language" => "SQL", + "definition_body" => cond_cfg["body"], "depends_on" => ["google_bigquery_dataset.#{name}"] + } + args = build_arguments(cond_cfg) + attrs["arguments"] = args if args + attrs["return_type"] = default_return_type + attrs + end + + # helper to extract argument blocks from condition config + def build_arguments(cond_cfg) + return unless cond_cfg["args"].is_a?(Hash) && !cond_cfg["args"].empty? + + cond_cfg["args"].map do |arg_name, arg_type| + { "name" => arg_name, "data_type" => [{ "type_kind" => arg_type }] } + end + end + + # default return type for condition routines + def default_return_type + [{ "data_type" => [{ "type_kind" => "BOOL" }] }] + end + + # helper to build routine identifier from condition name + def build_routine_id(cond_name) + "is#{cond_name.to_s.split(/_|\\s+/).map(&:capitalize).join}" + end end end end diff --git a/spec/manifold/terraform/workspace_configuration_spec.rb b/spec/manifold/terraform/workspace_configuration_spec.rb index 92e6ec0..07ad7f7 100644 --- a/spec/manifold/terraform/workspace_configuration_spec.rb +++ b/spec/manifold/terraform/workspace_configuration_spec.rb @@ -115,6 +115,56 @@ ) end end + + context "when metric conditions are present" do + before do + # define metrics with conditions for scalar function routines + config.manifold_config = { + "metrics" => { + "renders" => { + "conditions" => { + "organic" => { + "args" => { "acquisition" => "STRING" }, + "body" => "acquisition = 'organic'" + }, + "paid" => { + "args" => { "acquisition" => "STRING" }, + "body" => "acquisition = 'paid'" + } + } + } + } + } + end + + let(:routines) { json["resource"]["google_bigquery_routine"] } + + it "includes scalar function routines for each condition" do + expect(routines.keys).to include("isOrganic", "isPaid") + end + + # rubocop:disable RSpec/ExampleLength, RSpec/MultipleExpectations + it "correctly configures a condition routine" do + organic = routines["isOrganic"] + expect(organic).to include( + "dataset_id" => name, + "project" => "${var.project_id}", + "routine_id" => "isOrganic", + "routine_type" => "SCALAR_FUNCTION", + "language" => "SQL", + "definition_body" => "acquisition = 'organic'", + "depends_on" => ["google_bigquery_dataset.#{name}"] + ) + # arguments and return_type blocks + expect(organic["arguments"]).to eq([ + { "name" => "acquisition", "data_type" => [{ "type_kind" => "STRING" }] } + ]) + expect(organic["return_type"]).to eq([ + { "data_type" => [{ "type_kind" => "BOOL" }] } + ]) + end + # rubocop:enable RSpec/ExampleLength, RSpec/MultipleExpectations + end end context "when manifold configuration is present" do From f3d4c17c4e97a3933e5f3c5b3335e4ec3ffdd0ec Mon Sep 17 00:00:00 2001 From: claytongentry Date: Sat, 19 Apr 2025 12:24:40 -0400 Subject: [PATCH 2/3] little nicer --- lib/manifold/terraform/workspace_configuration.rb | 6 ++++-- lib/manifold/version.rb | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/manifold/terraform/workspace_configuration.rb b/lib/manifold/terraform/workspace_configuration.rb index 19c816b..87022fd 100644 --- a/lib/manifold/terraform/workspace_configuration.rb +++ b/lib/manifold/terraform/workspace_configuration.rb @@ -253,8 +253,10 @@ def build_condition_routines @manifold_config["metrics"].each_with_object({}) do |(_grp, grp_cfg), routines| next unless grp_cfg.is_a?(Hash) && grp_cfg["conditions"].is_a?(Hash) - grp_cfg["conditions"].each do |cond_name, cond_cfg| - routines[build_routine_id(cond_name)] = condition_routine_attributes(build_routine_id(cond_name), cond_cfg) + grp_cfg["conditions"].each do |name, cfg| + id = build_routine_id(name) + attrs = condition_routine_attributes(id, cfg) + routines[id] = attrs end end end diff --git a/lib/manifold/version.rb b/lib/manifold/version.rb index a0ab856..78c97ca 100644 --- a/lib/manifold/version.rb +++ b/lib/manifold/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Manifold - VERSION = "0.2.0" + VERSION = "0.3.0" end From fa9aee45f6430f03fd9cd0e1d926957aad4561cb Mon Sep 17 00:00:00 2001 From: claytongentry Date: Sat, 19 Apr 2025 12:25:52 -0400 Subject: [PATCH 3/3] hold on version bump for now --- lib/manifold/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/manifold/version.rb b/lib/manifold/version.rb index 78c97ca..a0ab856 100644 --- a/lib/manifold/version.rb +++ b/lib/manifold/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Manifold - VERSION = "0.3.0" + VERSION = "0.2.0" end