spectifly-sequel 0.0.1
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.
- data/.gitignore +3 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +55 -0
- data/README.md +99 -0
- data/Rakefile +13 -0
- data/lib/spectifly/sequel/builder.rb +30 -0
- data/lib/spectifly/sequel/config.rb +53 -0
- data/lib/spectifly/sequel/erb/create_association_tables.erb +4 -0
- data/lib/spectifly/sequel/erb/create_table.erb +9 -0
- data/lib/spectifly/sequel/erb/field/many_to_many_association.erb +9 -0
- data/lib/spectifly/sequel/erb/field/multiple_value_simple_type_field.erb +8 -0
- data/lib/spectifly/sequel/erb/field/single_value_simple_type_field.erb +1 -0
- data/lib/spectifly/sequel/erb/new_migration.erb +6 -0
- data/lib/spectifly/sequel/field.rb +22 -0
- data/lib/spectifly/sequel/field_for_migration.rb +45 -0
- data/lib/spectifly/sequel/migration_generator.rb +39 -0
- data/lib/spectifly/sequel/model.rb +47 -0
- data/lib/spectifly/sequel/relationship/base.rb +14 -0
- data/lib/spectifly/sequel/relationship/belongs_to.rb +17 -0
- data/lib/spectifly/sequel/relationship/belongs_to_many.rb +8 -0
- data/lib/spectifly/sequel/relationship/has_a.rb +8 -0
- data/lib/spectifly/sequel/relationship/has_and_belongs_to_many.rb +21 -0
- data/lib/spectifly/sequel/relationship/has_many.rb +12 -0
- data/lib/spectifly/sequel/relationship/has_one.rb +8 -0
- data/lib/spectifly/sequel/relationship/one_to_one.rb +17 -0
- data/lib/spectifly/sequel/tasks.rb +2 -0
- data/lib/spectifly/sequel/types.rb +22 -0
- data/lib/spectifly/sequel/version.rb +5 -0
- data/lib/spectifly/sequel.rb +24 -0
- data/lib/tasks/spectifly-sequel.rake +12 -0
- data/spec/expectations/animal_multiple_value_string_field.migration +8 -0
- data/spec/expectations/cow.migration +19 -0
- data/spec/expectations/group.migration +10 -0
- data/spec/expectations/individual.migration +21 -0
- data/spec/fixtures/config_file.yml +7 -0
- data/spec/fixtures/cow.entity +34 -0
- data/spec/fixtures/group.entity +17 -0
- data/spec/fixtures/individual.entity +37 -0
- data/spec/fixtures/invalid_config_file.yml +2 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/spectifly/sequel/builder_spec.rb +27 -0
- data/spec/spectifly/sequel/config_spec.rb +60 -0
- data/spec/spectifly/sequel/field_spec.rb +61 -0
- data/spec/spectifly/sequel/migration_generator_spec.rb +45 -0
- data/spec/spectifly/sequel/model_spec.rb +17 -0
- data/spec/spectifly/sequel/types_spec.rb +10 -0
- data/spec/tmp/migrations/README +2 -0
- data/spectifly-sequel.gemspec +30 -0
- metadata +253 -0
    
        data/.gitignore
    ADDED
    
    
    
        data/.ruby-version
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            1.9.3-p392
         | 
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | @@ -0,0 +1,55 @@ | |
| 1 | 
            +
            PATH
         | 
| 2 | 
            +
              remote: .
         | 
| 3 | 
            +
              specs:
         | 
| 4 | 
            +
                spectifly-sequel (0.0.1)
         | 
| 5 | 
            +
                  activesupport
         | 
| 6 | 
            +
                  sequel
         | 
| 7 | 
            +
                  spectifly
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            GEM
         | 
| 10 | 
            +
              remote: https://rubygems.org/
         | 
| 11 | 
            +
              specs:
         | 
| 12 | 
            +
                activesupport (3.2.12)
         | 
| 13 | 
            +
                  i18n (~> 0.6)
         | 
| 14 | 
            +
                  multi_json (~> 1.0)
         | 
| 15 | 
            +
                builder (3.2.0)
         | 
