Skip to content

Commit

Permalink
syntax_tree support (#33)
Browse files Browse the repository at this point in the history
* syntax tree

* single quotes

* nah, lets do double quotes

* no plugins, some syntax cleanup
  • Loading branch information
waymondo authored Dec 24, 2023
1 parent 8817276 commit ce3d250
Show file tree
Hide file tree
Showing 28 changed files with 549 additions and 504 deletions.
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,5 @@ jobs:
PGPASSWORD: password
POSTGRES_PASSWORD: password
run: |
bundle exec stree check --ignore-files="vendor/**/*.rb" "**/*.rb"
bundle exec rake
21 changes: 0 additions & 21 deletions .rubocop.yml

This file was deleted.

1 change: 1 addition & 0 deletions .streerc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--print-width=100
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ if (rails_version = ENV['RAILS_VERSION'])
else
gem 'rails'
end
gem 'syntax_tree'
gem 'typeprof'

gemspec
4 changes: 4 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ Rake::TestTask.new(:test) do |t|
t.test_files = FileList['test/**/test_*.rb']
end

task :pre_commit do
`typeprof lib/hoardable.rb && stree write "**/*.rb"`
end

task default: %i[test]
21 changes: 10 additions & 11 deletions lib/generators/hoardable/install_generator.rb
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
# frozen_string_literal: true

require 'rails/generators'
require "rails/generators"

module Hoardable
# Generates an initializer file for {Hoardable} configuration and a migration with a PostgreSQL
# function.
class InstallGenerator < Rails::Generators::Base
source_root File.expand_path('templates', __dir__)
source_root File.expand_path("templates", __dir__)
include Rails::Generators::Migration

def create_initializer_file
create_file(
'config/initializers/hoardable.rb',
<<~TEXT
create_file("config/initializers/hoardable.rb", <<~TEXT)
# Hoardable configuration defaults are below. Learn more at https://github.com/waymondo/hoardable#configuration
#
# Hoardable.enabled = true
# Hoardable.version_updates = true
# Hoardable.save_trash = true
TEXT
)
end

def create_migration_file
migration_template 'install.rb.erb', 'db/migrate/install_hoardable.rb'
migration_template "install.rb.erb", "db/migrate/install_hoardable.rb"
end

def create_functions
Dir.glob(File.join(__dir__, 'functions', '*.sql')).each do |file_path|
file_name = file_path.match(%r{([^/]+)\.sql})[1]
template file_path, "db/functions/#{file_name}_v01.sql"
end
Dir
.glob(File.join(__dir__, "functions", "*.sql"))
.each do |file_path|
file_name = file_path.match(%r{([^/]+)\.sql})[1]
template file_path, "db/functions/#{file_name}_v01.sql"
end
end

def self.next_migration_number(dir)
Expand Down
17 changes: 10 additions & 7 deletions lib/generators/hoardable/migration_generator.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
# frozen_string_literal: true

require 'rails/generators'
require 'rails/generators/active_record/migration/migration_generator'
require "rails/generators"
require "rails/generators/active_record/migration/migration_generator"

module Hoardable
# Generates a migration to create an inherited uni-temporal table of a model including
# {Hoardable::Model}, for the storage of +versions+.
class MigrationGenerator < ActiveRecord::Generators::Base
source_root File.expand_path('templates', __dir__)
source_root File.expand_path("templates", __dir__)
include Rails::Generators::Migration
class_option(
:foreign_key_type,
type: :string,
optional: true,
desc: 'explictly set / override the foreign key type of the versions table'
desc: "explictly set / override the foreign key type of the versions table"
)

def create_versions_table
migration_template 'migration.rb.erb', "db/migrate/create_#{singularized_table_name}_versions.rb"
migration_template(
"migration.rb.erb",
"db/migrate/create_#{singularized_table_name}_versions.rb"
)
end

def create_triggers
Expand All @@ -38,13 +41,13 @@ def foreign_key_type
options[:foreign_key_type] ||
class_name.singularize.constantize.columns.find { |col| col.name == primary_key }.sql_type
rescue StandardError
'bigint'
"bigint"
end

def primary_key
options[:primary_key] || class_name.singularize.constantize.primary_key
rescue StandardError
'id'
"id"
end

def singularized_table_name
Expand Down
36 changes: 18 additions & 18 deletions lib/hoardable.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# frozen_string_literal: true

require 'active_record'
require 'fx'
require_relative 'hoardable/version'
require_relative 'hoardable/engine'
require_relative 'hoardable/finder_methods'
require_relative 'hoardable/scopes'
require_relative 'hoardable/error'
require_relative 'hoardable/database_client'
require_relative 'hoardable/source_model'
require_relative 'hoardable/version_model'
require_relative 'hoardable/model'
require_relative 'hoardable/associations'
require_relative 'hoardable/has_many'
require_relative 'hoardable/belongs_to'
require_relative 'hoardable/has_one'
require_relative 'hoardable/has_rich_text'
require_relative 'generators/hoardable/migration_generator'
require_relative 'generators/hoardable/install_generator'
require "active_record"
require "fx"
require_relative "hoardable/version"
require_relative "hoardable/engine"
require_relative "hoardable/finder_methods"
require_relative "hoardable/scopes"
require_relative "hoardable/error"
require_relative "hoardable/database_client"
require_relative "hoardable/source_model"
require_relative "hoardable/version_model"
require_relative "hoardable/model"
require_relative "hoardable/associations"
require_relative "hoardable/has_many"
require_relative "hoardable/belongs_to"
require_relative "hoardable/has_one"
require_relative "hoardable/has_rich_text"
require_relative "generators/hoardable/migration_generator"
require_relative "generators/hoardable/install_generator"
64 changes: 41 additions & 23 deletions lib/hoardable/database_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ def initialize(source_record)
delegate :version_class, to: :source_record

def insert_hoardable_version(operation, &block)
version = version_class.insert(initialize_version_attributes(operation), returning: source_primary_key.to_sym)
version =
version_class.insert(
initialize_version_attributes(operation),
returning: source_primary_key.to_sym
)
version_id = version[0][source_primary_key]
source_record.instance_variable_set('@hoardable_version', version_class.find(version_id))
source_record.instance_variable_set("@hoardable_version", version_class.find(version_id))
source_record.run_callbacks(:versioned, &block)
end

Expand All @@ -24,40 +28,50 @@ def source_primary_key
end

def find_or_initialize_hoardable_event_uuid
Thread.current[:hoardable_event_uuid] ||= ActiveRecord::Base.connection.query('SELECT gen_random_uuid();')[0][0]
Thread.current[:hoardable_event_uuid] ||= (
ActiveRecord::Base.connection.query("SELECT gen_random_uuid();")[0][0]
)
end

def initialize_version_attributes(operation)
source_attributes_without_primary_key.merge(
source_record.changes.transform_values { |h| h[0] },
{
'hoardable_id' => source_record.id,
'_event_uuid' => find_or_initialize_hoardable_event_uuid,
'_operation' => operation,
'_data' => initialize_hoardable_data.merge(changes: source_record.changes),
'_during' => initialize_temporal_range
"hoardable_id" => source_record.id,
"_event_uuid" => find_or_initialize_hoardable_event_uuid,
"_operation" => operation,
"_data" => initialize_hoardable_data.merge(changes: source_record.changes),
"_during" => initialize_temporal_range
}
)
end

def has_one_find_conditions(reflection)
{
reflection.type => source_record.class.name.sub(/Version$/, ''),
reflection.type => source_record.class.name.sub(/Version$/, ""),
reflection.foreign_key => source_record.hoardable_id,
'name' => (reflection.name.to_s.sub(/^rich_text_/, '') if reflection.class_name.match?(/RichText$/))
"name" =>
(reflection.name.to_s.sub(/^rich_text_/, "") if reflection.class_name.match?(/RichText$/))
}.reject { |k, v| k.nil? || v.nil? }
end

def has_one_at_timestamp
Hoardable.instance_variable_get('@at') || source_record.updated_at
Hoardable.instance_variable_get("@at") || source_record.updated_at
rescue NameError
raise(UpdatedAtColumnMissingError, source_record.class.table_name)
end

def source_attributes_without_primary_key
source_record.attributes.without(source_primary_key, *generated_column_names).merge(
source_record.class.select(refreshable_column_names).find(source_record.id).slice(refreshable_column_names)
)
source_record
.attributes
.without(source_primary_key, *generated_column_names)
.merge(
source_record
.class
.select(refreshable_column_names)
.find(source_record.id)
.slice(refreshable_column_names)
)
end

def generated_column_names
Expand All @@ -67,19 +81,23 @@ def generated_column_names
end

def refreshable_column_names
@refreshable_column_names ||= source_record.class.columns.select(&:default_function).reject do |column|
column.name == source_primary_key || column.name.in?(generated_column_names)
end.map(&:name)
@refreshable_column_names ||=
source_record
.class
.columns
.select(&:default_function)
.reject do |column|
column.name == source_primary_key || column.name.in?(generated_column_names)
end
.map(&:name)
end

def initialize_temporal_range
((previous_temporal_tsrange_end || hoardable_source_epoch)..Time.now.utc)
end

def initialize_hoardable_data
DATA_KEYS.to_h do |key|
[key, assign_hoardable_context(key)]
end
DATA_KEYS.to_h { |key| [key, assign_hoardable_context(key)] }
end

def assign_hoardable_context(key)
Expand All @@ -89,18 +107,18 @@ def assign_hoardable_context(key)
end

def unset_hoardable_version_and_event_uuid
source_record.instance_variable_set('@hoardable_version', nil)
source_record.instance_variable_set("@hoardable_version", nil)
return if source_record.class.connection.transaction_open?

Thread.current[:hoardable_event_uuid] = nil
end

def previous_temporal_tsrange_end
source_record.versions.only_most_recent.pluck('_during').first&.end
source_record.versions.only_most_recent.pluck("_during").first&.end
end

def hoardable_source_epoch
return source_record.created_at if source_record.class.column_names.include?('created_at')
return source_record.created_at if source_record.class.column_names.include?("created_at")

raise CreatedAtColumnMissingError, source_record.class.table_name
end
Expand Down
Loading

0 comments on commit ce3d250

Please sign in to comment.