Skip to content
This repository has been archived by the owner on Oct 5, 2023. It is now read-only.

Commit

Permalink
Merge pull request #101 from socialcast/default-surrogate-key
Browse files Browse the repository at this point in the history
Default surrogate key
  • Loading branch information
mandrews committed Mar 25, 2015
2 parents 057f0a0 + 5aba560 commit 8aa8712
Show file tree
Hide file tree
Showing 24 changed files with 330 additions and 205 deletions.
31 changes: 23 additions & 8 deletions lib/masamune/schema/column.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class Column
index: Set.new,
unique: Set.new,
ignore: false,
sequence_offset: 1,
surrogate_key: false,
natural_key: false,
measure: false,
Expand All @@ -58,8 +59,6 @@ def initialize(opts = {})
DEFAULT_ATTRIBUTES.merge(opts).each do |name, value|
public_send("#{name}=", value)
end

initialize_default_attributes!
end

def id=(id)
Expand All @@ -74,6 +73,16 @@ def name
end
end

def default
return @default unless @default.nil?
case type
when :uuid
'uuid_generate_v4()'
when :sequence
"nextval('#{sequence_id}')"
end
end

def index=(value)
@index ||= Set.new
@index.clear
Expand All @@ -92,6 +101,11 @@ def index=(value)
end
end

def unique
self.unique = 'natural' if natural_key
@unique
end

def unique=(value)
@unique ||= Set.new
@unique.clear
Expand Down Expand Up @@ -152,6 +166,8 @@ def sql_type(for_surrogate_key = false)
'TIMESTAMP'
when :boolean
'BOOLEAN'
when :sequence
'INTEGER'
when :enum
"#{sub_type}_TYPE".upcase
when :key_value
Expand Down Expand Up @@ -436,24 +452,23 @@ def adjacent
reference.columns[id]
end

def sequence_id
"#{reference_name}_seq" if type == :sequence
end

private

def sql_constraints
[].tap do |constraints|
constraints << 'NOT NULL' unless null || surrogate_key || !strict || parent.temporary? || degenerate?
constraints << 'PRIMARY KEY' if surrogate_key
constraints << "PRIMARY KEY" if surrogate_key
end
end

def sql_default
"DEFAULT #{sql_value(default)}" unless default.nil?
end

def initialize_default_attributes!
self.default = 'uuid_generate_v4()' if surrogate_key && type == :uuid
self.unique = 'natural' if natural_key
end

def ruby_array(value)
case value
when Array
Expand Down
11 changes: 5 additions & 6 deletions lib/masamune/schema/dimension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def reserved_column_ids
when :two
[:start_at, :end_at, :version, :last_modified_at]
when :four
[:parent_uuid, :record_uuid, :start_at, :end_at, :version, :last_modified_at]
[:parent_id, :record_id, :start_at, :end_at, :version, :last_modified_at]
when :ledger
[:source_kind, :source_uuid, :start_at, :last_modified_at, :delta]
else
Expand Down Expand Up @@ -92,10 +92,8 @@ def ledger_table_columns

def initialize_surrogate_key_column!
case type
when :mini
when :mini, :one, :two, :four, :ledger, :date
initialize_column! id: 'id', type: :integer, surrogate_key: true
when :one, :two, :four, :ledger, :date
initialize_column! id: 'uuid', type: :uuid, surrogate_key: true
end
end

Expand All @@ -110,8 +108,9 @@ def initialize_dimension_columns!
initialize_column! id: 'last_modified_at', type: :timestamp, default: 'NOW()'
when :four
children << ledger_table
initialize_column! id: 'parent_uuid', type: :uuid, null: true, reference: ledger_table
initialize_column! id: 'record_uuid', type: :uuid, null: true, reference: ledger_table
# FIXME derive type from from parent
initialize_column! id: 'parent_id', type: :integer, null: true, reference: ledger_table
initialize_column! id: 'record_id', type: :integer, null: true, reference: ledger_table
initialize_column! id: 'start_at', type: :timestamp, default: 'TO_TIMESTAMP(0)', index: true, unique: 'natural'
initialize_column! id: 'end_at', type: :timestamp, null: true, index: true
initialize_column! id: 'version', type: :integer, default: 1, null: true, index: true
Expand Down
7 changes: 6 additions & 1 deletion lib/masamune/schema/table.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ def enum_columns
columns.select { |_, column| column.type == :enum }
end