| 16 | 
            +
                columnize (0.3.6)
         | 
| 17 | 
            +
                debugger (1.5.0)
         | 
| 18 | 
            +
                  columnize (>= 0.3.1)
         | 
| 19 | 
            +
                  debugger-linecache (~> 1.2.0)
         | 
| 20 | 
            +
                  debugger-ruby_core_source (~> 1.2.0)
         | 
| 21 | 
            +
                debugger-linecache (1.2.0)
         | 
| 22 | 
            +
                debugger-ruby_core_source (1.2.0)
         | 
| 23 | 
            +
                diff-lcs (1.2.4)
         | 
| 24 | 
            +
                i18n (0.6.4)
         | 
| 25 | 
            +
                json (1.8.0)
         | 
| 26 | 
            +
                multi_json (1.7.2)
         | 
| 27 | 
            +
                rake (10.0.4)
         | 
| 28 | 
            +
                rspec (2.13.0)
         | 
| 29 | 
            +
                  rspec-core (~> 2.13.0)
         | 
| 30 | 
            +
                  rspec-expectations (~> 2.13.0)
         | 
| 31 | 
            +
                  rspec-mocks (~> 2.13.0)
         | 
| 32 | 
            +
                rspec-core (2.13.1)
         | 
| 33 | 
            +
                rspec-expectations (2.13.0)
         | 
| 34 | 
            +
                  diff-lcs (>= 1.1.3, < 2.0)
         | 
| 35 | 
            +
                rspec-mocks (2.13.1)
         | 
| 36 | 
            +
                sequel (3.47.0)
         | 
| 37 | 
            +
                simplecov (0.7.1)
         | 
| 38 | 
            +
                  multi_json (~> 1.0)
         | 
| 39 | 
            +
                  simplecov-html (~> 0.7.1)
         | 
| 40 | 
            +
                simplecov-html (0.7.1)
         | 
| 41 | 
            +
                spectifly (0.0.1)
         | 
| 42 | 
            +
                  builder
         | 
| 43 | 
            +
                  json
         | 
| 44 | 
            +
                  rake
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            PLATFORMS
         | 
| 47 | 
            +
              ruby
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            DEPENDENCIES
         | 
| 50 | 
            +
              bundler (~> 1.3)
         | 
| 51 | 
            +
              debugger
         | 
| 52 | 
            +
              rake
         | 
| 53 | 
            +
              rspec
         | 
| 54 | 
            +
              simplecov
         | 
| 55 | 
            +
              spectifly-sequel!
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,99 @@ | |
| 1 | 
            +
            # Spectifly Sequel Add-on
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            An add-on to Spectifly, which uses entity definitions based on YAML, to
         | 
| 4 | 
            +
            create Sequel migrations and model files
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            ## Caveat
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            This is very much a work in progress and any migrations generated from
         | 
| 9 | 
            +
            the gem should be carefully scrutinized for correctness prior to
         | 
| 10 | 
            +
            applying them to your database.  Right now, the gem's output is only
         | 
| 11 | 
            +
            tested with Postgres and only creates new tables but does not update
         | 
| 12 | 
            +
            schema that already exists (though ideally, that would be a future
         | 
| 13 | 
            +
            feature).
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ## Installation
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            Add this line to your application's Gemfile:
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                gem 'spectifly-sequel'
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            And then execute:
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                $ bundle
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            Once on rubygems, you'll also be able to install it yourself as:
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                $ gem install spectifly-sequel
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            ## Usage
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            The Spectifly markup language is a subset of YAML. Only one root node is allowed
         | 
| 32 | 
            +
            per file (since a single `.entity` file represents a single business entity),
         | 
| 33 | 
            +
            and there are other restrictions, as well as additional features, which we'll
         | 
