schema_plus_default_expr 0.1.0
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/.gitignore +9 -0
- data/.travis.yml +17 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +118 -0
- data/Rakefile +9 -0
- data/gemfiles/Gemfile.base +4 -0
- data/gemfiles/activerecord-4.2/Gemfile.base +3 -0
- data/gemfiles/activerecord-4.2/Gemfile.postgresql +10 -0
- data/gemfiles/activerecord-4.2/Gemfile.sqlite3 +10 -0
- data/lib/schema_plus/default_expr/active_record/connection_adapters/abstract_adapter.rb +13 -0
- data/lib/schema_plus/default_expr/active_record/connection_adapters/column.rb +14 -0
- data/lib/schema_plus/default_expr/active_record/connection_adapters/postgresql_adapter.rb +18 -0
- data/lib/schema_plus/default_expr/active_record/connection_adapters/sqlite3_adapter.rb +19 -0
- data/lib/schema_plus/default_expr/middleware.rb +55 -0
- data/lib/schema_plus/default_expr/version.rb +5 -0
- data/lib/schema_plus/default_expr.rb +10 -0
- data/lib/schema_plus_default_expr.rb +1 -0
- data/schema_dev.yml +7 -0
- data/schema_plus_default_expr.gemspec +29 -0
- data/spec/column_default_spec.rb +127 -0
- data/spec/migration_spec.rb +44 -0
- data/spec/schema_dumper_spec.rb +113 -0
- data/spec/spec_helper.rb +33 -0
- metadata +191 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 233c5f272e73d93ee11a5689c290511864c4e613
|
4
|
+
data.tar.gz: b5989731ef1ccb2cd48b8d3e75c591d2bb3a57ec
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 37137a6e9c15d2873bcd7b2fc0b37c1e13e9d3efe7838c520d1f3f748e417015fd026c2cf650ea117c9aa7c9a17c48319de9eb66dd38da8328dea40b171b968a
|
7
|
+
data.tar.gz: 5dc9dc12ca8166865a7867220ac324e48eabc81d0c9ef873934a900ad0a15646f5610dfab46ac6d134c83891c235ebb574fa968e6cae83ea5f853f967ad6d642
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was auto-generated by the schema_dev tool, based on the data in
|
2
|
+
# ./schema_dev.yml
|
3
|
+
# Please do not edit this file; any changes will be overwritten next time
|
4
|
+
# schema_dev gets run.
|
5
|
+
---
|
6
|
+
sudo: false
|
7
|
+
rvm:
|
8
|
+
- 2.1.5
|
9
|
+
gemfile:
|
10
|
+
- gemfiles/activerecord-4.2/Gemfile.postgresql
|
11
|
+
- gemfiles/activerecord-4.2/Gemfile.sqlite3
|
12
|
+
env: POSTGRESQL_DB_USER=postgres
|
13
|
+
addons:
|
14
|
+
postgresql: '9.3'
|
15
|
+
before_script: bundle exec rake create_databases
|
16
|
+
after_script: bundle exec rake drop_databases
|
17
|
+
script: bundle exec rake travis
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 ronen barzel
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
[](http://badge.fury.io/rb/schema_plus_default_expr)
|
2
|
+
[](http://travis-ci.org/SchemaPlus/schema_plus_default_expr)
|
3
|
+
[](https://coveralls.io/r/SchemaPlus/schema_plus_default_expr)
|
4
|
+
[](https://gemnasium.com/SchemaPlus/schema_plus_default_expr)
|
5
|
+
|
6
|
+
# SchemaPlus::DefaultExpr
|
7
|
+
|
8
|
+
SchemaPlus::DefaultExpr extends ActiveRecord's migrations to allow you to set the default value of a column to an SQL expression.
|
9
|
+
|
10
|
+
This gem works with PostgreSQL and Sqlite3, but not MySQL; see [Compatibility](#compatibility)below.
|
11
|
+
|
12
|
+
SchemaPlus::DefaultExpr is part of the [SchemaPlus](https://github.com/SchemaPlus/) family of Ruby on Rails ActiveRecord extension gems.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
<!-- SCHEMA_DEV: TEMPLATE INSTALLATION - begin -->
|
17
|
+
<!-- These lines are auto-inserted from a schema_dev template -->
|
18
|
+
As usual:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem "schema_plus_default_expr" # in a Gemfile
|
22
|
+
gem.add_dependency "schema_plus_default_expr" # in a .gemspec
|
23
|
+
```
|
24
|
+
|
25
|
+
<!-- SCHEMA_DEV: TEMPLATE INSTALLATION - end -->
|
26
|
+
|
27
|
+
## <a name="compatibility"></a>Compatibility
|
28
|
+
|
29
|
+
SchemaPlus::DefaultExpr is tested on:
|
30
|
+
|
31
|
+
<!-- SCHEMA_DEV: MATRIX - begin -->
|
32
|
+
<!-- These lines are auto-generated by schema_dev based on schema_dev.yml -->
|
33
|
+
* ruby **2.1.5** with activerecord **4.2**, using **sqlite3** and **postgresql**
|
34
|
+
|
35
|
+
<!-- SCHEMA_DEV: MATRIX - end -->
|
36
|
+
|
37
|
+
MySQL only supports SQL expression defaults for `TIMESTAMP` column types, which ActiveRecord does not use. So SchemaPlus::DefaultExpr does not work with MySQL.
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
SchemaPlus::DefaultExpr augments the syntax for setting column defaults, to support expressions or constant values:
|
42
|
+
|
43
|
+
t.datetime :seen_at, default: { expr: 'NOW()' }
|
44
|
+
t.datetime :seen_at, default: { value: "2011-12-11 00:00:00" }
|
45
|
+
|
46
|
+
The standard syntax will still work as usual:
|
47
|
+
|
48
|
+
t.datetime :seen_at, default: "2011-12-11 00:00:00"
|
49
|
+
|
50
|
+
Also, as a convenience
|
51
|
+
|
52
|
+
t.datetime :seen_at, default: :now
|
53
|
+
|
54
|
+
resolves to:
|
55
|
+
|
56
|
+
NOW() # PostgreSQL
|
57
|
+
(DATETIME('now')) # SQLite3
|
58
|
+
invalid # MySQL
|
59
|
+
|
60
|
+
### Note on PostgreSQL & json:
|
61
|
+
|
62
|
+
If you are using Postgresql with a `json` column, ActiveRecord allows you to use a Hash for a default value. Be aware that if the hash contains just one key which is `:expr` or `:value`, then SchemaPlus::DefaultExpr will interpret, and use the corresponding value for the default. That is, these are equivalent:
|
63
|
+
|
64
|
+
t.json :fields, default: { value: { field1: 'a', field2: 'b' } }
|
65
|
+
t.json :fields, default: { field1: 'a', field2: 'b' }
|
66
|
+
|
67
|
+
|
68
|
+
## History
|
69
|
+
|
70
|
+
* 0.1.0 - Initial release, extracted from schema_plus 1.x
|
71
|
+
|
72
|
+
## Development & Testing
|
73
|
+
|
74
|
+
Are you interested in contributing to SchemaPlus::DefaultExpr? Thanks! Please follow
|
75
|
+
the standard protocol: fork, feature branch, develop, push, and issue pull
|
76
|
+
request.
|
77
|
+
|
78
|
+
Some things to know about to help you develop and test:
|
79
|
+
|
80
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_DEV - begin -->
|
81
|
+
<!-- These lines are auto-inserted from a schema_dev template -->
|
82
|
+
* **schema_dev**: SchemaPlus::DefaultExpr uses [schema_dev](https://github.com/SchemaPlus/schema_dev) to
|
83
|
+
facilitate running rspec tests on the matrix of ruby, activerecord, and database
|
84
|
+
versions that the gem supports, both locally and on
|
85
|
+
[travis-ci](http://travis-ci.org/SchemaPlus/schema_plus_default_expr)
|
86
|
+
|
87
|
+
To to run rspec locally on the full matrix, do:
|
88
|
+
|
89
|
+
$ schema_dev bundle install
|
90
|
+
$ schema_dev rspec
|
91
|
+
|
92
|
+
You can also run on just one configuration at a time; For info, see `schema_dev --help` or the [schema_dev](https://github.com/SchemaPlus/schema_dev) README.
|
93
|
+
|
94
|
+
The matrix of configurations is specified in `schema_dev.yml` in
|
95
|
+
the project root.
|
96
|
+
|
97
|
+
|
98
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_DEV - end -->
|
99
|
+
|
100
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_PLUS_CORE - begin -->
|
101
|
+
<!-- These lines are auto-inserted from a schema_dev template -->
|
102
|
+
* **schema_plus_core**: SchemaPlus::DefaultExpr uses the SchemaPlus::Core API that
|
103
|
+
provides middleware callback stacks to make it easy to extend
|
104
|
+
ActiveRecord's behavior. If that API is missing something you need for
|
105
|
+
your contribution, please head over to
|
106
|
+
[schema_plus_core](https://github.com/SchemaPlus/schema_plus_core) and open
|
107
|
+
an issue or pull request.
|
108
|
+
|
109
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_PLUS_CORE - end -->
|
110
|
+
|
111
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - begin -->
|
112
|
+
<!-- These lines are auto-inserted from a schema_dev template -->
|
113
|
+
* **schema_monkey**: SchemaPlus::DefaultExpr is implemented as a
|
114
|
+
[schema_monkey](https://github.com/SchemaPlus/schema_monkey) client,
|
115
|
+
using [schema_monkey](https://github.com/SchemaPlus/schema_monkey)'s
|
116
|
+
convention-based protocols for extending ActiveRecord and using middleware stacks.
|
117
|
+
|
118
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - end -->
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module SchemaPlus::DefaultExpr
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module AbstractAdapter
|
5
|
+
def sql_for_function(function)
|
6
|
+
# Default nil implementation to be overriden by db adapters.
|
7
|
+
# (Keep this here to avoid failure if gem is loaded with mysql2 or
|
8
|
+
# other non-supported db adapters.)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SchemaPlus::DefaultExpr
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module PostgresqlAdapter
|
5
|
+
def default_expr_valid?(expr)
|
6
|
+
true # arbitrary sql is okay in PostgreSQL
|
7
|
+
end
|
8
|
+
|
9
|
+
def sql_for_function(function)
|
10
|
+
case function
|
11
|
+
when :now
|
12
|
+
"NOW()"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SchemaPlus::DefaultExpr
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module Sqlite3Adapter
|
5
|
+
|
6
|
+
def default_expr_valid?(expr)
|
7
|
+
true # arbitrary sql is okay
|
8
|
+
end
|
9
|
+
|
10
|
+
def sql_for_function(function)
|
11
|
+
case function
|
12
|
+
when :now
|
13
|
+
"(DATETIME('now'))"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module SchemaPlus::DefaultExpr
|
2
|
+
module Middleware
|
3
|
+
|
4
|
+
module Sql
|
5
|
+
module ColumnOptions
|
6
|
+
|
7
|
+
# Add options for default expressions
|
8
|
+
def before(env)
|
9
|
+
options = env.options
|
10
|
+
|
11
|
+
return unless (default = options[:default])
|
12
|
+
|
13
|
+
if default.is_a? Hash and [[:expr], [:value]].include?(default.keys)
|
14
|
+
value = default[:value]
|
15
|
+
expr = env.connection.sql_for_function(default[:expr]) || default[:expr] if default[:expr]
|
16
|
+
else
|
17
|
+
value = default
|
18
|
+
expr = env.connection.sql_for_function(default)
|
19
|
+
end
|
20
|
+
|
21
|
+
if expr
|
22
|
+
raise ArgumentError, "Invalid default expression" unless env.connection.default_expr_valid?(expr)
|
23
|
+
env.sql << " DEFAULT #{expr}"
|
24
|
+
# must explicitly check for :null to allow change_column to work on migrations
|
25
|
+
if options[:null] == false
|
26
|
+
env.sql << " NOT NULL"
|
27
|
+
end
|
28
|
+
options.delete(:default)
|
29
|
+
options.delete(:null)
|
30
|
+
else
|
31
|
+
options[:default] = value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module Dumper
|
38
|
+
module Table
|
39
|
+
|
40
|
+
# Emit default expression options in dump
|
41
|
+
def after(env)
|
42
|
+
env.connection.columns(env.table.name).each do |column|
|
43
|
+
if !column.default_function.nil?
|
44
|
+
if col = env.table.columns.find(&its.name == column.name)
|
45
|
+
options = "default: { expr: #{column.default_function.inspect} }"
|
46
|
+
options += ", #{col.options}" unless col.options.blank?
|
47
|
+
col.options = options
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'schema_plus/core'
|
2
|
+
|
3
|
+
require_relative 'default_expr/version'
|
4
|
+
require_relative 'default_expr/middleware'
|
5
|
+
require_relative 'default_expr/active_record/connection_adapters/abstract_adapter'
|
6
|
+
require_relative 'default_expr/active_record/connection_adapters/column'
|
7
|
+
require_relative 'default_expr/active_record/connection_adapters/postgresql_adapter'
|
8
|
+
require_relative 'default_expr/active_record/connection_adapters/sqlite3_adapter'
|
9
|
+
|
10
|
+
SchemaMonkey.register SchemaPlus::DefaultExpr
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'schema_plus/default_expr'
|
data/schema_dev.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'schema_plus/default_expr/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "schema_plus_default_expr"
|
8
|
+
gem.version = SchemaPlus::DefaultExpr::VERSION
|
9
|
+
gem.authors = ["ronen barzel"]
|
10
|
+
gem.email = ["ronen@barzel.org"]
|
11
|
+
gem.summary = %q{Extends ActiveRecord migrations to allow an SQL expression for the default value of a column}
|
12
|
+
gem.homepage = "https://github.com/SchemaPlus/schema_plus_default_expr"
|
13
|
+
gem.license = "MIT"
|
14
|
+
|
15
|
+
gem.files = `git ls-files -z`.split("\x0")
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "activerecord", "~> 4.2"
|
21
|
+
gem.add_dependency "schema_plus_core", "~> 0.2", ">= 0.2.1"
|
22
|
+
|
23
|
+
gem.add_development_dependency "bundler", "~> 1.7"
|
24
|
+
gem.add_development_dependency "rake", "~> 10.0"
|
25
|
+
gem.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
gem.add_development_dependency "schema_dev", "~> 3.4"
|
27
|
+
gem.add_development_dependency "simplecov"
|
28
|
+
gem.add_development_dependency "simplecov-gem-profile"
|
29
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Column definition" do
|
4
|
+
before(:each) do
|
5
|
+
define_schema do
|
6
|
+
create_table :models, :force => true do |t|
|
7
|
+
end
|
8
|
+
end
|
9
|
+
class Model < ::ActiveRecord::Base ; end
|
10
|
+
end
|
11
|
+
|
12
|
+
subject {
|
13
|
+
Model.connection.execute("INSERT INTO models (dummy) values (1)")
|
14
|
+
Model.last.reload.test_column
|
15
|
+
}
|
16
|
+
|
17
|
+
context "text columns" do
|
18
|
+
|
19
|
+
before(:each) do
|
20
|
+
@nowish = /(#{Time.now.utc.to_s.sub(/:[^:]+$/, '')}|#{Time.now.to_s.sub(/:[^:]+$/,'')}).*/
|
21
|
+
end
|
22
|
+
|
23
|
+
context "just default passed" do
|
24
|
+
before(:each) do
|
25
|
+
define_test_column(:string, :default => "2011-12-11 00:00:00")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should use the normal default" do
|
29
|
+
is_expected.to eq "2011-12-11 00:00:00"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "just default passed in hash" do
|
34
|
+
before(:each) do
|
35
|
+
define_test_column(:string, :default => { :value => "2011-12-11 00:00:00" })
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should use the normal default" do
|
39
|
+
is_expected.to eq "2011-12-11 00:00:00"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "default passed with no nulls" do
|
44
|
+
before(:each) do
|
45
|
+
define_test_column(:string, :default => "2011-12-11 00:00:00", null: false)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should use the normal default" do
|
49
|
+
is_expected.to eq "2011-12-11 00:00:00"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "default passed in hash with no nulls" do
|
54
|
+
before(:each) do
|
55
|
+
define_test_column(:string, :default => { :value => "2011-12-11 00:00:00" }, null: false)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should use the normal default" do
|
59
|
+
is_expected.to eq "2011-12-11 00:00:00"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "default function passed as :now" do
|
64
|
+
before(:each) do
|
65
|
+
define_test_column(:string, :default => :now)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should use NOW() as the default" do
|
69
|
+
is_expected.to match @nowish
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "default function passed as now with no nulls" do
|
74
|
+
before(:each) do
|
75
|
+
define_test_column(:string, :default => :now, null: false)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should use NOW() as the default" do
|
79
|
+
is_expected.to match @nowish
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "valid expr passed as default" do
|
84
|
+
it "uses the expression" do
|
85
|
+
define_test_column(:string, :default => { :expr => "(replace('THIS IS A TEST', 'TEST', 'DOG'))" })
|
86
|
+
is_expected.to eq "THIS IS A DOG"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
context "boolean column" do
|
93
|
+
|
94
|
+
context "passed as boolean false" do
|
95
|
+
before(:each) do
|
96
|
+
define_test_column :boolean, :default => false
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should give the default as false" do
|
100
|
+
is_expected.to eq false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "passed as boolean true" do
|
105
|
+
before(:each) do
|
106
|
+
define_test_column :boolean, :default => true
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should give the default as true" do
|
110
|
+
is_expected.to eq true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def define_test_column(type, *args)
|
118
|
+
ActiveRecord::Migration.suppress_messages do
|
119
|
+
ActiveRecord::Migration.create_table Model.table_name, :force => true do |t|
|
120
|
+
t.send type, :test_column, *args
|
121
|
+
t.integer :dummy
|
122
|
+
end
|
123
|
+
end
|
124
|
+
Model.reset_column_information
|
125
|
+
@column = Model.columns.first()
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRecord::Migration do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
define_schema do
|
7
|
+
create_table :posts, :force => true do |t|
|
8
|
+
t.string :content
|
9
|
+
end
|
10
|
+
end
|
11
|
+
class Post < ::ActiveRecord::Base ; end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when table is created" do
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
@model = Post
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should properly handle default values for booleans" do
|
21
|
+
expect {
|
22
|
+
recreate_table(@model) do |t|
|
23
|
+
t.boolean :bool, :default => true
|
24
|
+
end
|
25
|
+
}.to_not raise_error
|
26
|
+
expect(@model.create.reload.bool).to be true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should properly handle default values for json (#195)", :postgresql => :only do
|
30
|
+
recreate_table(@model) do |t|
|
31
|
+
t.json :json, :default => {}
|
32
|
+
end
|
33
|
+
expect(@model.create.reload.json).to eq({})
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def recreate_table(model, opts={}, &block)
|
39
|
+
ActiveRecord::Migration.suppress_messages do
|
40
|
+
ActiveRecord::Migration.create_table model.table_name, opts.merge(:force => true), &block
|
41
|
+
end
|
42
|
+
model.reset_column_information
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
describe "Schema dump" do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
ActiveRecord::Migration.suppress_messages do
|
8
|
+
ActiveRecord::Schema.define do
|
9
|
+
connection.tables.each do |table| drop_table table, force: :cascade end
|
10
|
+
|
11
|
+
create_table :posts, :force => true do |t|
|
12
|
+
t.text :body
|
13
|
+
t.integer :user_id
|
14
|
+
t.integer :first_comment_id
|
15
|
+
t.string :string_no_default
|
16
|
+
t.integer :short_id
|
17
|
+
t.string :str_short
|
18
|
+
t.integer :integer_col
|
19
|
+
t.float :float_col
|
20
|
+
t.decimal :decimal_col
|
21
|
+
t.datetime :datetime_col
|
22
|
+
t.timestamp :timestamp_col
|
23
|
+
t.time :time_col
|
24
|
+
t.date :date_col
|
25
|
+
t.binary :binary_col
|
26
|
+
t.boolean :boolean_col
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
class ::Post < ActiveRecord::Base ; end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with date default", :postgresql => :only do
|
35
|
+
it "should dump the default hash expr as now()" do
|
36
|
+
with_additional_column Post, :posted_at, :datetime, :default => :now do
|
37
|
+
expect(dump_posts).to match(%r{t\.datetime\s+"posted_at",\s*(?:default:|:default =>)\s*\{\s*(?:expr:|:expr\s*=>)\s*"now\(\)"\s*\}})
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should dump the default hash expr as CURRENT_TIMESTAMP" do
|
42
|
+
with_additional_column Post, :posted_at, :datetime, :default => {:expr => 'date \'2001-09-28\''} do
|
43
|
+
expect(dump_posts).to match(%r{t\.datetime\s+"posted_at",\s*(?:default:|:default =>).*2001-09-28.*})
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "can dump a complex default expression" do
|
48
|
+
with_additional_column Post, :name, :string, :default => {:expr => 'substring(random()::text from 3 for 6)'} do
|
49
|
+
expect(dump_posts).to match(%r{t\.string\s+"name",\s*(?:default:|:default\s*=>)\s*{\s*(?:expr:|:expr\s*=>)\s*"\\"substring\\"\(\(random\(\)\)::text, 3, 6\)"\s*}})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "with date default", :sqlite3 => :only do
|
55
|
+
it "should dump the default hash expr as now" do
|
56
|
+
with_additional_column Post, :posted_at, :datetime, :default => :now do
|
57
|
+
expect(dump_posts).to match(%r{t\.datetime\s+"posted_at",\s*(?:default:|:default =>)\s*\{\s*(?:expr:|:expr =>)\s*"\(DATETIME\('now'\)\)"\s*\}})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should dump the default hash expr string as now" do
|
62
|
+
with_additional_column Post, :posted_at, :datetime, :default => { :expr => "(DATETIME('now'))" } do
|
63
|
+
expect(dump_posts).to match(%r{t\.datetime\s+"posted_at",\s*(?:default:|:default =>)\s*\{\s*(?:expr:|:expr =>)\s*"\(DATETIME\('now'\)\)"\s*\}})
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should dump the default value normally" do
|
68
|
+
with_additional_column Post, :posted_at, :string, :default => "now" do
|
69
|
+
expect(dump_posts).to match(%r{t\.string\s*"posted_at",\s*(?:default:|:default =>)\s*"now"})
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should leave out :default when default was changed to null" do
|
75
|
+
ActiveRecord::Migration.suppress_messages do
|
76
|
+
ActiveRecord::Migration.change_column_default :posts, :string_no_default, nil
|
77
|
+
end
|
78
|
+
# mysql2 includes 'limit: 255' in the output. that's OK, just want to
|
79
|
+
# make sure the full line doesn't have 'default' in it.
|
80
|
+
expect(dump_posts).to match(%r{t\.string\s+"string_no_default"\s*(,\s*limit:\s*\d+)?$})
|
81
|
+
end
|
82
|
+
|
83
|
+
protected
|
84
|
+
def to_regexp(string)
|
85
|
+
Regexp.new(Regexp.escape(string))
|
86
|
+
end
|
87
|
+
|
88
|
+
def with_additional_column(model, column_name, column_type, options)
|
89
|
+
table_columns = model.columns.reject{|column| column.name == 'id'}
|
90
|
+
ActiveRecord::Migration.suppress_messages do
|
91
|
+
ActiveRecord::Migration.create_table model.table_name, :force => true do |t|
|
92
|
+
table_columns.each do |column|
|
93
|
+
t.column column.name, column.type, :default => column.default
|
94
|
+
end
|
95
|
+
t.column column_name, column_type, options
|
96
|
+
end
|
97
|
+
end
|
98
|
+
yield
|
99
|
+
end
|
100
|
+
|
101
|
+
def dump_schema(opts={})
|
102
|
+
stream = StringIO.new
|
103
|
+
ActiveRecord::SchemaDumper.ignore_tables = Array.wrap(opts[:ignore]) || []
|
104
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
105
|
+
stream.string
|
106
|
+
end
|
107
|
+
|
108
|
+
def dump_posts
|
109
|
+
dump_schema(:ignore => %w[users comments])
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'simplecov-gem-profile'
|
3
|
+
SimpleCov.start "gem"
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
|
+
|
8
|
+
require 'rspec'
|
9
|
+
require 'active_record'
|
10
|
+
require 'schema_plus_default_expr'
|
11
|
+
require 'schema_dev/rspec'
|
12
|
+
|
13
|
+
SchemaDev::Rspec.setup
|
14
|
+
|
15
|
+
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.warnings = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def define_schema(&block)
|
22
|
+
ActiveRecord::Migration.suppress_messages do
|
23
|
+
ActiveRecord::Schema.define do
|
24
|
+
connection.tables.each do |table|
|
25
|
+
drop_table table, force: :cascade
|
26
|
+
end
|
27
|
+
instance_eval &block
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
SimpleCov.command_name "[ruby#{RUBY_VERSION}-activerecord#{::ActiveRecord.version}-#{ActiveRecord::Base.connection.adapter_name}]"
|
metadata
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: schema_plus_default_expr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ronen barzel
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: schema_plus_core
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.2'
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 0.2.1
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0.2'
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.2.1
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bundler
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.7'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '1.7'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rake
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '10.0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '10.0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rspec
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '3.0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '3.0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: schema_dev
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '3.4'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '3.4'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: simplecov
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: simplecov-gem-profile
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
description:
|
132
|
+
email:
|
133
|
+
- ronen@barzel.org
|
134
|
+
executables: []
|
135
|
+
extensions: []
|
136
|
+
extra_rdoc_files: []
|
137
|
+
files:
|
138
|
+
- ".gitignore"
|
139
|
+
- ".travis.yml"
|
140
|
+
- Gemfile
|
141
|
+
- LICENSE.txt
|
142
|
+
- README.md
|
143
|
+
- Rakefile
|
144
|
+
- gemfiles/Gemfile.base
|
145
|
+
- gemfiles/activerecord-4.2/Gemfile.base
|
146
|
+
- gemfiles/activerecord-4.2/Gemfile.postgresql
|
147
|
+
- gemfiles/activerecord-4.2/Gemfile.sqlite3
|
148
|
+
- lib/schema_plus/default_expr.rb
|
149
|
+
- lib/schema_plus/default_expr/active_record/connection_adapters/abstract_adapter.rb
|
150
|
+
- lib/schema_plus/default_expr/active_record/connection_adapters/column.rb
|
151
|
+
- lib/schema_plus/default_expr/active_record/connection_adapters/postgresql_adapter.rb
|
152
|
+
- lib/schema_plus/default_expr/active_record/connection_adapters/sqlite3_adapter.rb
|
153
|
+
- lib/schema_plus/default_expr/middleware.rb
|
154
|
+
- lib/schema_plus/default_expr/version.rb
|
155
|
+
- lib/schema_plus_default_expr.rb
|
156
|
+
- schema_dev.yml
|
157
|
+
- schema_plus_default_expr.gemspec
|
158
|
+
- spec/column_default_spec.rb
|
159
|
+
- spec/migration_spec.rb
|
160
|
+
- spec/schema_dumper_spec.rb
|
161
|
+
- spec/spec_helper.rb
|
162
|
+
homepage: https://github.com/SchemaPlus/schema_plus_default_expr
|
163
|
+
licenses:
|
164
|
+
- MIT
|
165
|
+
metadata: {}
|
166
|
+
post_install_message:
|
167
|
+
rdoc_options: []
|
168
|
+
require_paths:
|
169
|
+
- lib
|
170
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
requirements: []
|
181
|
+
rubyforge_project:
|
182
|
+
rubygems_version: 2.2.2
|
183
|
+
signing_key:
|
184
|
+
specification_version: 4
|
185
|
+
summary: Extends ActiveRecord migrations to allow an SQL expression for the default
|
186
|
+
value of a column
|
187
|
+
test_files:
|
188
|
+
- spec/column_default_spec.rb
|
189
|
+
- spec/migration_spec.rb
|
190
|
+
- spec/schema_dumper_spec.rb
|
191
|
+
- spec/spec_helper.rb
|