schemaless 0.0.3
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 +7 -0
 - data/README.md +93 -0
 - data/Rakefile +18 -0
 - data/lib/generators/schemaless/migrations/USAGE +8 -0
 - data/lib/generators/schemaless/migrations/migrations_generator.rb +108 -0
 - data/lib/generators/schemaless/migrations/templates/change_table.rb +34 -0
 - data/lib/generators/schemaless/migrations/templates/create_table.rb +18 -0
 - data/lib/generators/schemaless/setup/setup_generator.rb +17 -0
 - data/lib/generators/schemaless/setup/templates/schemaless.rb +3 -0
 - data/lib/schemaless/ar/fields.rb +76 -0
 - data/lib/schemaless/ar/indexes.rb +46 -0
 - data/lib/schemaless/ar/stubs.rb +15 -0
 - data/lib/schemaless/field.rb +94 -0
 - data/lib/schemaless/index.rb +59 -0
 - data/lib/schemaless/railtie.rb +23 -0
 - data/lib/schemaless/table.rb +95 -0
 - data/lib/schemaless/version.rb +4 -0
 - data/lib/schemaless/worker.rb +47 -0
 - data/lib/schemaless.rb +21 -0
 - data/lib/tasks/schemaless_tasks.rake +23 -0
 - data/spec/dummy/README.rdoc +28 -0
 - data/spec/dummy/Rakefile +6 -0
 - data/spec/dummy/app/assets/javascripts/application.js +13 -0
 - data/spec/dummy/app/assets/stylesheets/application.css +15 -0
 - data/spec/dummy/app/controllers/application_controller.rb +5 -0
 - data/spec/dummy/app/helpers/application_helper.rb +2 -0
 - data/spec/dummy/app/models/bike.rb +18 -0
 - data/spec/dummy/app/models/place.rb +8 -0
 - data/spec/dummy/app/models/rider.rb +8 -0
 - data/spec/dummy/app/models/user.rb +21 -0
 - data/spec/dummy/app/views/layouts/application.html.erb +14 -0
 - data/spec/dummy/bin/bundle +3 -0
 - data/spec/dummy/bin/rails +4 -0
 - data/spec/dummy/bin/rake +4 -0
 - data/spec/dummy/config/application.rb +28 -0
 - data/spec/dummy/config/boot.rb +5 -0
 - data/spec/dummy/config/database.yml +25 -0
 - data/spec/dummy/config/environment.rb +5 -0
 - data/spec/dummy/config/environments/development.rb +37 -0
 - data/spec/dummy/config/environments/production.rb +78 -0
 - data/spec/dummy/config/environments/test.rb +39 -0
 - data/spec/dummy/config/initializers/assets.rb +8 -0
 - data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
 - data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
 - data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
 - data/spec/dummy/config/initializers/inflections.rb +16 -0
 - data/spec/dummy/config/initializers/mime_types.rb +4 -0
 - data/spec/dummy/config/initializers/session_store.rb +3 -0
 - data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
 - data/spec/dummy/config/locales/en.yml +23 -0
 - data/spec/dummy/config/routes.rb +56 -0
 - data/spec/dummy/config/secrets.yml +22 -0
 - data/spec/dummy/config.ru +4 -0
 - data/spec/dummy/db/development.sqlite3 +0 -0
 - data/spec/dummy/db/migrate/20141202223732_create_bikes.rb +16 -0
 - data/spec/dummy/db/migrate/20141202223750_create_places.rb +9 -0
 - data/spec/dummy/db/migrate/20141202223751_create_riders.rb +10 -0
 - data/spec/dummy/db/migrate/20141202223752_create_users.rb +8 -0
 - data/spec/dummy/db/migrate/20141202223753_create_user_skills.rb +8 -0
 - data/spec/dummy/db/migrate/20141202223754_create_user_extras.rb +8 -0
 - data/spec/dummy/db/production.sqlite3 +0 -0
 - data/spec/dummy/db/test.sqlite3 +0 -0
 - data/spec/dummy/log/development.log +213 -0
 - data/spec/dummy/log/test.log +185888 -0
 - data/spec/dummy/public/404.html +67 -0
 - data/spec/dummy/public/422.html +67 -0
 - data/spec/dummy/public/500.html +66 -0
 - data/spec/dummy/public/favicon.ico +0 -0
 - data/spec/generators/schemaless/migrations/migration_generator_spec.rb +14 -0
 - data/spec/locales/en.yml +15 -0
 - data/spec/locales/pt.yml +27 -0
 - data/spec/schemaless/ar/fields_spec.rb +45 -0
 - data/spec/schemaless/ar/indexes_spec.rb +43 -0
 - data/spec/schemaless/field_spec.rb +29 -0
 - data/spec/schemaless/index_spec.rb +9 -0
 - data/spec/schemaless/table_spec.rb +25 -0
 - data/spec/schemaless/worker_spec.rb +57 -0
 - data/spec/schemaless_spec.rb +15 -0
 - data/spec/spec_helper.rb +57 -0
 - data/spec/support/001_create_testing_structure.rb +36 -0
 - metadata +309 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: cc3e152ecd0dded8e8316950f59c6616276694e4
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: a4232d47f7faec46ac0886141b215c0eaac023ad
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 131f65209c376f9976dbdd973ddf87bfda7ab27f6e29e16303c0f38dc7a3c564dfc077573953a4499a64f9a1b4ace3103e1f2dfe715f1786d5e867e1ffbddcba
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 6ac58bc7b86799d04557a64cb2f3f7bdc4e2722354a1a6cbd122b4d6cbef967e273b84c69558d47f0d08c76a810e1364f74a4a6337b0839bf2ae6adb37825c9f
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,93 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Schemaless
         
     | 