| 34 | 
            +
            discuss here.
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            Given a Spectifly entity defintion `lib/entities/widget.entity`:
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            ```YAML
         | 
| 39 | 
            +
            Widget:
         | 
| 40 | 
            +
              Description: A widget produced by WidgetCo
         | 
| 41 | 
            +
              Fields:
         | 
| 42 | 
            +
                Name*:
         | 
| 43 | 
            +
                  Description: Display name of widget
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                Created At:
         | 
| 46 | 
            +
                  Description: When the widget was built
         | 
| 47 | 
            +
                  Type: DateTime
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                Awesome?:
         | 
| 50 | 
            +
                  Description: Whether or not the widget is awesome
         | 
| 51 | 
            +
            ```
         | 
| 52 | 
            +
            When `rake spectifly:sequel:generate['widget']` is run, the following
         | 
| 53 | 
            +
            migration `db/migrate/001_create_widgets.rb` will be created.
         | 
| 54 | 
            +
            ```ruby
         | 
| 55 | 
            +
            Sequel.migration do
         | 
| 56 | 
            +
              change do
         | 
| 57 | 
            +
                create_table(:widgets) do
         | 
| 58 | 
            +
                  primary_key :id
         | 
| 59 | 
            +
                  String :name, :null => false
         | 
| 60 | 
            +
                  DateTime :created_at
         | 
| 61 | 
            +
                  Boolean :awesome
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
            end
         | 
| 65 | 
            +
            ```
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            ## Configuration
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            Spectifly Sequel does not make any assumptions about where you put your
         | 
| 70 | 
            +
            entity definitions or migrations.  In order for the gem to run
         | 
| 71 | 
            +
            correctly, you'll need to specifly the path to a YAML file or set the
         | 
| 72 | 
            +
            config directly via a hash.
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            ```ruby
         | 
| 75 | 
            +
            # to set via YAML file
         | 
| 76 | 
            +
            Spectifly::Sequel.configure_with PATH_TO_CONFIG_YAML
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            # to set via hash
         | 
| 79 | 
            +
            Spectifly::Sequel.configure {
         | 
| 80 | 
            +
              'migration_path' => PATH_TO_MIGRATION_DIRECTORY
         | 
| 81 | 
            +
              'entity_definition_path' => PATH_TO_ENTITY_DEFINITION_DIRECTORY
         | 
| 82 | 
            +
            }
         | 
| 83 | 
            +
            ```
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            The YAML configuration file should look something like this:
         | 
| 86 | 
            +
            ```yaml
         | 
| 87 | 
            +
            Sequel:
         | 
| 88 | 
            +
              Spectifly:
         | 
| 89 | 
            +
                migration_path: PATH_TO_MIGRATION_DIRECTORY
         | 
| 90 | 
            +
                entity_definition_path: PATH_TO_ENTITY_DEFINITION_DIRECTORY
         | 
| 91 | 
            +
            ```
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            ## Contributing
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            1. Fork it
         | 
| 96 | 
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         | 
| 97 | 
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         | 
| 98 | 
            +
            4. Push to the branch (`git push origin my-new-feature`)
         | 
| 99 | 
            +
            5. Create new Pull Request
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            require 'bundler'
         | 
| 2 | 
            +
            Bundler.setup
         | 
| 3 | 
            +
            Bundler::GemHelper.install_tasks
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require 'rspec/core/rake_task'
         | 
| 6 | 
            +
            RSpec::Core::RakeTask.new(:spec)
         | 
| 7 | 
            +
            task :default => [:spec]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            require 'sequel'
         | 
| 10 | 
            +
            require 'spectifly'
         | 
| 11 | 
            +
            require 'spectifly/base'
         | 
| 12 | 
            +
            require 'spectifly/sequel'
         | 
| 13 | 
            +
            require 'spectifly/sequel/tasks'
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            require 'erb'
         | 
| 2 | 
            +
            module Spectifly
         | 
| 3 | 
            +
              module Sequel
         | 
| 4 | 
            +
                class Builder < Spectifly::Base::Builder
         | 
| 5 | 
            +
                  attr_accessor :entities, :model
         | 
| 6 | 
            +
                  def initialize(entity, options = {})
         | 
| 7 | 
            +
                    super(entity, options)
         | 
| 8 | 
            +
                    @entities = Spectifly::Entity.from_directory(File.dirname(entity.path))
         | 