def sequence_columns
return {} if temporary?
columns.select { |_, column| column.reference.nil? && column.type == :sequence }
end

def reference_columns
columns.values.select { | column| column.reference }
end
Expand Down Expand Up @@ -244,7 +249,7 @@ def stage_table_references(parent, selected = [])
def initialize_surrogate_key_column!
case type
when :table
initialize_column! id: 'uuid', type: :uuid, surrogate_key: true
initialize_column! id: 'id', type: :integer, surrogate_key: true
end
end

Expand Down
10 changes: 5 additions & 5 deletions lib/masamune/transform/deduplicate_dimension.psql.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@
-- THE SOFTWARE.

INSERT INTO
<%= target.name %> (<%= target.insert_columns.join(', ') %>, parent_uuid, record_uuid, start_at)
<%= target.name %> (<%= target.insert_columns.join(', ') %>, parent_id, record_id, start_at)
SELECT DISTINCT
<%- target.insert_view_values.each do |value| -%>
<%= value %><%= ',' %>
<%- end -%>
parent_uuid,
record_uuid,
parent_id,
record_id,
start_at
FROM (
SELECT
<%- target.insert_view_values.each do |value| -%>
<%= value %><%= ',' %>
<%- end -%>
parent_uuid,
record_uuid,
parent_id,
record_id,
start_at,
CASE
WHEN <%= target.insert_view_values.map { |value| "(LAG(#{value}) OVER w = #{value})" }.join(' AND ') %> THEN
Expand Down
12 changes: 12 additions & 0 deletions lib/masamune/transform/define_table.psql.erb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ CREATE TYPE <%= column.sql_type %> AS ENUM (<%= column.values.map { |value| "'#{
END IF; END $$;
<%- end -%>

<%- target.sequence_columns.each do |_, column| -%>
DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.relname = '<%= column.sequence_id %>') THEN
CREATE SEQUENCE <%= column.sequence_id %>;
ALTER SEQUENCE <%= column.sequence_id %> RESTART <%= column.sequence_offset %>;
END IF; END $$;
<%- end -%>

<%- if target.temporary? -%>
CREATE TEMPORARY TABLE IF NOT EXISTS <%= target.name %>
<%- else -%>
Expand All @@ -44,6 +52,10 @@ CREATE TABLE IF NOT EXISTS <%= target.name %>
<%- end -%>
);

<%- target.sequence_columns.each do |_, column| -%>
ALTER SEQUENCE <%= column.sequence_id %> OWNED BY <%= column.qualified_name %>;
<%- end -%>

<%- files.each do |file| -%>
<%-
copy_options = []
Expand Down
12 changes: 6 additions & 6 deletions lib/masamune/transform/relabel_dimension.psql.erb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ SET
FROM
(
SELECT
uuid,
id,
<%- target.window.each do |name| -%>
<%= name %>,
<%- end -%>
Expand All @@ -42,10 +42,10 @@ FROM
FROM
<%= target.name %>
GROUP BY
<%= target.window(:uuid, :start_at).join(', ') %>
<%= target.window(:id, :start_at).join(', ') %>
) AS tmp
WHERE
<%= target.name %>.uuid = tmp.uuid
<%= target.name %>.id = tmp.id
;

<%-# Relabel end_at column -%>
Expand All @@ -58,7 +58,7 @@ SET
FROM
(
SELECT
uuid,
id,
start_at,
<%- target.window.each do |name| -%>
<%= name %>,
Expand All @@ -67,10 +67,10 @@ FROM
FROM
<%= target.name %>
GROUP BY
<%= target.window(:uuid, :start_at).join(', ') %>
<%= target.window(:id, :start_at).join(', ') %>
) AS tmp
WHERE
<%= target.name %>.uuid = tmp.uuid
<%= target.name %>.id = tmp.id
;

COMMIT;
3 changes: 3 additions & 0 deletions lib/masamune/transform/rollup_fact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def insert_columns(source)
shared_columns(source).values.map do |columns|
column = columns.first
next if column.id == :last_modified_at
next if column.auto_reference
values << column.name
end
measures.each do |_ ,measure|
Expand All @@ -56,6 +57,7 @@ def insert_values(source)
column = columns.first
next unless column.reference
next if column.reference.type == :date
next if column.auto_reference
values << column.qualified_name
end
source.measures.each do |_ ,measure|
Expand All @@ -81,6 +83,7 @@ def group_by(source)
column = columns.first
next unless column.reference
next if column.reference.type == :date
next if column.auto_reference
group_by << column.qualified_name
end
group_by << "(#{floor_time_key(source)})" if grain == :hourly
Expand Down
14 changes: 7 additions & 7 deletions lib/masamune/transform/snapshot_dimension.psql.erb
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ WITH ranges AS (
<%- target.insert_view_values.each do |value| -%>
consolidated.<%= value %><%= ',' %>
<%- end -%>
consolidated.parent_uuid,
consolidated.record_uuid,
consolidated.parent_id,
consolidated.record_id,
consolidated.start_at
FROM (
SELECT DISTINCT ON (<%= target.window('start_at').join(', ') %>)
FIRST_VALUE(uuid) OVER w AS parent_uuid,
FIRST_VALUE(id) OVER w AS parent_id,
FIRST_VALUE(start_at) OVER w AS parent_start_at,
uuid AS record_uuid,
id AS record_id,
<%- target.insert_values(window: 'w').each do |value, last| -%>
<%= value %><%= ',' %>
<%- end -%>
Expand All @@ -62,13 +62,13 @@ WITH ranges AS (
<%- end -%>
)
INSERT INTO
<%= target.name %> (<%= target.insert_columns.join(', ') %>, parent_uuid, record_uuid, start_at)
<%= target.name %> (<%= target.insert_columns.join(', ') %>, parent_id, record_id, start_at)
SELECT
<%- target.insert_view_values.each do |value| -%>
<%= value %><%= ',' %>
<%- end -%>
parent_uuid,
record_uuid,
parent_id,
record_id,
start_at
FROM
snapshot
Expand Down
4 changes: 2 additions & 2 deletions lib/masamune/transform/stage_dimension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def insert_columns(source)
else
column.name
end
end
end.compact
end

def insert_values(source)
Expand All @@ -54,7 +54,7 @@ def insert_values(source)
else
column.qualified_name
end
end
end.compact
end
method_with_last_element :insert_values

Expand Down
2 changes: 1 addition & 1 deletion lib/masamune/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
# THE SOFTWARE.

module Masamune
VERSION = '0.9.0'
VERSION = '0.10.0.rc1'
end
16 changes: 16 additions & 0 deletions spec/masamune/schema/column_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@
it { expect { column }.to raise_error ArgumentError }
end

context 'with default: true' do
subject(:column) { described_class.new(id: 'boolean', type: :boolean, default: true) }
context '#default' do
subject { column.default }
it { is_expected.to eq(true) }
end
end

context 'with default: false' do
subject(:column) { described_class.new(id: 'boolean', type: :boolean, default: false) }
context '#default' do
subject { column.default }
it { is_expected.to eq(false) }
end
end

context 'with index: false' do
subject(:column) { described_class.new(id: 'id', index: false) }
context '#index' do
Expand Down
8 changes: 4 additions & 4 deletions spec/masamune/schema/table_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -292,17 +292,17 @@
end

context 'with specified columns' do
subject(:stage_table) { table.stage_table(columns: %w(uuid name user_account_state.uuid hr_user_account_state.uuid)) }
subject(:stage_table) { table.stage_table(columns: %w(id name user_account_state.id hr_user_account_state.id)) }

it 'should stage table' do
expect(stage_table.name).to eq('user_table_stage')
expect(stage_table.columns.keys).to eq([:name, :user_account_state_table_uuid, :hr_user_account_state_table_uuid])
expect(stage_table.columns.keys).to eq([:name, :user_account_state_table_id, :hr_user_account_state_table_id])
expect(stage_table.references.keys).to eq([:user_account_state, :hr_user_account_state])
end
end

context 'with specified columns (denormalized)' do
subject(:stage_table) { table.stage_table(columns: %w(uuid name user_account_state.name hr_user_account_state.name)) }
subject(:stage_table) { table.stage_table(columns: %w(id name user_account_state.name hr_user_account_state.name)) }

it 'should stage table' do
expect(stage_table.name).to eq('user_table_stage')
Expand Down Expand Up @@ -364,7 +364,7 @@

it 'should stage table' do
expect(stage_table.name).to eq('user_table_stage')
expect(stage_table.columns.keys).to eq([:hr_user_account_state_table_uuid, :user_id, :name])
expect(stage_table.columns.keys).to eq([:hr_user_account_state_table_id, :user_id, :name])
expect(stage_table.references.keys).to eq([:hr_user_account_state])
end
end
Expand Down
Loading

0 comments on commit 8aa8712

Please sign in to comment.