| 
      
 2 
     | 
    
         
            +
            ==========
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            **On ActiveRecord | PostgreSQL**
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            **Experimental, bugged code**, please use to submit bugs/requests.
         
     | 
| 
      
 7 
     | 
    
         
            +
            Needs more test code and scenarios also.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 11 
     | 
    
         
            +
            class Bike < ActiveRecord::Base
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              # field column name, column type, null: limit: precision: scale:
         
     | 
| 
      
 14 
     | 
    
         
            +
              field :name               # omit for String
         
     | 
| 
      
 15 
     | 
    
         
            +
              field :cylinders, Integer # or Float, :decimal, :currency
         
     | 
| 
      
 16 
     | 
    
         
            +
              field :bought_at, Date    # Time, :date, :time, :timestamp
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              # Adds 'default: to AR
         
     | 
| 
      
 19 
     | 
    
         
            +
              field :three_wheeler, :boolean, default: false
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              # Adds Array/Hash in PG
         
     | 
| 
      
 22 
     | 
    
         
            +
              field :tags, Hash  # hstore
         
     | 
| 
      
 23 
     | 
    
         
            +
              field :tags, Array # hstore
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              # index columns, name: unique: orders: also supported.
         
     | 
| 
      
 26 
     | 
    
         
            +
              index :name
         
     | 
| 
      
 27 
     | 
    
         
            +
              index [:name, :cylinders]
         
     | 