| 9 | 
            +
                    @model = Spectifly::Sequel::Model.new(entity, fields)
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def field_class
         | 
| 13 | 
            +
                    Spectifly::Sequel::Field
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def build
         | 
| 17 | 
            +
                    template_path = File.join(*File.dirname(__FILE__), 'erb', 'new_migration.erb')
         | 
| 18 | 
            +
                    render template_path
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  private
         | 
| 22 | 
            +
                    def render path
         | 
| 23 | 
            +
                      content = File.read(File.expand_path(path))
         | 
| 24 | 
            +
                      t = ERB.new(content, nil, '-') # third param lets us use trim
         | 
| 25 | 
            +
                      t.filename = File.expand_path(path)
         | 
| 26 | 
            +
                      t.result(binding)
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            module Spectifly
         | 
| 2 | 
            +
              module Sequel
         | 
| 3 | 
            +
                @valid_config_keys = [:migration_path, :entity_definition_path, :migration_version_type]
         | 
| 4 | 
            +
                @config = {}
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def self.configure_with(path_to_config_file)
         | 
| 7 | 
            +
                  begin
         | 
| 8 | 
            +
                    config = YAML.load_file(path_to_config_file)['Spectifly']['Sequel']
         | 
| 9 | 
            +
                  rescue NoMethodError
         | 
| 10 | 
            +
                    raise config_instructions
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                  configure(config)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def self.configure(opts)
         | 
| 16 | 
            +
                  opts.each {|k,v| @config[k.to_sym] = v if @valid_config_keys.include? k.to_sym}
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def self.migration_path
         | 
| 20 | 
            +
                  @config[:migration_path] or raise missing_configuration('migration_path')
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def self.entity_definition_path
         | 
| 24 | 
            +
                  @config[:entity_definition_path] or raise missing_configuration('entity_definition_path')
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def self.migration_version_type
         | 
| 28 | 
            +
                  type = @config[:migration_version_type].to_s
         | 
| 29 | 
            +
                  if %w(Timestamp Integer).include? type
         | 
| 30 | 
            +
                    type
         | 
| 31 | 
            +
                  else
         | 
| 32 | 
            +
                    'Timestamp'
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            private
         | 
| 37 | 
            +
                def self.config_instructions 
         | 
| 38 | 
            +
            <<-INSTRUCTIONS
         | 
| 39 | 
            +
            Please format config files in the following manner:
         | 
| 40 | 
            +
            ``- begin YAML
         | 
| 41 | 
            +
            Sequel:
         | 
| 42 | 
            +
              Spectifly:
         | 
| 43 | 
            +
                migration_path: PATH_TO_MIGRATION_DIRECTORY
         | 
| 44 | 
            +
                entity_definition_path: PATH_TO_ENTITY_DEFINITION_DIRECTORY
         | 
| 45 | 
            +
            ``- end YAML
         | 
| 46 | 
            +
            INSTRUCTIONS
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def self.missing_configuration(config_param)
         | 
| 50 | 
            +
                  "Spectify::Sequel is not configured properly. \"#{config_param}\" must be set via YAML or a hash."
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         | 
| @@ -0,0 +1,9 @@ | |
| 1 | 
            +
                create_table(:<%= @model.table_name %>) do
         | 
| 2 | 
            +
                  primary_key :id
         | 
| 3 | 
            +
            <% @model.single_value_fields.each do |field| -%>
         | 
| 4 | 
            +
                  <%= field.for_new_migration(@model, @entities) %>
         | 
| 5 | 
            +
            <% end -%>
         | 
| 6 | 
            +
            <% @model.foreign_keys.each do |key| -%>
         | 
| 7 | 
            +
                  foreign_key :<%= key.field_name %>, :<%= key.table_name %><%= ", :unique => true" if key.unique -%><%= ", :null => false" if key.required %>
         | 
| 8 | 
            +
            <% end -%>
         | 
| 9 | 
            +
                end
         | 
| @@ -0,0 +1,9 @@ | |
| 1 | 
            +
            <% @model.has_and_belong_to_many.each do |relationship| -%>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
                create_table(:<%= relationship.many_to_many_table_name %>) do
         | 
