object_id_gem 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +44 -0
- data/CHANGES.md +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +225 -0
- data/Rakefile +6 -0
- data/lib/objectid_columns.rb +127 -0
- data/lib/objectid_columns/active_record/base.rb +33 -0
- data/lib/objectid_columns/active_record/relation.rb +40 -0
- data/lib/objectid_columns/arel/visitors/to_sql.rb +88 -0
- data/lib/objectid_columns/dynamic_methods_module.rb +127 -0
- data/lib/objectid_columns/extensions.rb +41 -0
- data/lib/objectid_columns/has_objectid_columns.rb +47 -0
- data/lib/objectid_columns/objectid_columns_manager.rb +451 -0
- data/lib/objectid_columns/version.rb +4 -0
- data/object_id_gem.gemspec +71 -0
- data/spec/objectid_columns/helpers/database_helper.rb +178 -0
- data/spec/objectid_columns/helpers/system_helpers.rb +92 -0
- data/spec/objectid_columns/system/basic_system_spec.rb +600 -0
- data/spec/objectid_columns/system/extensions_spec.rb +69 -0
- metadata +194 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'objectid_columns/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "object_id_gem"
|
8
|
+
spec.version = ObjectidColumns::VERSION
|
9
|
+
spec.authors = ["Andrew Geweke"]
|
10
|
+
spec.email = ["ageweke@swiftype.com"]
|
11
|
+
spec.summary = %q{Transparently store MongoDB ObjectId values in ActiveRecord.}
|
12
|
+
spec.homepage = "https://www.github.com/swiftype/objectid_columns"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
|
21
|
+
ar_version = ENV['OBJECTID_COLUMNS_AR_TEST_VERSION']
|
22
|
+
ar_version = ar_version.strip if ar_version
|
23
|
+
|
24
|
+
version_spec = case ar_version
|
25
|
+
when nil then [ ">= 5.0"]
|
26
|
+
when 'master' then nil
|
27
|
+
else [ "=#{ar_version}" ]
|
28
|
+
end
|
29
|
+
|
30
|
+
if version_spec
|
31
|
+
spec.add_dependency("activerecord", *version_spec)
|
32
|
+
spec.add_dependency("activesupport", *version_spec)
|
33
|
+
end
|
34
|
+
|
35
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
36
|
+
spec.add_development_dependency "rake"
|
37
|
+
spec.add_development_dependency "rspec", "~> 2.14"
|
38
|
+
spec.add_development_dependency "moped", "~> 1.5" unless RUBY_VERSION =~ /^1\.8\./
|
39
|
+
spec.add_development_dependency "bson", "~> 1.9"
|
40
|
+
|
41
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec', 'objectid_columns', 'helpers', 'database_helper'))
|
42
|
+
database_gem_name = ObjectidColumns::Helpers::DatabaseHelper.maybe_database_gem_name
|
43
|
+
|
44
|
+
# Ugh. Later versions of the 'mysql2' gem are incompatible with AR 3.0.x; so, here, we explicitly trap that case
|
45
|
+
# and use an earlier version of that Gem.
|
46
|
+
if database_gem_name && database_gem_name == 'mysql2' && ar_version && ar_version =~ /^3\.0\./
|
47
|
+
spec.add_development_dependency('mysql2', '~> 0.2.0')
|
48
|
+
else
|
49
|
+
spec.add_development_dependency(database_gem_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Double ugh. Basically, composite_primary_keys -- as useful as it is! -- is also incredibly incompatible with so
|
53
|
+
# much stuff:
|
54
|
+
#
|
55
|
+
# * Under Ruby 1.9+ with Postgres, it causes binary strings sent to or from the database to get truncated
|
56
|
+
# at the first null byte (!), which completely breaks binary-column support;
|
57
|
+
# * Under JRuby with ActiveRecord 3.0, it's completely broken;
|
58
|
+
# * Under JRuby with ActiveRecord 3.1 and PostgreSQL, it's also broken.
|
59
|
+
#
|
60
|
+
# In these cases, we simply don't load or test against composite_primary_keys; our code is good, but the interactions
|
61
|
+
# between CPK and the rest of the system make it impossible to run those tests. There is corresponding code in our
|
62
|
+
# +basic_system_spec+ to exclude those combinations.
|
63
|
+
cpk_allowed = true
|
64
|
+
cpk_allowed = false if database_gem_name =~ /(pg|postgres)/i && RUBY_VERSION =~ /^(1\.9)|(2\.)/ && ar_version && ar_version =~ /^4\.(0|1)\./
|
65
|
+
cpk_allowed = false if defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'jruby') && ar_version && ar_version =~ /^3\.0\./
|
66
|
+
cpk_allowed = false if defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'jruby') && ar_version && ar_version =~ /^3\.1\./ && database_gem_name =~ /(pg|postgres)/i
|
67
|
+
|
68
|
+
if cpk_allowed
|
69
|
+
spec.add_development_dependency "composite_primary_keys"
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
module ObjectidColumns
|
2
|
+
module Helpers
|
3
|
+
class DatabaseHelper
|
4
|
+
class InvalidDatabaseConfigurationError < StandardError; end
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def maybe_database_gem_name
|
8
|
+
begin
|
9
|
+
dh = new
|
10
|
+
dh.database_gem_name
|
11
|
+
rescue InvalidDatabaseConfigurationError => idce
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
config # make sure we raise on instantiation if configuration is invalid
|
19
|
+
end
|
20
|
+
|
21
|
+
def database_type
|
22
|
+
case database_gem_name
|
23
|
+
when /mysql/i then :mysql
|
24
|
+
when /sqlite/i then :sqlite
|
25
|
+
when /pg/i, /postgres/i then :postgres
|
26
|
+
else raise "Unknown database type for Gem name: #{database_gem_name.inspect}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup_activerecord!
|
31
|
+
require 'active_record'
|
32
|
+
require config[:require]
|
33
|
+
::ActiveRecord::Base.establish_connection(config[:config])
|
34
|
+
|
35
|
+
require 'logger'
|
36
|
+
require 'stringio'
|
37
|
+
@logs = StringIO.new
|
38
|
+
::ActiveRecord::Base.logger = Logger.new(@logs)
|
39
|
+
|
40
|
+
if config[:config][:adapter] == 'sqlite3'
|
41
|
+
sqlite_version = ::ActiveRecord::Base.connection.send(:sqlite_version).instance_variable_get("@version").inspect rescue "unknown"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def table_name(name)
|
46
|
+
"objectidcols_spec_#{name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def database_gem_name
|
50
|
+
config[:database_gem_name]
|
51
|
+
end
|
52
|
+
|
53
|
+
def adapter_name
|
54
|
+
config[:config][:adapter]
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def config
|
59
|
+
config_from_config_file || travis_ci_config_from_environment || invalid_config_file!
|
60
|
+
end
|
61
|
+
|
62
|
+
def config_from_config_file
|
63
|
+
return nil unless File.exist?(config_file_path)
|
64
|
+
require config_file_path
|
65
|
+
|
66
|
+
return nil unless defined?(OBJECTID_COLUMNS_SPEC_DATABASE_CONFIG)
|
67
|
+
return nil unless OBJECTID_COLUMNS_SPEC_DATABASE_CONFIG.kind_of?(Hash)
|
68
|
+
|
69
|
+
return nil unless OBJECTID_COLUMNS_SPEC_DATABASE_CONFIG[:require]
|
70
|
+
return nil unless OBJECTID_COLUMNS_SPEC_DATABASE_CONFIG[:database_gem_name]
|
71
|
+
|
72
|
+
return nil unless OBJECTID_COLUMNS_SPEC_DATABASE_CONFIG
|
73
|
+
OBJECTID_COLUMNS_SPEC_DATABASE_CONFIG
|
74
|
+
end
|
75
|
+
|
76
|
+
def travis_ci_config_from_environment
|
77
|
+
dbtype = (ENV['OBJECTID_COLUMNS_TRAVIS_CI_DATABASE_TYPE'] || '').strip.downcase
|
78
|
+
is_jruby = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
79
|
+
|
80
|
+
if is_jruby
|
81
|
+
case dbtype
|
82
|
+
when 'mysql'
|
83
|
+
{
|
84
|
+
:require => 'activerecord-jdbcmysql-adapter',
|
85
|
+
:database_gem_name => 'activerecord-jdbcmysql-adapter',
|
86
|
+
:config => {
|
87
|
+
:adapter => 'jdbcmysql',
|
88
|
+
:database => 'myapp_test',
|
89
|
+
:username => 'travis',
|
90
|
+
:encoding => 'utf8'
|
91
|
+
}
|
92
|
+
}
|
93
|
+
when 'postgres', 'postgresql'
|
94
|
+
{
|
95
|
+
:require => 'activerecord-jdbcpostgresql-adapter',
|
96
|
+
:database_gem_name => 'activerecord-jdbcpostgresql-adapter',
|
97
|
+
:config => {
|
98
|
+
:adapter => 'jdbcpostgresql',
|
99
|
+
:database => 'myapp_test',
|
100
|
+
:username => 'postgres'
|
101
|
+
}
|
102
|
+
}
|
103
|
+
when 'sqlite'
|
104
|
+
{
|
105
|
+
:require => 'activerecord-jdbcsqlite3-adapter',
|
106
|
+
:database_gem_name => 'activerecord-jdbcsqlite3-adapter',
|
107
|
+
:config => {
|
108
|
+
:adapter => 'jdbcsqlite3',
|
109
|
+
:database => ':memory:'
|
110
|
+
}
|
111
|
+
}
|
112
|
+
when '', nil then nil
|
113
|
+
else
|
114
|
+
raise "Unknown Travis CI database type: #{dbtype.inspect}"
|
115
|
+
end
|
116
|
+
else
|
117
|
+
case dbtype
|
118
|
+
when 'postgres', 'postgresql'
|
119
|
+
{
|
120
|
+
:require => 'pg',
|
121
|
+
:database_gem_name => 'pg',
|
122
|
+
:config => {
|
123
|
+
:adapter => 'postgresql',
|
124
|
+
:database => 'myapp_test',
|
125
|
+
:username => 'postgres',
|
126
|
+
:min_messages => 'WARNING'
|
127
|
+
}
|
128
|
+
}
|
129
|
+
when 'mysql'
|
130
|
+
{
|
131
|
+
:require => 'mysql2',
|
132
|
+
:database_gem_name => 'mysql2',
|
133
|
+
:config => {
|
134
|
+
:adapter => 'mysql2',
|
135
|
+
:database => 'myapp_test',
|
136
|
+
:username => 'travis',
|
137
|
+
:encoding => 'utf8'
|
138
|
+
}
|
139
|
+
}
|
140
|
+
when 'sqlite'
|
141
|
+
{
|
142
|
+
:require => 'sqlite3',
|
143
|
+
:database_gem_name => 'sqlite3',
|
144
|
+
:config => {
|
145
|
+
:adapter => 'sqlite3',
|
146
|
+
:database => ':memory:',
|
147
|
+
:timeout => 500
|
148
|
+
}
|
149
|
+
}
|
150
|
+
when '', nil then nil
|
151
|
+
else
|
152
|
+
raise "Unknown Travis CI database type: #{dbtype.inspect}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def config_file_path
|
158
|
+
@config_file_path ||= File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_database_config.rb'))
|
159
|
+
end
|
160
|
+
|
161
|
+
def invalid_config_file!
|
162
|
+
raise Errno::ENOENT, %{In order to run specs for ObjectIdColumns, you need to create a file at:
|
163
|
+
|
164
|
+
#{config_file_path}
|
165
|
+
|
166
|
+
...that defines a top-level OBJECTID_COLUMNS_SPEC_DATABASE_CONFIG hash, with members:
|
167
|
+
|
168
|
+
:require => 'name_of_adapter_to_require',
|
169
|
+
:database_gem_name => 'name_of_gem_for_adapter',
|
170
|
+
:config => { ...whatever ActiveRecord::Base.establish_connection should be passed... }
|
171
|
+
|
172
|
+
Alternatively, if you're running under Travis CI, you can set the environment variable
|
173
|
+
OBJECTID_COLUMNS_TRAVIS_CI_DATABASE_TYPE to 'postgres', 'mysql', or 'sqlite', and it will
|
174
|
+
use the correct configuration for testing on Travis CI.}
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_record/migration'
|
3
|
+
require 'objectid_columns/helpers/database_helper'
|
4
|
+
|
5
|
+
module ObjectidColumns
|
6
|
+
module Helpers
|
7
|
+
module SystemHelpers
|
8
|
+
def migrate(&block)
|
9
|
+
migration_class = Class.new(::ActiveRecord::Migration)
|
10
|
+
metaclass = migration_class.class_eval { class << self; self; end }
|
11
|
+
metaclass.instance_eval { define_method(:up, &block) }
|
12
|
+
|
13
|
+
::ActiveRecord::Migration.suppress_messages do
|
14
|
+
migration_class.migrate(:up)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def define_model_class(name, table_name, options = { }, &block)
|
19
|
+
superclass = options[:superclass] || ::ActiveRecord::Base
|
20
|
+
model_class = Class.new(superclass)
|
21
|
+
::Object.send(:remove_const, name) if ::Object.const_defined?(name)
|
22
|
+
::Object.const_set(name, model_class)
|
23
|
+
model_class.table_name = table_name if table_name
|
24
|
+
model_class.class_eval(&block) if block
|
25
|
+
model_class
|
26
|
+
end
|
27
|
+
|
28
|
+
def ensure_database_is_set_up!
|
29
|
+
::ObjectidColumns::Helpers::SystemHelpers.database_helper
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
def database_helper
|
34
|
+
@database_helper ||= begin
|
35
|
+
out = ObjectidColumns::Helpers::DatabaseHelper.new
|
36
|
+
out.setup_activerecord!
|
37
|
+
out
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def binary_column(length)
|
42
|
+
case ObjectidColumns::Helpers::SystemHelpers.database_helper.adapter_name.to_s
|
43
|
+
when /mysql/, /sqlite/ then "BINARY(#{length})"
|
44
|
+
when /postgres/ then "BYTEA"
|
45
|
+
else raise "Don't yet know how to define a binary column for database #{OBJECTID_COLUMNS_SPEC_DATABASE_CONFIG[:config][:adapter].inspect}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def supports_length_limits_on_binary_columns?
|
50
|
+
case ObjectidColumns::Helpers::SystemHelpers.database_helper.adapter_name.to_s
|
51
|
+
when /mysql/, /sqlite/ then true
|
52
|
+
when /postgres/ then false
|
53
|
+
else raise "Don't yet know whether database #{OBJECTID_COLUMNS_SPEC_DATABASE_CONFIG[:config][:adapter].inspect} supports limits on binary columns"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_standard_system_spec_tables!
|
59
|
+
migrate do
|
60
|
+
drop_table :objectidcols_spec_table rescue nil
|
61
|
+
create_table :objectidcols_spec_table do |t|
|
62
|
+
t.column :perfect_b_oid, ObjectidColumns::Helpers::SystemHelpers.binary_column(12)
|
63
|
+
t.column :longer_b_oid, ObjectidColumns::Helpers::SystemHelpers.binary_column(15)
|
64
|
+
|
65
|
+
t.column :too_short_b, ObjectidColumns::Helpers::SystemHelpers.binary_column(11)
|
66
|
+
t.column :perfect_b, ObjectidColumns::Helpers::SystemHelpers.binary_column(12)
|
67
|
+
t.column :longer_b, ObjectidColumns::Helpers::SystemHelpers.binary_column(15)
|
68
|
+
|
69
|
+
t.column :perfect_s_oid, 'VARCHAR(24)'
|
70
|
+
t.column :longer_s_oid, 'VARCHAR(30)'
|
71
|
+
|
72
|
+
t.column :too_short_s, 'VARCHAR(23)'
|
73
|
+
t.column :perfect_s, 'VARCHAR(24)'
|
74
|
+
t.column :longer_s, 'VARCHAR(30)'
|
75
|
+
|
76
|
+
t.integer :some_int_column
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_standard_system_spec_models!
|
82
|
+
define_model_class(:Spectable, 'objectidcols_spec_table') { }
|
83
|
+
end
|
84
|
+
|
85
|
+
def drop_standard_system_spec_tables!
|
86
|
+
migrate do
|
87
|
+
drop_table :objectidcols_spec_table rescue nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,600 @@
|
|
1
|
+
require 'objectid_columns'
|
2
|
+
require 'objectid_columns/helpers/system_helpers'
|
3
|
+
|
4
|
+
# See the gemspec for more details -- basically, we don't always load composite_primary_keys, because it's pretty
|
5
|
+
# broken and doesn't work with a fair number of combinations of Ruby versions, databases, and so on. So if it's not
|
6
|
+
# available, we skip those tests.
|
7
|
+
begin
|
8
|
+
require 'composite_primary_keys'
|
9
|
+
$composite_primary_keys_available = true
|
10
|
+
rescue LoadError => le
|
11
|
+
# nothing here
|
12
|
+
end
|
13
|
+
|
14
|
+
unless defined?(VALID_OBJECTID_CLASSES)
|
15
|
+
VALID_OBJECTID_CLASSES = [ BSON::ObjectId ]
|
16
|
+
VALID_OBJECTID_CLASSES << Moped::BSON::ObjectId if defined?(Moped::BSON::ObjectId)
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec::Matchers.define :be_an_objectid_object do
|
20
|
+
match do |actual|
|
21
|
+
VALID_OBJECTID_CLASSES.detect { |c| actual.kind_of?(c) }
|
22
|
+
end
|
23
|
+
failure_message_for_should do |actual|
|
24
|
+
"expected that #{actual} (#{actual.class}) would be an instance of BSON::ObjectId or Moped::BSON::ObjectId"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec::Matchers.define :be_the_same_objectid_as do |expected|
|
29
|
+
match do |actual|
|
30
|
+
net_expected = expected ? expected.to_bson_id.to_s : expected
|
31
|
+
net_actual = actual ? actual.to_bson_id.to_s : actual
|
32
|
+
net_expected == net_actual
|
33
|
+
end
|
34
|
+
failure_message_for_should do |actual|
|
35
|
+
"expected that #{actual} (#{actual.class}) would be the same ObjectId as #{expected} (#{expected.class})"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
RSpec::Matchers.define :be_an_objectid_object_matching do |expected|
|
40
|
+
match do |actual|
|
41
|
+
net_expected = expected ? expected.to_bson_id.to_s : expected
|
42
|
+
net_actual = actual ? actual.to_bson_id.to_s : actual
|
43
|
+
(net_expected == net_actual) && (VALID_OBJECTID_CLASSES.detect { |c| actual.kind_of?(c) })
|
44
|
+
end
|
45
|
+
failure_message_for_should do |actual|
|
46
|
+
"expected that #{actual} (#{actual.class}) would be an ObjectId object equal to #{expected} (#{expected.class})"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "ObjectidColumns basic operations" do
|
51
|
+
include ObjectidColumns::Helpers::SystemHelpers
|
52
|
+
|
53
|
+
before :each do
|
54
|
+
ensure_database_is_set_up!
|
55
|
+
|
56
|
+
create_standard_system_spec_tables!
|
57
|
+
create_standard_system_spec_models!
|
58
|
+
end
|
59
|
+
|
60
|
+
after :each do
|
61
|
+
drop_standard_system_spec_tables!
|
62
|
+
end
|
63
|
+
|
64
|
+
VALID_OBJECTID_CLASSES.each do |test_class|
|
65
|
+
context "using test class #{test_class}" do
|
66
|
+
before :each do
|
67
|
+
@tc = test_class
|
68
|
+
end
|
69
|
+
|
70
|
+
def new_oid
|
71
|
+
@tc.new
|
72
|
+
end
|
73
|
+
|
74
|
+
context "with an STI table and model" do
|
75
|
+
before :each do
|
76
|
+
migrate do
|
77
|
+
drop_table :objectidcols_spec_table_sti rescue nil
|
78
|
+
create_table :objectidcols_spec_table_sti do |t|
|
79
|
+
t.string :type
|
80
|
+
t.column :some_oid, 'VARCHAR(24)'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
after :each do
|
86
|
+
migrate do
|
87
|
+
drop_table :objectidcols_spec_table_sti rescue nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
let(:parent_model_class) { define_model_class(:SpectableStiParent, 'objectidcols_spec_table_sti') { has_objectid_columns } }
|
92
|
+
let(:child_model_class) { define_model_class(:SpectableStiChild, 'objectidcols_spec_table_sti', :superclass => parent_model_class) { } }
|
93
|
+
|
94
|
+
it "should work from both the parent and child class" do
|
95
|
+
id_1 = new_oid
|
96
|
+
id_2 = new_oid
|
97
|
+
|
98
|
+
parent_instance = parent_model_class.new(:some_oid => id_1)
|
99
|
+
parent_instance.save!
|
100
|
+
|
101
|
+
child_instance = child_model_class.new(:some_oid => id_2)
|
102
|
+
child_instance.save!
|
103
|
+
|
104
|
+
all_models = parent_model_class.all.to_a
|
105
|
+
expect(all_models.length).to eq(2)
|
106
|
+
parent_instance_again = all_models.detect { |m| m.id == parent_instance.id }
|
107
|
+
child_instance_again = all_models.detect { |m| m.id == child_instance.id }
|
108
|
+
|
109
|
+
expect(parent_instance_again.some_oid).to be_an_objectid_object_matching(id_1)
|
110
|
+
expect(child_instance_again.some_oid).to be_an_objectid_object_matching(id_2)
|
111
|
+
|
112
|
+
child_models = child_model_class.all.to_a
|
113
|
+
expect(child_models.length).to eq(1)
|
114
|
+
expect(child_models[0].some_oid).to be_an_objectid_object_matching(id_2)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should not allow defining a column that's too short" do
|
119
|
+
if ObjectidColumns::Helpers::SystemHelpers.supports_length_limits_on_binary_columns?
|
120
|
+
expect { ::Spectable.class_eval { has_objectid_column :too_short_b } }.to raise_error(ArgumentError)
|
121
|
+
expect { ::Spectable.class_eval { has_objectid_column :too_short_s } }.to raise_error(ArgumentError)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should not allow defining a column that's the wrong type" do
|
126
|
+
expect { ::Spectable.class_eval { has_objectid_column :some_int_column } }.to raise_error(ArgumentError)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should not allow defining a column that doesn't exist" do
|
130
|
+
expect { ::Spectable.class_eval { has_objectid_column :unknown_column } }.to raise_error(ArgumentError)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should not fail if the table doesn't exist" do
|
134
|
+
define_model_class(:SpectableNonexistent, 'objectidcols_spec_table_nonexistent') { }
|
135
|
+
expect { ::SpectableNonexistent.class_eval { has_objectid_column :foo } }.to_not raise_error
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should not fail if declared as a primary key and the table doesn't exist" do
|
139
|
+
define_model_class(:SpectableNonexistent, 'objectidcols_spec_table_nonexistent') { }
|
140
|
+
expect { ::SpectableNonexistent.class_eval { has_objectid_primary_key } }.to_not raise_error
|
141
|
+
expect { ::SpectableNonexistent.class_eval { has_objectid_primary_key :foo } }.to_not raise_error
|
142
|
+
end
|
143
|
+
|
144
|
+
if $composite_primary_keys_available
|
145
|
+
describe "composite primary key support" do
|
146
|
+
context "with an implicit PK" do
|
147
|
+
before :each do
|
148
|
+
migrate do
|
149
|
+
drop_table :objectidcols_spec_pk_cmp rescue nil
|
150
|
+
create_table :objectidcols_spec_pk_cmp, :id => false do |t|
|
151
|
+
t.binary :some_oid, :null => false
|
152
|
+
t.string :more_pk, :null => false
|
153
|
+
t.string :value
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
define_model_class(:SpectablePkCmp, :objectidcols_spec_pk_cmp) do
|
158
|
+
if respond_to?(:primary_keys=)
|
159
|
+
self.primary_keys = [ 'some_oid', 'more_pk' ]
|
160
|
+
else
|
161
|
+
self.set_primary_keys('some_oid', 'more_pk')
|
162
|
+
end
|
163
|
+
end
|
164
|
+
::SpectablePkCmp.class_eval { has_objectid_primary_key }
|
165
|
+
@model_class = ::SpectablePkCmp
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should allow using a composite primary key in individual parts" do
|
169
|
+
pending "disabled" unless $composite_primary_keys_available
|
170
|
+
|
171
|
+
instance = @model_class.new
|
172
|
+
instance.some_oid = new_oid
|
173
|
+
instance.more_pk = "foo"
|
174
|
+
instance.value = "foo value"
|
175
|
+
instance.save!
|
176
|
+
|
177
|
+
instance_again = @model_class.find([ instance.some_oid, instance.more_pk ])
|
178
|
+
expect(instance_again.value).to eq(instance.value)
|
179
|
+
expect(instance_again.some_oid).to eq(instance.some_oid)
|
180
|
+
expect(instance_again.more_pk).to eq(instance.more_pk)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should allow using a composite primary key as a whole" do
|
184
|
+
pending "disabled" unless $composite_primary_keys_available
|
185
|
+
|
186
|
+
oid = new_oid
|
187
|
+
instance = @model_class.new
|
188
|
+
instance.id = [ oid, "foo" ]
|
189
|
+
instance.value = "foo value"
|
190
|
+
instance.save!
|
191
|
+
|
192
|
+
expect(instance.some_oid).to be_an_objectid_object_matching(oid)
|
193
|
+
expect(instance.more_pk).to eq("foo")
|
194
|
+
expect(instance.value).to eq("foo value")
|
195
|
+
|
196
|
+
instance_again = @model_class.find(instance.id)
|
197
|
+
expect(instance_again.id).to eq(instance.id)
|
198
|
+
expect(instance_again.some_oid).to be_an_objectid_object_matching(oid)
|
199
|
+
expect(instance_again.more_pk).to eq("foo")
|
200
|
+
expect(instance_again.value).to eq("foo value")
|
201
|
+
expect(instance_again.id).to be_kind_of(Array)
|
202
|
+
expect(instance_again.id.length).to eq(2)
|
203
|
+
expect(instance_again.id[0]).to be_an_objectid_object_matching(oid)
|
204
|
+
expect(instance_again.id[1]).to eq("foo")
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "with an explicit PK" do
|
209
|
+
before :each do
|
210
|
+
migrate do
|
211
|
+
drop_table :objectidcols_spec_pk_cmp_2 rescue nil
|
212
|
+
create_table :objectidcols_spec_pk_cmp_2, :id => false do |t|
|
213
|
+
t.binary :one, :null => false
|
214
|
+
t.string :two, :null => false
|
215
|
+
t.string :three, :null => false
|
216
|
+
t.string :value
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
define_model_class(:SpectablePkCmp2, :objectidcols_spec_pk_cmp_2) do
|
221
|
+
if respond_to?(:primary_keys=)
|
222
|
+
self.primary_keys = [ 'one', 'two', 'three' ]
|
223
|
+
else
|
224
|
+
self.set_primary_keys('one', 'two', 'three')
|
225
|
+
end
|
226
|
+
end
|
227
|
+
::SpectablePkCmp2.class_eval { has_objectid_primary_key :one, :three }
|
228
|
+
@model_class = ::SpectablePkCmp2
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should allow using a composite primary key that's partially ObjectId and partially not" do
|
232
|
+
instance = @model_class.new
|
233
|
+
instance.two = "foo"
|
234
|
+
instance.value = "foo_value"
|
235
|
+
instance.save!
|
236
|
+
|
237
|
+
expect(instance.id).to be_kind_of(Array)
|
238
|
+
expect(instance.id[0]).to be_an_objectid_object
|
239
|
+
expect(instance.id[1]).to eq("foo")
|
240
|
+
expect(instance.id[2]).to be_an_objectid_object
|
241
|
+
|
242
|
+
id = instance.id
|
243
|
+
instance_again = @model_class.find(id)
|
244
|
+
expect(instance_again.id).to eq(id)
|
245
|
+
expect(instance_again.id[0]).to be_an_objectid_object_matching(id[0])
|
246
|
+
expect(instance_again.id[1]).to eq("foo")
|
247
|
+
expect(instance_again.id[2]).to be_an_objectid_object_matching(id[2])
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe "primary key column support" do
|
254
|
+
before :each do
|
255
|
+
migrate do
|
256
|
+
drop_table :objectidcols_spec_pk_bin rescue nil
|
257
|
+
create_table :objectidcols_spec_pk_bin, :id => false do |t|
|
258
|
+
t.binary :id, :null => false
|
259
|
+
t.string :name
|
260
|
+
end
|
261
|
+
|
262
|
+
drop_table :objectidcols_spec_pk_str rescue nil
|
263
|
+
create_table :objectidcols_spec_pk_str, :id => false do |t|
|
264
|
+
t.string :id, :null => false
|
265
|
+
t.string :name
|
266
|
+
end
|
267
|
+
|
268
|
+
drop_table :objectidcols_spec_pk_alt rescue nil
|
269
|
+
create_table :objectidcols_spec_pk_alt, :id => false do |t|
|
270
|
+
t.binary :some_name, :null => false
|
271
|
+
t.string :name
|
272
|
+
end
|
273
|
+
|
274
|
+
drop_table :objectidcols_spec_pk_implicit rescue nil
|
275
|
+
create_table :objectidcols_spec_pk_implicit, :id => false do |t|
|
276
|
+
t.binary :some_name, :null => false
|
277
|
+
t.string :name
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
define_model_class(:SpectablePkBin, :objectidcols_spec_pk_bin) { self.primary_key = 'id' }
|
282
|
+
define_model_class(:SpectablePkStr, :objectidcols_spec_pk_str) { self.primary_key = 'id' }
|
283
|
+
define_model_class(:SpectablePkAlt, :objectidcols_spec_pk_alt) { self.primary_key = 'some_name' }
|
284
|
+
define_model_class(:SpectablePkImplicit, :objectidcols_spec_pk_implicit) { }
|
285
|
+
|
286
|
+
::SpectablePkBin.class_eval { has_objectid_primary_key }
|
287
|
+
::SpectablePkStr.class_eval { has_objectid_primary_key }
|
288
|
+
::SpectablePkAlt.class_eval { has_objectid_primary_key }
|
289
|
+
::SpectablePkImplicit.class_eval { has_objectid_primary_key :some_name }
|
290
|
+
end
|
291
|
+
|
292
|
+
after :each do
|
293
|
+
drop_table :objectidcols_spec_pk_bin rescue nil
|
294
|
+
drop_table :objectidcols_spec_pk_str rescue nil
|
295
|
+
drop_table :objectidcols_spec_pk_table_alt rescue nil
|
296
|
+
drop_table :objectidcols_spec_pk_implicit rescue nil
|
297
|
+
end
|
298
|
+
|
299
|
+
[ :SpectablePkBin, :SpectablePkStr, :SpectablePkAlt, :SpectablePkImplicit ].each do |model_class|
|
300
|
+
context "on model #{model_class}" do
|
301
|
+
before :each do
|
302
|
+
@model_class = model_class.to_s.constantize
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should fail autodetection, since there are no columns ending in _oid" do
|
306
|
+
expect { @model_class.has_objectid_columns }.to raise_error(ArgumentError)
|
307
|
+
end
|
308
|
+
|
309
|
+
it "should allow using a binary ObjectId column as a primary key" do
|
310
|
+
r1 = @model_class.new
|
311
|
+
r1.name = 'row 1'
|
312
|
+
expect(r1.id).to be_nil
|
313
|
+
r1.save!
|
314
|
+
expect(r1.id).to_not be_nil
|
315
|
+
expect(r1.id).to be_an_objectid_object
|
316
|
+
r1_id = r1.id
|
317
|
+
|
318
|
+
r2 = @model_class.new
|
319
|
+
r2.name = 'row 2'
|
320
|
+
expect(r2.id).to be_nil
|
321
|
+
r2.save!
|
322
|
+
expect(r2.id).to_not be_nil
|
323
|
+
expect(r2.id).to be_an_objectid_object
|
324
|
+
r2_id = r2.id
|
325
|
+
|
326
|
+
expect(r1.send(@model_class.primary_key)).to be_an_objectid_object_matching(r1.id)
|
327
|
+
expect(r2.send(@model_class.primary_key)).to be_an_objectid_object_matching(r2.id)
|
328
|
+
|
329
|
+
r1_again = @model_class.find(r1.id)
|
330
|
+
expect(r1_again.name).to eq('row 1')
|
331
|
+
|
332
|
+
r2_again = @model_class.find(r2.id)
|
333
|
+
expect(r2_again.name).to eq('row 2')
|
334
|
+
|
335
|
+
expect(@model_class.find([ r1.id, r2. id ]).map(&:id).sort_by(&:to_s)).to eq([ r1_id, r2_id ].sort_by(&:to_s))
|
336
|
+
|
337
|
+
expect(@model_class.where(:name => 'row 1').first.id).to eq(r1_id)
|
338
|
+
expect(@model_class.where(:name => 'row 2').first.id).to eq(r2_id)
|
339
|
+
|
340
|
+
find_by_id_method = "find_by_#{@model_class.primary_key}"
|
341
|
+
expect(@model_class.send(find_by_id_method, r1.id).id).to eq(r1_id)
|
342
|
+
expect(@model_class.send(find_by_id_method, r2.id).id).to eq(r2_id)
|
343
|
+
expect(@model_class.send(find_by_id_method, new_oid)).to be_nil
|
344
|
+
end
|
345
|
+
|
346
|
+
it "should let you load and save objects properly" do
|
347
|
+
r1 = @model_class.new
|
348
|
+
r1.name = 'row 1'
|
349
|
+
r1.id = new_oid
|
350
|
+
r1.save!
|
351
|
+
|
352
|
+
r1_again = @model_class.find(@tc.from_string(r1.id.to_s))
|
353
|
+
expect(r1_again.name).to eq('row 1')
|
354
|
+
r1_again.id = @tc.from_string(r1.id.to_s)
|
355
|
+
r1_again.name = 'row 1 again'
|
356
|
+
r1_again.save!
|
357
|
+
|
358
|
+
r1_yet_again = @model_class.find(r1_again.id)
|
359
|
+
expect(r1_yet_again.name).to eq('row 1 again')
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should not pick up primary-key columns automatically, even if they're named _oid" do
|
363
|
+
migrate do
|
364
|
+
drop_table :objectidcols_spec_pk_auto rescue nil
|
365
|
+
create_table :objectidcols_spec_pk_auto, :id => false do |t|
|
366
|
+
t.binary :foo_oid, :null => false
|
367
|
+
t.binary :bar_oid
|
368
|
+
t.string :name
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
define_model_class(:SpectablePkAuto, :objectidcols_spec_pk_auto) { self.primary_key = 'foo_oid' }
|
373
|
+
|
374
|
+
::SpectablePkAuto.has_objectid_columns
|
375
|
+
r = ::SpectablePkAuto.new
|
376
|
+
r.foo_oid = 'foobar' # this will only work if we do NOT think it's an ObjectId
|
377
|
+
expect { r.bar_oid = 'foobar' }.to raise_error(ArgumentError)
|
378
|
+
r.bar_oid = the_bar_oid = new_oid.to_s
|
379
|
+
|
380
|
+
expect(r.bar_oid).to be_an_objectid_object_matching(the_bar_oid)
|
381
|
+
|
382
|
+
migrate do
|
383
|
+
drop_table :objectidcols_spec_pk_auto rescue nil
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
context "with a single, manually-defined column" do
|
391
|
+
before :each do
|
392
|
+
::Spectable.class_eval { has_objectid_column :perfect_s_oid }
|
393
|
+
end
|
394
|
+
|
395
|
+
it "should allow writing and reading via an ObjectId object" do
|
396
|
+
the_oid = new_oid
|
397
|
+
|
398
|
+
r = ::Spectable.new
|
399
|
+
r.perfect_s_oid = the_oid
|
400
|
+
expect(r.perfect_s_oid).to be_the_same_objectid_as(the_oid)
|
401
|
+
expect(r.perfect_s_oid).to be_an_objectid_object
|
402
|
+
r.save!
|
403
|
+
expect(r.perfect_s_oid).to be_the_same_objectid_as(the_oid.to_s)
|
404
|
+
expect(r.perfect_s_oid).to be_an_objectid_object
|
405
|
+
|
406
|
+
r_again = ::Spectable.find(r.id)
|
407
|
+
expect(r_again.perfect_s_oid).to be_the_same_objectid_as(the_oid.to_s)
|
408
|
+
expect(r_again.perfect_s_oid).to be_an_objectid_object
|
409
|
+
end
|
410
|
+
|
411
|
+
it "should raise a good exception if you try to assign something that isn't a valid ObjectId" do
|
412
|
+
r = ::Spectable.new
|
413
|
+
|
414
|
+
expect { r.perfect_s_oid = 12345 }.to raise_error(ArgumentError, /12345/)
|
415
|
+
expect { r.perfect_s_oid = /foobar/ }.to raise_error(ArgumentError, /foobar/i)
|
416
|
+
end
|
417
|
+
|
418
|
+
if "".respond_to?(:encoding)
|
419
|
+
it "should not allow assigning binary strings unless their encoding is BINARY" do
|
420
|
+
r = ::Spectable.new
|
421
|
+
|
422
|
+
binary = new_oid.to_binary
|
423
|
+
binary = binary.force_encoding(Encoding::ISO_8859_1)
|
424
|
+
expect { r.perfect_s_oid = binary }.to raise_error(ArgumentError)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
it "should not allow assigning strings that are the wrong format" do
|
429
|
+
r = ::Spectable.new
|
430
|
+
|
431
|
+
expect { r.perfect_s_oid = new_oid.to_binary[0..10] }.to raise_error(ArgumentError)
|
432
|
+
expect { r.perfect_s_oid = new_oid.to_binary + "\x00" }.to raise_error(ArgumentError)
|
433
|
+
end
|
434
|
+
|
435
|
+
it "should let you set columns to nil" do
|
436
|
+
r = ::Spectable.create!(:perfect_s_oid => (@oid = new_oid))
|
437
|
+
|
438
|
+
r_again = ::Spectable.find(r.id)
|
439
|
+
expect(r_again.perfect_s_oid).to be_an_objectid_object_matching(@oid)
|
440
|
+
r.perfect_s_oid = nil
|
441
|
+
r.save!
|
442
|
+
|
443
|
+
r_yet_again = ::Spectable.find(r.id)
|
444
|
+
expect(r_yet_again.perfect_s_oid).to be_nil
|
445
|
+
end
|
446
|
+
|
447
|
+
it "should accept ObjectIds for input in binary, String, or either object format" do
|
448
|
+
VALID_OBJECTID_CLASSES.each do |klass|
|
449
|
+
r = ::Spectable.create!(:perfect_s_oid => (@oid = klass.new))
|
450
|
+
expect(::Spectable.find(r.id).perfect_s_oid).to be_an_objectid_object_matching(@oid)
|
451
|
+
end
|
452
|
+
|
453
|
+
r = ::Spectable.create!(:perfect_s_oid => (@oid = new_oid.to_s))
|
454
|
+
expect(::Spectable.find(r.id).perfect_s_oid).to be_an_objectid_object_matching(@oid)
|
455
|
+
|
456
|
+
r = ::Spectable.create!(:perfect_s_oid => (@oid = new_oid.to_binary))
|
457
|
+
expect(::Spectable.find(r.id).perfect_s_oid).to be_an_objectid_object_matching(@oid)
|
458
|
+
end
|
459
|
+
|
460
|
+
it "should not do anything to the other columns" do
|
461
|
+
r = ::Spectable.new
|
462
|
+
|
463
|
+
r.perfect_b_oid = 'perfect_b_1'
|
464
|
+
r.longer_b_oid = 'longer_b_1'
|
465
|
+
|
466
|
+
r.too_short_b = 'short_b_2'
|
467
|
+
r.perfect_b = 'perfect_b_2'
|
468
|
+
r.longer_b = 'longer_b_2'
|
469
|
+
|
470
|
+
the_oid = new_oid
|
471
|
+
r.perfect_s_oid = the_oid
|
472
|
+
r.longer_s_oid = 'longer_s_1'
|
473
|
+
|
474
|
+
r.too_short_s = 'short_s_1'
|
475
|
+
r.perfect_s = 'perfect_s_2'
|
476
|
+
r.longer_s = 'longer_s'
|
477
|
+
|
478
|
+
r.save!
|
479
|
+
|
480
|
+
r_again = ::Spectable.find(r.id)
|
481
|
+
|
482
|
+
expect(r_again.perfect_b_oid.strip).to eq('perfect_b_1')
|
483
|
+
expect(r_again.longer_b_oid.strip).to eq('longer_b_1')
|
484
|
+
|
485
|
+
expect(r_again.too_short_b.strip).to eq('short_b_2')
|
486
|
+
expect(r_again.perfect_b.strip).to eq('perfect_b_2')
|
487
|
+
expect(r_again.longer_b.strip).to eq('longer_b_2')
|
488
|
+
|
489
|
+
expect(r_again.perfect_s_oid).to be_the_same_objectid_as(the_oid)
|
490
|
+
expect(r_again.perfect_s_oid).to be_an_objectid_object
|
491
|
+
expect(r_again.longer_s_oid).to eq('longer_s_1')
|
492
|
+
|
493
|
+
expect(r_again.too_short_s).to eq('short_s_1')
|
494
|
+
expect(r_again.perfect_s).to eq('perfect_s_2')
|
495
|
+
expect(r_again.longer_s).to eq('longer_s')
|
496
|
+
end
|
497
|
+
|
498
|
+
it "should allow querying on ObjectId columns via Hash, but not change other queries" do
|
499
|
+
r1 = ::Spectable.create!(:perfect_s_oid => (@oid1 = new_oid), :longer_s_oid => "foobar")
|
500
|
+
r2 = ::Spectable.create!(:perfect_s_oid => (@oid2 = new_oid), :longer_s_oid => "barfoo")
|
501
|
+
|
502
|
+
expect(::Spectable.where(:perfect_s_oid => @oid1).to_a.map(&:id)).to eq([ r1.id ])
|
503
|
+
expect(::Spectable.where(:perfect_s_oid => @oid2).to_a.map(&:id)).to eq([ r2.id ])
|
504
|
+
expect(::Spectable.where(:perfect_s_oid => [ @oid1, @oid2 ]).to_a.map(&:id).sort).to eq([ r1.id, r2.id ].sort)
|
505
|
+
|
506
|
+
expect(::Spectable.where(:perfect_s_oid => @oid1.to_s).to_a.map(&:id)).to eq([ r1.id ])
|
507
|
+
expect(::Spectable.where(:perfect_s_oid => @oid2.to_s).to_a.map(&:id)).to eq([ r2.id ])
|
508
|
+
expect(::Spectable.where(:perfect_s_oid => [ @oid1, @oid2 ].map(&:to_s)).to_a.map(&:id).sort).to eq([ r1.id, r2.id ].sort)
|
509
|
+
|
510
|
+
expect(::Spectable.where(:perfect_s_oid => @oid1.to_binary).to_a.map(&:id)).to eq([ r1.id ])
|
511
|
+
expect(::Spectable.where(:perfect_s_oid => @oid2.to_binary).to_a.map(&:id)).to eq([ r2.id ])
|
512
|
+
expect(::Spectable.where(:perfect_s_oid => [ @oid1, @oid2 ].map(&:to_binary)).to_a.map(&:id).sort).to eq([ r1.id, r2.id ].sort)
|
513
|
+
end
|
514
|
+
|
515
|
+
it "should give a good exception if you try to pass an ObjectID for a column that isn't an official ObjectID column" do
|
516
|
+
oid = new_oid
|
517
|
+
expect { ::Spectable.where(:perfect_b_oid => oid).to_a }.to raise_error(/ObjectidColumns:.*perfect_b_oid/mi)
|
518
|
+
end
|
519
|
+
|
520
|
+
it "should not blow up (and instead let ActiveRecord blow up) if you try to pass an ObjectID for a column that isn't a column at all" do
|
521
|
+
oid = new_oid
|
522
|
+
expect { ::Spectable.where(:something => oid).to_a }.to raise_error(/something/mi)
|
523
|
+
end
|
524
|
+
|
525
|
+
it "should not blow up (and instead let ActiveRecord just find no records, or blow up) if you try to pass an ObjectID for a column on a table that isn't using this gem at all" do
|
526
|
+
define_model_class(:SpectableNondeclared, 'objectidcols_spec_table') { }
|
527
|
+
expect(::SpectableNondeclared.where(:perfect_s_oid => new_oid).to_a).to eq([ ])
|
528
|
+
|
529
|
+
expect { ::SpectableNondeclared.where(:something => new_oid).to_a }.to raise_error(/something/i)
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
it "should allow using any column that's long enough, including binary or string columns" do
|
534
|
+
::Spectable.class_eval do
|
535
|
+
has_objectid_columns :perfect_b_oid, :longer_b_oid
|
536
|
+
has_objectid_columns :perfect_s_oid, :longer_s_oid, :perfect_s, :longer_s
|
537
|
+
end
|
538
|
+
|
539
|
+
r = ::Spectable.new
|
540
|
+
|
541
|
+
r.perfect_b_oid = @perfect_b_oid = new_oid
|
542
|
+
r.longer_b_oid = @longer_b_oid = new_oid
|
543
|
+
r.perfect_s_oid = @perfect_s_oid = new_oid
|
544
|
+
r.longer_s_oid = @longer_s_oid = new_oid
|
545
|
+
r.perfect_s = @perfect_s = new_oid
|
546
|
+
r.longer_s = @longer_s = new_oid
|
547
|
+
|
548
|
+
r.save!
|
549
|
+
|
550
|
+
r_again = ::Spectable.find(r.id)
|
551
|
+
expect(r_again.perfect_b_oid).to be_an_objectid_object_matching(@perfect_b_oid)
|
552
|
+
expect(r_again.longer_b_oid).to be_an_objectid_object_matching(@longer_b_oid)
|
553
|
+
expect(r_again.perfect_s_oid).to be_an_objectid_object_matching(@perfect_s_oid)
|
554
|
+
expect(r_again.longer_s_oid).to be_an_objectid_object_matching(@longer_s_oid)
|
555
|
+
expect(r_again.perfect_s).to be_an_objectid_object_matching(@perfect_s)
|
556
|
+
expect(r_again.longer_s).to be_an_objectid_object_matching(@longer_s)
|
557
|
+
end
|
558
|
+
|
559
|
+
it "should automatically pick up any _oid columns" do
|
560
|
+
::Spectable.class_eval do
|
561
|
+
has_objectid_columns
|
562
|
+
end
|
563
|
+
|
564
|
+
r = ::Spectable.new
|
565
|
+
|
566
|
+
r.perfect_b_oid = @perfect_b_oid = new_oid
|
567
|
+
r.longer_b_oid = @longer_b_oid = new_oid
|
568
|
+
|
569
|
+
r.too_short_b = 'short_b_2'
|
570
|
+
r.perfect_b = 'perfect_b_2'
|
571
|
+
r.longer_b = 'longer_b_2'
|
572
|
+
|
573
|
+
r.perfect_s_oid = @perfect_s_oid = new_oid
|
574
|
+
r.longer_s_oid = @longer_s_oid = new_oid
|
575
|
+
|
576
|
+
r.too_short_s = 'short_s_1'
|
577
|
+
r.perfect_s = 'perfect_s_2'
|
578
|
+
r.longer_s = 'longer_s'
|
579
|
+
|
580
|
+
r.save!
|
581
|
+
|
582
|
+
r_again = ::Spectable.find(r.id)
|
583
|
+
|
584
|
+
expect(r_again.perfect_b_oid).to be_an_objectid_object_matching(@perfect_b_oid)
|
585
|
+
expect(r_again.longer_b_oid).to be_an_objectid_object_matching(@longer_b_oid)
|
586
|
+
|
587
|
+
expect(r_again.too_short_b.strip).to eq('short_b_2')
|
588
|
+
expect(r_again.perfect_b.strip).to eq('perfect_b_2')
|
589
|
+
expect(r_again.longer_b.strip).to eq('longer_b_2')
|
590
|
+
|
591
|
+
r_again.perfect_s_oid.should be_an_objectid_object_matching(@perfect_s_oid)
|
592
|
+
r_again.longer_s_oid.should be_an_objectid_object_matching(@longer_s_oid)
|
593
|
+
|
594
|
+
expect(r_again.too_short_s).to eq('short_s_1')
|
595
|
+
expect(r_again.perfect_s).to eq('perfect_s_2')
|
596
|
+
expect(r_again.longer_s).to eq('longer_s')
|
597
|
+
end
|
598
|
+
end
|
599
|
+
end
|
600
|
+
end
|