| 
      
 28 
     | 
    
         
            +
              ...
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            ```
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            # Why?
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            * Schema is **defined in code**, not in the DB.
         
     | 
| 
      
 36 
     | 
    
         
            +
            (Plus no need for annotate models)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            * It's easier and **less time** consuming.
         
     | 
| 
      
 39 
     | 
    
         
            +
            Honestly, you never forgot that field and had to re-run a migration?
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            * There's **no footprint** in production mode.
         
     | 
| 
      
 42 
     | 
    
         
            +
            No code executed in production mode.
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            # How?
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            Just include the gem and run:
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                rails g schemaless:setup
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            ## DEVELOPMENT | Realtime mode
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            This mode runs only in development mode.
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            It's when you are working, happy, without worry about schemas!
         
     | 
| 
      
 57 
     | 
    
         
            +
            And also now DB fields are nicely described in the model.rb.
         
     | 
| 
      
 58 
     | 
    
         
            +
            Logic is all in the ruby file now. It's like NoSQL: fun!
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            ## PRODUCTION | Migrate servers
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            Schemaless only stubs the #fields and #index methods in production.
         
     | 
| 
      
 64 
     | 
    
         
            +
            There's nothing running/using resources in production.
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            To commit your changes you have two options:
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            ## Safe mode
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            In safe mode there's no change in the production perspective:
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                rails g schemaless:migrations
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            You'll find a migration per changed table waiting for you in git.
         
     | 
| 
      
 75 
     | 
    
         
            +
            You simply review'em, and actually, there's no need to test them,
         
     | 
| 
      
 76 
     | 
    
         
            +
            as your test suite is using them.
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
            ## Wild mode
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            Schemaphobia? Very dangerous idea?
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                rake schemaless:run
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            Here we don't use any migration **as files**.
         
     | 
| 
      
 86 
     | 
    
         
            +
            On the production servers a rake task ensures everything is up to date.
         
     | 
| 
      
 87 
     | 
    
         
            +
            Tests also use the schema on the models.
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            ---
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            Have fun!
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env rake
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'bundler/gem_tasks'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'rspec/core/rake_task'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'rubocop/rake_task'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
         
     | 
| 
      
 8 
     | 
    
         
            +
            # load 'rails/tasks/engine.rake'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            Bundler::GemHelper.install_tasks
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            # Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            # RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
         
     | 
| 
      
 15 
     | 
    
         
            +
            RSpec::Core::RakeTask.new
         
     | 
| 
      
 16 
     | 
    
         
            +
            RuboCop::RakeTask.new
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            task default: [:spec, :rubocop]
         
     | 
| 
         @@ -0,0 +1,108 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rails/generators'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rails/generators/migration'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Schemaless
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Generates migrations for schemaless safe mode
         
     | 
| 
      
 6 
     | 
    
         
            +
              class MigrationsGenerator < Rails::Generators::Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                include Rails::Generators::Migration
         
     | 
| 
      
 8 
     | 
    
         
            +
                source_root File.expand_path('../templates', __FILE__)
         
     | 
| 
      
 9 
     | 
    
         
            +
                argument :models, type: :array, default: [] # , banner: 'path'
         
     | 
| 
      
 10 
     | 
    
         
            +
                desc 'Schemaless migration files generator!'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def create_migration_files
         
     | 
| 
      
 13 
     | 
    
         
            +
                  Rails.application.eager_load!
         
     | 
| 
      
 14 
     | 
    
         
            +
                  all_tables = Schemaless::Worker.all_tables
         
     | 
| 
      
 15 
     | 
    
         
            +
                  if models.empty?
         
     | 
| 
      
 16 
     | 
    
         
            +
                    tables = all_tables
         
     | 
| 
      
 17 
     | 
    
         
            +
                  else
         
     | 
| 
      
 18 
     | 
    
         
            +
                    tables = all_tables.select { |t| models.include?(t.model.to_s.downcase) }
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  tables.each do |table|
         
     | 
| 
      
 21 
     | 
    
         
            +
                    puts "Generating migrations for #{table}"
         
     | 
| 
      
 22 
     | 
    
         
            +
                    create_migration_for table
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                protected
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                attr_reader :table_name, :fields, :indexes, :migration_action, :join_tables
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def build_file_name(name = [])
         
     | 
| 
      
 31 
     | 
    
         
            +
                  if @table.fields.add.any?
         
     | 
| 
      
 32 
     | 
    
         
            +
                    name << :add
         
     | 
| 
      
 33 
     | 
    
         
            +
                    name << (@table.fields.add.size > 3 ? :many : @table.fields.add)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    name << (@table.fields.remove.any? ? :and : :to)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                  if @table.fields.remove.any?
         
     | 
| 
      
 37 
     | 
    
         
            +
                    name << :remove
         
     | 
| 
      
 38 
     | 
    
         
            +
                    name << (@table.fields.remove.size > 3 ? :many : @table.fields.remove)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    name << :from
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  name << table_name
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def file_name
         
     | 
| 
      
 45 
     | 
    
         
            +
                  return @file_name if @file_name
         
     | 
| 
      
 46 
     | 
    
         
            +
                  return "create_#{@table_name}" unless @table.exists?
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @file_name = build_file_name.flatten.join('_')
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def create_migration_for table
         
     | 
| 
      
 51 
     | 
    
         
            +
                  @table   = table
         
     | 
| 
      
 52 
     | 
    
         
            +
                  @fields  = @table.fields
         
     | 
| 
      
 53 
     | 
    
         
            +
                  @indexes = @table.indexes
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @table_name = @table.name
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  template = file_name =~ /^create_(.+)/ ? 'create' : 'change'
         
     | 
| 
      
 57 
     | 
    
         
            +
                  migration_template "#{template}_table.rb", "db/migrate/#{file_name}.rb"
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  # case file_name
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # when /join_table/
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #   if attributes.length == 2
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #     @migration_action = 'join'
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #     @join_tables      = if pluralize_table_names?
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #                           attributes.map(&:plural_name)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  #                         else
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #                           attributes.map(&:singular_name)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  #                         end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  #     set_index_names
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                def set_index_names
         
     | 
| 
      
 74 
     | 
    
         
            +
                  attributes.each_with_index do |att, i|
         
     | 
| 
      
 75 
     | 
    
         
            +
                    att.index_name = [att, attributes[i - 1]].map { |a| index_name_for(a) }
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                def index_name_for(attribute)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  if attribute.foreign_key?
         
     | 
| 
      
 81 
     | 
    
         
            +
                    attribute.name
         
     | 
| 
      
 82 
     | 
    
         
            +
                  else
         
     | 
| 
      
 83 
     | 
    
         
            +
                    attribute.name.singularize.foreign_key
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end.to_sym
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                private
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                # def attributes_with_index
         
     | 
| 
      
 90 
     | 
    
         
            +
                #   attributes.select { |a| !a.reference? && a.has_index? }
         
     | 
| 
      
 91 
     | 
    
         
            +
                # end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                def old_migrations
         
     | 
| 
      
 94 
     | 
    
         
            +
                  ActiveRecord::Migrator.get_all_versions
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                # def validate_file_name!
         
     | 
| 
      
 98 
     | 
    
         
            +
                #   unless file_name =~ /^[_a-z0-9]+$/
         
     | 
| 
      
 99 
     | 
    
         
            +
                #     fail IllegalMigrationNameError, file_name
         
     | 
| 
      
 100 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 101 
     | 
    
         
            +
                # end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                def self.next_migration_number(dirname)
         
     | 
| 
      
 104 
     | 
    
         
            +
                  next_migration_number = current_migration_number(dirname) + 1
         
     | 
| 
      
 105 
     | 
    
         
            +
                  ActiveRecord::Migration.next_migration_number(next_migration_number)
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
              end
         
     | 
| 
      
 108 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class <%= migration_class_name %> < ActiveRecord::Migration
         
     | 
| 
      
 2 
     | 
    
         
            +
              def change
         
     | 
| 
      
 3 
     | 
    
         
            +
            <%- fields.add.each do |field| -%>
         
     | 
| 
      
 4 
     | 
    
         
            +
              <%- if field.reference? -%>
         
     | 
| 
      
 5 
     | 
    
         
            +
                add_reference :<%= table_name %>, :<%= field.name %><%= field.opts_text %>
         
     | 
| 
      
 6 
     | 
    
         
            +
                <%- unless field.polymorphic? -%>
         
     | 
| 
      
 7 
     | 
    
         
            +
                add_foreign_key :<%= table_name %>, :<%= field.name.pluralize %>
         
     | 
| 
      
 8 
     | 
    
         
            +
                <%- end -%>
         
     | 
| 
      
 9 
     | 
    
         
            +
              <%- end -%>
         
     | 
| 
      
 10 
     | 
    
         
            +
                add_column :<%= table_name %>, :<%= field.name %>, :<%= field.type %><%= field.opts_text %>
         
     | 
| 
      
 11 
     | 
    
         
            +
            <%- end -%>
         
     | 
| 
      
 12 
     | 
    
         
            +
            <%- fields.change.each do |field| -%>
         
     | 
| 
      
 13 
     | 
    
         
            +
                change_column :<%= table_name %>, :<%= field.name %>, :<%= field.type %><%= field.opts_text %>
         
     | 
| 
      
 14 
     | 
    
         
            +
            <%- end -%>
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            <%- indexes.remove do |index| -%>
         
     | 
| 
      
 17 
     | 
    
         
            +
                remove_index :<%= table_name %>, <%= index.fields_text %>
         
     | 
| 
      
 18 
     | 
    
         
            +
            <%- end -%>
         
     | 
| 
      
 19 
     | 
    
         
            +
            <%- fields.remove.each do |field| -%>
         
     | 
| 
      
 20 
     | 
    
         
            +
                remove_column :<%= table_name %>, :<%= field.name %>
         
     | 
| 
      
 21 
     | 
    
         
            +
            <%- end -%>
         
     | 
| 
      
 22 
     | 
    
         
            +
            <%- indexes.add.each do |index| -%>
         
     | 
| 
      
 23 
     | 
    
         
            +
                add_index :<%= table_name %>, <%= index.fields_text %><%= index.opts_text %>
         
     | 
| 
      
 24 
     | 
    
         
            +
            <%- end -%>
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            <%- if migration_action == 'join' -%>
         
     | 
| 
      
 27 
     | 
    
         
            +
                create_join_table :<%= join_tables.first %>, :<%= join_tables.second %> do |t|
         
     | 
| 
      
 28 
     | 
    
         
            +
                <%- fields.each do |field| -%>
         
     | 
| 
      
 29 
     | 
    
         
            +
                  <%= '# ' unless field.has_index? -%>t.index <%= field.index_name %><%= field.opts_text %>
         
     | 
| 
      
 30 
     | 
    
         
            +
                <%- end -%>
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            <%- end -%>
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class <%= migration_class_name %> < ActiveRecord::Migration
         
     | 
| 
      
 2 
     | 
    
         
            +
              def change
         
     | 
| 
      
 3 
     | 
    
         
            +
                create_table :<%= table_name %> do |t|
         
     | 
| 
      
 4 
     | 
    
         
            +
            <% fields.add.each do |field| -%>
         
     | 
| 
      
 5 
     | 
    
         
            +
                  t.<%= field.type %> :<%= field.name %><%= field.opts_text %>
         
     | 
| 
      
 6 
     | 
    
         
            +
            <% end -%>
         
     | 
| 
      
 7 
     | 
    
         
            +
            <% if options[:timestamps] %>
         
     | 
| 
      
 8 
     | 
    
         
            +
                  t.timestamps null: false
         
     | 
| 
      
 9 
     | 
    
         
            +
            <% end -%>
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
            <% indexes.add.each do |index| -%>
         
     | 
| 
      
 12 
     | 
    
         
            +
                add_index :<%= table_name %>, <%= index.fields_text %><%= index.opts_text %>
         
     | 
| 
      
 13 
     | 
    
         
            +
            <% end -%>
         
     | 
| 
      
 14 
     | 
    
         
            +
            <% fields.add.select(&:reference?).reject(&:polymorphic?).each do |field| -%>
         
     | 
| 
      
 15 
     | 
    
         
            +
                add_foreign_key :<%= table_name %>, :<%= field.name.pluralize %>
         
     | 
| 
      
 16 
     | 
    
         
            +
            <% end -%>
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Schemaless
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Generates schemaless setup for rails app
         
     | 
| 
      
 3 
     | 
    
         
            +
              class SetupGenerator < Rails::Generators::Base
         
     | 
| 
      
 4 
     | 
    
         
            +
                source_root File.expand_path('../templates', __FILE__)
         
     | 
| 
      
 5 
     | 
    
         
            +
                argument :attributes, type: :array, default: [], banner: 'path'
         
     | 
| 
      
 6 
     | 
    
         
            +
                desc 'Schemaless config files generator!'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def create_config_file
         
     | 
| 
      
 9 
     | 
    
         
            +
                  application 'end'
         
     | 
| 
      
 10 
     | 
    
         
            +
                  application '  Schemaless::Worker.run!'
         
     | 
| 
      
 11 
     | 
    
         
            +
                  application '  Rails.application.eager_load!'
         
     | 
| 
      
 12 
     | 
    
         
            +
                  application 'config.to_prepare do'
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # initializer | application
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # copy 'schemaless.rb'
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,76 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_support/concern'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'active_support/core_ext/hash/keys'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Schemaless
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              # Extend ActiveRecord for #field
         
     | 
| 
      
 7 
     | 
    
         
            +
              #
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Fields
         
     | 
| 
      
 9 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                # Schemaless ActiveRecord fields
         
     | 
| 
      
 12 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 13 
     | 
    
         
            +
                  AR_OPTS = ::Schemaless::Field::VALID_OPTS - [:index, :type]
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def schemaless_fields
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @schemaless_fields ||= []
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  #
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # field(*)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # Gets all fields in the model in the schamless_fields array.
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #     field :name                # Defaults String
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #     field :cylinders, Integer  # Use Class or :symbols
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #     field :type, index: true, default: nil, limit: 5
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #
         
     | 
| 
      
 28 
     | 
    
         
            +
                  #
         
     | 
| 
      
 29 
     | 
    
         
            +
                  def field(*params)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    config = params.extract_options!
         
     | 
| 
      
 31 
     | 
    
         
            +
                    config.assert_valid_keys(*::Schemaless::Field::VALID_OPTS)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    type = config.delete(:type)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    type ||= params.size > 1 ? params.pop : :string # TBD
         
     | 
| 
      
 34 
     | 
    
         
            +
                    name = params.join
         
     | 
| 
      
 35 
     | 
    
         
            +
                    schemaless_fields <<
         
     | 
| 
      
 36 
     | 
    
         
            +
                      ::Schemaless::Field.new(name, type, config)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  #
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # Create the belongs_to foreign keys
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #
         
     | 
| 
      
 42 
     | 
    
         
            +
                  def belongs_to(*params)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    config = params.extract_options!
         
     | 
| 
      
 44 
     | 
    
         
            +
                    name = "#{params.join}_id"
         
     | 
| 
      
 45 
     | 
    
         
            +
                    schemaless_fields <<
         
     | 
| 
      
 46 
     | 
    
         
            +
                      ::Schemaless::Field.new(name, :integer, config)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    super(*params)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  #
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # Helper for timestamps
         
     | 
| 
      
 52 
     | 
    
         
            +
                  #
         
     | 
| 
      
 53 
     | 
    
         
            +
                  def timestamps(*params)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    config = params.extract_options!
         
     | 
| 
      
 55 
     | 
    
         
            +
                    type = config[:type] || :timestamp
         
     | 
| 
      
 56 
     | 
    
         
            +
                    schemaless_fields << ::Schemaless::Field.new(:created_at, type, null: false)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    schemaless_fields << ::Schemaless::Field.new(:updated_at, type, null: true)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    return unless config[:paranoid]
         
     | 
| 
      
 59 
     | 
    
         
            +
                    schemaless_fields << ::Schemaless::Field.new(:deleted_at, type, null: true)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  #
         
     | 
| 
      
 63 
     | 
    
         
            +
                  # Get all fields in a schemaless way
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #
         
     | 
| 
      
 65 
     | 
    
         
            +
                  def current_attributes
         
     | 
| 
      
 66 
     | 
    
         
            +
                    columns_hash.map do |k, v|
         
     | 
| 
      
 67 
     | 
    
         
            +
                      next if v.primary
         
     | 
| 
      
 68 
     | 
    
         
            +
                      opts = AR_OPTS.reduce({}) do |a, e|
         
     | 
| 
      
 69 
     | 
    
         
            +
                        v.send(e) ? a.merge(e => v.send(e)) : a
         
     | 
| 
      
 70 
     | 
    
         
            +
                      end
         
     | 
| 
      
 71 
     | 
    
         
            +
                      ::Schemaless::Field.new(k, v.type, opts)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end.reject!(&:nil?)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_support/concern'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'active_support/core_ext/hash/keys'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Schemaless
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              # Extend ActiveRecord for #index
         
     | 
| 
      
 7 
     | 
    
         
            +
              #
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Indexes
         
     | 
| 
      
 9 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                # Schemaless ActiveRecord indexes
         
     | 
| 
      
 12 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def schemaless_indexes
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @schemaless_indexes ||= []
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  #
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # index(*)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #     index :name
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #     index [:one, :other]
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #     index :name, unique: true
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #
         
     | 
| 
      
 26 
     | 
    
         
            +
                  def index(*params)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    config = params.extract_options!
         
     | 
| 
      
 28 
     | 
    
         
            +
                    name = config.delete(:name)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    schemaless_indexes <<
         
     | 
| 
      
 30 
     | 
    
         
            +
                      ::Schemaless::Index.new(params, name, config)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  #
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # Get all indexes in a schemaless way
         
     | 
| 
      
 35 
     | 
    
         
            +
                  #
         
     | 
| 
      
 36 
     | 
    
         
            +
                  def current_indexes
         
     | 
| 
      
 37 
     | 
    
         
            +
                    ::ActiveRecord::Base.connection.indexes(table_name).map do |i|
         
     | 
| 
      
 38 
     | 
    
         
            +
                      opts = ::Schemaless::Index::VALID_OPTS.reduce({}) do |a, e|
         
     | 
| 
      
 39 
     | 
    
         
            +
                        i.send(e) ? a.merge(e => i.send(e)) : a
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
                      ::Schemaless::Index.new(i.columns, i.name, opts)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
              end # ActiveRecord
         
     | 
| 
      
 46 
     | 
    
         
            +
            end # Schemaless
         
     | 
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_support/concern'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Schemaless
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Stubs for production mode
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Stubs
         
     | 
| 
      
 6 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                # Schemaless ActiveRecord Stub
         
     | 
| 
      
 9 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 10 
     | 
    
         
            +
                  def field(*)     end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def index(*)     end
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
              end # Stubs
         
     | 
| 
      
 15 
     | 
    
         
            +
            end # Schemaless
         
     | 
| 
         @@ -0,0 +1,94 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Schemaless
         
     | 
| 
      
 2 
     | 
    
         
            +
              #
         
     | 
| 
      
 3 
     | 
    
         
            +
              # Fields
         
     | 
| 
      
 4 
     | 
    
         
            +
              #
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Field
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_accessor :name, :type, :opts, :default, :index
         
     | 
| 
      
 7 
     | 
    
         
            +
                VALID_OPTS = [:type, :limit, :precision, :scale, :null, :default, :index]
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                #
         
     | 
| 
      
 10 
     | 
    
         
            +
                # Field - name, type, opts: [:default, :null, :unique]
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                def initialize(name, type, opts = {})
         
     | 
| 
      
 13 
     | 
    
         
            +
                  fail InvalidArgument, 'opts must be a hash' unless opts.is_a?(Hash)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @name = name.to_s
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @type = map_field type
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @opts = opts.select { |_k, v| v.present? }
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @opts[:null] = true unless @opts[:null].present?
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @opts[:limit] = 255 unless @opts[:limit].present? || @type != :string
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def ==(other)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  name == other.name #  && type == other.type
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def reference?
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def opts_text
         
     | 
| 
      
 29 
     | 
    
         
            +
                  txt = opts.map { |k, v| "#{k}: #{v}" }.join(', ')
         
     | 
| 
      
 30 
     | 
    
         
            +
                  txt.empty? ? '' : ", #{txt}"
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 34 
     | 
    
         
            +
                  name
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                #
         
     | 
| 
      
 38 
     | 
    
         
            +
                # Add Fields
         
     | 
| 
      
 39 
     | 
    
         
            +
                #
         
     | 
| 
      
 40 
     | 
    
         
            +
                def add!(table)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  puts "++ Adding '#{self}' to '#{table}'"
         
     | 
| 
      
 42 
     | 
    
         
            +
                  return if Schemaless.sandbox
         
     | 
| 
      
 43 
     | 
    
         
            +
                  ::ActiveRecord::Migration.add_column(table.name, name, type, opts)
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                #
         
     | 
| 
      
 47 
     | 
    
         
            +
                # Delete Fields
         
     | 
| 
      
 48 
     | 
    
         
            +
                #
         
     | 
| 
      
 49 
     | 
    
         
            +
                def remove!(table)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  puts "-- Removing '#{self}' from '#{table}'"
         
     | 
| 
      
 51 
     | 
    
         
            +
                  return if Schemaless.sandbox
         
     | 
| 
      
 52 
     | 
    
         
            +
                  ::ActiveRecord::Migration.remove_column(table.name, name)
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                #
         
     | 
| 
      
 56 
     | 
    
         
            +
                # Change Fields
         
     | 
| 
      
 57 
     | 
    
         
            +
                #
         
     | 
| 
      
 58 
     | 
    
         
            +
                def change!(table)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  return if Schemaless.sandbox
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # ::ActiveRecord::Migration.change_column(table, name)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  # ::ActiveRecord::Migration.change_column_null(table, name)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # ::ActiveRecord::Migration.change_column_default(table, name)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  ::ActiveRecord::Migration.change_column(table.name, name, type, opts)
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                #
         
     | 
| 
      
 67 
     | 
    
         
            +
                # binary    # boolean
         
     | 
| 
      
 68 
     | 
    
         
            +
                # date      # datetime
         
     | 
| 
      
 69 
     | 
    
         
            +
                # time      # timestamp
         
     | 
| 
      
 70 
     | 
    
         
            +
                # integer   # primary_key    # references
         
     | 
| 
      
 71 
     | 
    
         
            +
                # decimal   # float
         
     | 
| 
      
 72 
     | 
    
         
            +
                # string    # text
         
     | 
| 
      
 73 
     | 
    
         
            +
                # hstore
         
     | 
| 
      
 74 
     | 
    
         
            +
                # json
         
     | 
| 
      
 75 
     | 
    
         
            +
                # array
         
     | 
| 
      
 76 
     | 
    
         
            +
                # cidr_address
         
     | 
| 
      
 77 
     | 
    
         
            +
                # ip_address
         
     | 
| 
      
 78 
     | 
    
         
            +
                # mac_address
         
     | 
| 
      
 79 
     | 
    
         
            +
                #
         
     | 
| 
      
 80 
     | 
    
         
            +
                def map_field(field) # rubocop:disable Metrics/MethodLength
         
     | 
| 
      
 81 
     | 
    
         
            +
                  return field if field.is_a?(Symbol)
         
     | 
| 
      
 82 
     | 
    
         
            +
                  case field.to_s
         
     | 
| 
      
 83 
     | 
    
         
            +
                  when /Integer|Fixnum|Numeric/ then :integer
         
     | 
| 
      
 84 
     | 
    
         
            +
                  when /BigDecimal|Rational/ then :decimal
         
     | 
| 
      
 85 
     | 
    
         
            +
                  when /Float/      then :float
         
     | 
| 
      
 86 
     | 
    
         
            +
                  when /DateTime/   then :datetime
         
     | 
| 
      
 87 
     | 
    
         
            +
                  when /Date/       then :date
         
     | 
| 
      
 88 
     | 
    
         
            +
                  when /Time/       then :timestamp
         
     | 
| 
      
 89 
     | 
    
         
            +
                  else
         
     | 
| 
      
 90 
     | 
    
         
            +
                    :string
         
     | 
| 
      
 91 
     | 
    
         
            +
                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
      
 93 
     | 
    
         
            +
              end
         
     | 
| 
      
 94 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,59 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Schemaless
         
     | 
| 
      
 2 
     | 
    
         
            +
              #
         
     | 
| 
      
 3 
     | 
    
         
            +
              # Stores indexes
         
     | 
| 
      
 4 
     | 
    
         
            +
              #
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Index
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_accessor :fields, :name, :opts
         
     | 
| 
      
 7 
     | 
    
         
            +
                VALID_OPTS = [:unique, :orders]
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(fields, name = nil, opts = {})
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @fields = [fields].flatten
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @fields = @fields.first if @fields.size == 1
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @name = name || opts[:name]
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @opts = opts.select { |_k, v| v.present?  }
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @opts.merge!(name: @name) if @name
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def opts_text
         
     | 
| 
      
 18 
     | 
    
         
            +
                  txt = opts.map { |k, v| "#{k}: #{v}" }.join(', ')
         
     | 
| 
      
 19 
     | 
    
         
            +
                  txt.empty? ? '' : ", #{txt}"
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def fields_text
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @fields.inspect
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 27 
     | 
    
         
            +
                  name
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def ==(other)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  name == other.name
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                #
         
     | 
| 
      
 35 
     | 
    
         
            +
                # Add Indexes
         
     | 
| 
      
 36 
     | 
    
         
            +
                #
         
     | 
| 
      
 37 
     | 
    
         
            +
                def add!(table)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  return if Schemaless.sandbox
         
     | 
| 
      
 39 
     | 
    
         
            +
                  ::ActiveRecord::Migration.add_index(table.name, fields, opts)
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                #
         
     | 
| 
      
 43 
     | 
    
         
            +
                # Delete Indexes
         
     | 
| 
      
 44 
     | 
    
         
            +
                #
         
     | 
| 
      
 45 
     | 
    
         
            +
                def remove!(table)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  return if Schemaless.sandbox
         
     | 
| 
      
 47 
     | 
    
         
            +
                  key = name ? { name: name } : { column: fields }
         
     | 
| 
      
 48 
     | 
    
         
            +
                  ::ActiveRecord::Migration.remove_index(table.name, key)
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                #
         
     | 
| 
      
 52 
     | 
    
         
            +
                # Change Indexes
         
     | 
| 
      
 53 
     | 
    
         
            +
                #
         
     | 
| 
      
 54 
     | 
    
         
            +
                def change!(table)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  return if Schemaless.sandbox
         
     | 
| 
      
 56 
     | 
    
         
            +
                  ::ActiveRecord::Migration.change_index(table.name, name, type, opts)
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Rails 3 initialization
         
     | 
| 
      
 2 
     | 
    
         
            +
            module Schemaless
         
     | 
| 
      
 3 
     | 
    
         
            +
              require 'rails'
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Rails include
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Railtie < Rails::Railtie
         
     | 
| 
      
 6 
     | 
    
         
            +
                initializer 'schemaless.insert_into_active_record' do
         
     | 
| 
      
 7 
     | 
    
         
            +
                  ActiveSupport.on_load :active_record do
         
     | 
| 
      
 8 
     | 
    
         
            +
                    if Rails.env =~ /production/
         
     | 
| 
      
 9 
     | 
    
         
            +
                      require 'schemaless/ar/stubs'
         
     | 
| 
      
 10 
     | 
    
         
            +
                      ::ActiveRecord::Base.send :include, Schemaless::Stubs
         
     | 
| 
      
 11 
     | 
    
         
            +
                    else
         
     | 
| 
      
 12 
     | 
    
         
            +
                      require 'schemaless/ar/fields'
         
     | 
| 
      
 13 
     | 
    
         
            +
                      require 'schemaless/ar/indexes'
         
     | 
| 
      
 14 
     | 
    
         
            +
                      ::ActiveRecord::Base.send :include, Schemaless::Fields
         
     | 
| 
      
 15 
     | 
    
         
            +
                      ::ActiveRecord::Base.send :include, Schemaless::Indexes
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
                rake_tasks do
         
     | 
| 
      
 20 
     | 
    
         
            +
                  load 'tasks/schemaless_tasks.rake'
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     |