| 4 | 
            +
                  foreign_key :<%= @model.name_as_foreign_key %>, :<%= @model.table_name %>, :null => false
         | 
| 5 | 
            +
                  foreign_key :<%= relationship.field_name %>, :<%= relationship.table_name %>, :null => false
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                add_index [:<%=@model.name_as_foreign_key -%>, :<%= relationship.field_name -%>], :<%= relationship.many_to_many_table_name -%>, :unique => true
         | 
| 9 | 
            +
            <% end -%>
         | 
| @@ -0,0 +1,8 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
                create_table(:<%= @model.table_name %>_<%= @field.name %>) do
         | 
| 3 | 
            +
                  primary_key :id
         | 
| 4 | 
            +
                  foreign_key :<%= @model.name_as_foreign_key %>, :<%= @model.table_name %>, :null => false
         | 
| 5 | 
            +
                  <%= @field.type %> :name, :null => false
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                add_index [:<%=@model.name_as_foreign_key %>, :name], :<%= @model.table_name %>_<%= @field.name %>, :unique => true
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            <%= @field_type %> :<%= @field_name %><%= ", #{@options.join(', ')}" if !@options.empty? -%>
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            module Spectifly
         | 
| 2 | 
            +
              module Sequel
         | 
| 3 | 
            +
                class Field < Spectifly::Base::Field
         | 
| 4 | 
            +
                  def type
         | 
| 5 | 
            +
                    field_type = super
         | 
| 6 | 
            +
                    if base_type = Spectifly::Sequel::Types::Extended[field_type]
         | 
| 7 | 
            +
                      field_type = base_type['Type']
         | 
| 8 | 
            +
                    end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    Spectifly::Support.camelize(field_type)
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  # The entity_references param is the list of entity namesthat the caller
         | 
| 14 | 
            +
                  # knows about.  This lets us figure out whether the field should actually
         | 
| 15 | 
            +
                  # be the id of the entity/model being referenced by the field type.
         | 
| 16 | 
            +
                  def for_new_migration(model, entity_references = [])
         | 
| 17 | 
            +
                    @field_for_migration = Spectifly::Sequel::FieldForMigration.new(self, model, entity_references)
         | 
| 18 | 
            +
                    @field_for_migration.render
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            module Spectifly
         | 
| 2 | 
            +
              module Sequel
         | 
| 3 | 
            +
                class FieldForMigration
         | 
| 4 | 
            +
                  attr_accessor :field_name, :field_type, :options, :model
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(field, model, entity_references)
         | 
| 7 | 
            +
                    @field = field
         | 
| 8 | 
            +
                    @field_name = field.name
         | 
| 9 | 
            +
                    @field_type = field.type
         | 
| 10 | 
            +
                    @model = model
         | 
| 11 | 
            +
                    @options = retrieve_options(field)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def retrieve_options(field)
         | 
| 15 | 
            +
                    options = []
         | 
| 16 | 
            +
                    options << ':null => false' if field.required?
         | 
| 17 | 
            +
                    options << ':unique => true' if field.unique?
         | 
| 18 | 
            +
                    options
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def render
         | 
| 22 | 
            +
                    template = if single_value_simple_type?
         | 
| 23 | 
            +
                                 'single_value_simple_type_field'
         | 
| 24 | 
            +
                               elsif multiple_value_simple_type?
         | 
| 25 | 
            +
                                 'multiple_value_simple_type_field'
         | 
| 26 | 
            +
                               end
         | 
| 27 | 
            +
                    return if template.nil?
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    path = File.expand_path(File.join(*File.dirname(__FILE__), 'erb', 'field', "#{template}.erb"))
         | 
| 30 | 
            +
                    content = File.read(path)
         | 
| 31 | 
            +
                    t = ERB.new(content, nil, '-')
         | 
| 32 | 
            +
                    t.filename = path
         | 
| 33 | 
            +
                    t.result(binding)
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def single_value_simple_type?
         | 
| 37 | 
            +
                    @model_for_field.nil? && !@field.multiple?
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  def multiple_value_simple_type?
         | 
| 41 | 
            +
                    @model_for_field.nil? && @field.multiple?
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         | 
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            module Spectifly
         | 
| 2 | 
            +
              module Sequel
         | 
| 3 | 
            +
                class MigrationGenerator
         | 
| 4 | 
            +
                  def initialize(entity, migration_path=nil, entity_path=nil, migration_version_type=nil)
         | 
| 5 | 
            +
                    @migration_path = File.expand_path(migration_path || Spectifly::Sequel.migration_path)
         | 
| 6 | 
            +
                    @entity_definition_path = File.expand_path(entity_path || Spectifly::Sequel.entity_definition_path)
         | 
| 7 | 
            +
                    @migration_version_type = migration_version_type || Spectifly::Sequel.migration_version_type
         | 
| 8 | 
            +
                    @builder = Spectifly::Sequel::Builder.from_path(File.join(@entity_definition_path, entity + '.entity'))
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def run!
         | 
| 12 | 
            +
                    migration_output = @builder.build
         | 
| 13 | 
            +
                    File.open(File.join(@migration_path, migration_name), 'w') { |f| f.write(migration_output) }
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def migration_name
         | 
| 17 | 
            +
                    '%s_create_%s.rb' % [next_migration_version, @builder.model.table_name]
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def next_migration_version
         | 
| 21 | 
            +
                    if @migration_version_type == 'Timestamp'
         | 
| 22 | 
            +
                      DateTime.now.strftime('%Y%m%d%H%M%S')
         | 
| 23 | 
            +
                    else
         | 
| 24 | 
            +
                      last_migration = 0
         | 
| 25 | 
            +
                      length = 3
         | 
| 26 | 
            +
                      Dir.glob("#{@migration_path}/*.rb") do |rb_file|
         | 
| 27 | 
            +
                        migration = File.basename(rb_file).split('_').first
         | 
| 28 | 
            +
                        if migration.to_i > last_migration
         | 
| 29 | 
            +
                          last_migration = migration.to_i
         | 
| 30 | 
            +
                          length = migration.length
         | 
| 31 | 
            +
                        end
         | 
| 32 | 
            +
                      end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                      (last_migration + 1).to_s.rjust(length, "0")
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
            end
         | 
| @@ -0,0 +1,47 @@ | |
| 1 | 
            +
            module Spectifly
         | 
| 2 | 
            +
              module Sequel
         | 
| 3 | 
            +
                class Model
         | 
| 4 | 
            +
                  attr_accessor :table_name, :display_name, :model_name,
         | 
| 5 | 
            +
                    :single_value_fields, :multiple_value_fields,
         | 
| 6 | 
            +
                    :has_and_belong_to_many, :name_as_foreign_key,
         | 
| 7 | 
            +
                    :foreign_keys
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def initialize(entity, fields)
         | 
| 10 | 
            +
                    @display_name = entity.root
         | 
| 11 | 
            +
                    @model_name = Spectifly::Support.camelize(display_name)
         | 
| 12 | 
            +
                    @table_name = Spectifly::Support.tokenize(ActiveSupport::Inflector.pluralize(display_name))
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    @single_value_fields = fields.select { |f| !f.multiple? }
         | 
| 15 | 
            +
                    @multiple_value_fields = fields.select { |f| f.multiple? }
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    @name_as_foreign_key = Spectifly::Support.tokenize(display_name) + '_id'
         | 
| 18 | 
            +
                    get_relationships(entity)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def get_relationships(entity)
         | 
| 22 | 
            +
                    @foreign_keys = []
         | 
| 23 | 
            +
                    @has_and_belong_to_many = []
         | 
| 24 | 
            +
                    entity.relationships.each do |relationship_type, rels|
         | 
| 25 | 
            +
                      camelized_type = Spectifly::Support.camelize(relationship_type)
         | 
| 26 | 
            +
                      rels.each do |name, attributes|
         | 
| 27 | 
            +
                        if %w(BelongsTo HasOne HasA).include? camelized_type
         | 
| 28 | 
            +
                          relation = create_relation(camelized_type, name, attributes, entity)
         | 
| 29 | 
            +
                          @foreign_keys << relation
         | 
| 30 | 
            +
                        elsif %(BelongsToMany HasAndBelongsToMany HasMany).include?(camelized_type)
         | 
| 31 | 
            +
                          relation = create_relation(camelized_type, name, attributes, entity)
         | 
| 32 | 
            +
                          # as long as the has_many has a coinciding belongs_to_many and the association table makes sense...
         | 
| 33 | 
            +
                          if relation.multiple_related_entity? && !(@name_as_foreign_key == relation.field_name && @table_name == relation.table_name)
         | 
| 34 | 
            +
                            @has_and_belong_to_many << relation
         | 
| 35 | 
            +
                          end
         | 
| 36 | 
            +
                        end
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  def create_relation(type, name, attributes, entity)
         | 
| 42 | 
            +
                    relationship_class = ActiveSupport::Inflector.constantize('Spectifly::Sequel::Relationship::%s' % type)
         | 
| 43 | 
            +
                    relation = relationship_class.new(name, attributes, entity)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
            end
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            module Spectifly
         | 
| 2 | 
            +
              module Sequel
         | 
| 3 | 
            +
                module Relationship
         | 
| 4 | 
            +
                  class Base
         | 
| 5 | 
            +
                    attr_accessor :entity, :related_entity
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    def initialize(name, attributes, related_entity)
         | 
| 8 | 
            +
                      @entity = Spectifly::Base::EntityNode.new(name, attributes)
         | 
| 9 | 
            +
                      @related_entity = related_entity
         | 
| 10 | 
            +
                    end
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module Spectifly
         | 
| 2 | 
            +
              module Sequel
         | 
| 3 | 
            +
                module Relationship
         | 
| 4 | 
            +
                  class BelongsTo < Base
         | 
| 5 | 
            +
                    attr_accessor :field_name, :table_name, :required, :unique
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    def initialize(name, attributes, related_entity)
         | 
| 8 | 
            +
                      super
         | 
| 9 | 
            +
                      @table_name = Spectifly::Support.tokenize(ActiveSupport::Inflector.pluralize(@entity.type))
         | 
| 10 | 
            +
                      @field_name = Spectifly::Support.tokenize(@entity.name) + '_id'
         | 
| 11 | 
            +
                      @required = @entity.required?
         | 
| 12 | 
            +
                      @unique = @entity.unique?
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            module Spectifly
         | 
| 2 | 
            +
              module Sequel
         | 
| 3 | 
            +
                module Relationship
         | 
| 4 | 
            +
                  class HasAndBelongsToMany < Base
         | 
| 5 | 
            +
                    attr_accessor :field_name, :table_name, :many_to_many_table_name
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    def initialize(name, attributes, related_entity)
         | 
| 8 | 
            +
                      super
         | 
| 9 | 
            +
                      related_table_name = Spectifly::Support.tokenize(ActiveSupport::Inflector.pluralize(related_entity.root))
         | 
| 10 | 
            +
                      @field_name = Spectifly::Support.tokenize(ActiveSupport::Inflector.singularize(@entity.name)) + '_id'
         | 
| 11 | 
            +
                      @table_name = Spectifly::Support.tokenize(ActiveSupport::Inflector.pluralize(@entity.type))
         | 
| 12 | 
            +
                      @many_to_many_table_name = [related_table_name, Spectifly::Support.tokenize(@entity.name)].sort.join('_')
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    def multiple_related_entity?
         | 
| 16 | 
            +
                      true
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            module Spectifly
         | 
| 2 | 
            +
              module Sequel
         | 
| 3 | 
            +
                module Relationship
         | 
| 4 | 
            +
                  class HasMany < HasAndBelongsToMany
         | 
| 5 | 
            +
                    def multiple_related_entity?
         | 
| 6 | 
            +
                      related_entity = Spectifly::Entity.from_directory(File.dirname(@related_entity.path))[@entity.type]
         | 
| 7 | 
            +
                      (related_entity.relationships['Belongs To Many'] || {}).any? { |rel_name, attrs| attrs['Type'] == @related_entity.root }
         | 
| 8 | 
            +
                    end
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module Spectifly
         | 
| 2 | 
            +
              module Sequel
         | 
| 3 | 
            +
                module Relationship
         | 
| 4 | 
            +
                  class OneToOne < Base
         | 
| 5 | 
            +
                    attr_accessor :field_name, :table_name, :required, :unique
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    def initialize(name, attributes, related_entity)
         | 
| 8 | 
            +
                      super
         | 
| 9 | 
            +
                      @table_name = Spectifly::Support.tokenize(ActiveSupport::Inflector.pluralize(@entity.type))
         | 
| 10 | 
            +
                      @field_name = Spectifly::Support.tokenize(@entity.name) + '_id'
         | 
| 11 | 
            +
                      @required = @entity.required?
         | 
| 12 | 
            +
                      @unique = @entity.unique?
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            require 'sequel'
         | 
| 2 | 
            +
            module Spectifly
         | 
| 3 | 
            +
              module Sequel
         | 
| 4 | 
            +
                class Types
         | 
| 5 | 
            +
                  Native = ::Sequel::Schema::CreateTableGenerator::GENERIC_TYPES.map { |type| type.to_s }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  Extended = {
         | 
| 8 | 
            +
                    'percent' => {
         | 
| 9 | 
            +
                      'Type' => 'Numeric',
         | 
| 10 | 
            +
                    },
         | 
| 11 | 
            +
                    'currency' => {
         | 
| 12 | 
            +
                      'Type' => 'Numeric',
         | 
| 13 | 
            +
                    },
         | 
| 14 | 
            +
                    'year' => {
         | 
| 15 | 
            +
                      'Type' => 'Integer'
         | 
| 16 | 
            +
                    },
         | 
| 17 | 
            +
                  }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  All = Native + Extended.map { |k, v| v['Type'] }
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            require 'active_support/inflector/methods'
         | 
| 2 | 
            +
            require 'spectifly'
         | 
| 3 | 
            +
            require_relative 'sequel/config'
         | 
| 4 | 
            +
            require_relative 'sequel/types'
         | 
| 5 | 
            +
            require_relative 'sequel/model'
         | 
| 6 | 
            +
            require_relative 'sequel/tasks'
         | 
| 7 | 
            +
            require_relative 'sequel/relationship/base'
         | 
| 8 | 
            +
            require_relative 'sequel/relationship/one_to_one'
         | 
| 9 | 
            +
            require_relative 'sequel/relationship/belongs_to'
         | 
| 10 | 
            +
            require_relative 'sequel/relationship/has_and_belongs_to_many'
         | 
| 11 | 
            +
            require_relative 'sequel/relationship/belongs_to_many'
         | 
| 12 | 
            +
            require_relative 'sequel/relationship/has_a'
         | 
| 13 | 
            +
            require_relative 'sequel/relationship/has_one'
         | 
| 14 | 
            +
            require_relative 'sequel/relationship/has_many'
         | 
| 15 | 
            +
            require_relative 'sequel/field'
         | 
| 16 | 
            +
            require_relative 'sequel/field_for_migration'
         | 
| 17 | 
            +
            require_relative 'sequel/builder'
         | 
| 18 | 
            +
            require_relative 'sequel/migration_generator'
         | 
| 19 | 
            +
            require_relative 'sequel/version'
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            module Spectifly
         | 
| 22 | 
            +
              module Sequel
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            require 'rake'
         | 
| 2 | 
            +
            require 'spectifly/sequel'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            namespace 'spectifly' do
         | 
| 5 | 
            +
              namespace 'sequel' do
         | 
| 6 | 
            +
                desc 'Generate migration from entity definition file'
         | 
| 7 | 
            +
                task :generate, [:entity_type] do |t, args|
         | 
| 8 | 
            +
                  Spectifly::Sequel.configure_with File.join(Dir.pwd, 'config', 'spectifly.yml')
         | 
| 9 | 
            +
                  Spectifly::Sequel::MigrationGenerator.new(args[:entity_type]).run!
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         |