dm-restful-adapter 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.autotest ADDED
@@ -0,0 +1,15 @@
1
+ Autotest.add_hook :initialize do |at|
2
+ at.clear_mappings
3
+ ['.git'].each { |exception| at.add_exception(exception) }
4
+
5
+ at.add_mapping(%r%^lib/(.*)\.rb$%) do |_, m|
6
+ at.files_matching %r%^spec/#{m[1]}_spec\.rb$%
7
+ at.files_matching %r%^spec/dm-restful-adapter_spec\.rb$%
8
+ end
9
+
10
+ at.add_mapping(%r%^spec\/support\/mimic.rb$%) do |_, m|
11
+ at.files_matching %r%^spec/dm-restful-adapter_spec\.rb$%
12
+ end
13
+
14
+ at.add_mapping(%r%^spec/.*\_spec\.rb$%) { |filename, _| filename }
15
+ end
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rbenv-gemsets ADDED
@@ -0,0 +1 @@
1
+ dm-restful-adapter
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dm-restful-adapter.gemspec
4
+ gemspec
5
+
6
+ gem 'autotest-standalone'
7
+ gem 'typhoeus'
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Ryan Moran
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,29 @@
1
+ # Dm::Restful::Adapter
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'dm-restful-adapter'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install dm-restful-adapter
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc 'Default: run specs.'
6
+ task :default => :spec
7
+
8
+ desc 'Run specs'
9
+ RSpec::Core::RakeTask.new do |t|
10
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/dm-restful-adapter/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Ryan Moran", "Hubert Huang"]
6
+ gem.email = ["ryan.moran@gmail.com", "hubert77@gmail.com"]
7
+ gem.description = 'Modular adapter for datamapper to access remote resources restfully'
8
+ gem.summary = ''
9
+ gem.homepage = "https://github.com/optimis/dm-restful-adapter"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "dm-restful-adapter"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = DataMapper::Adapters::RestfulAdapter::VERSION
17
+
18
+ gem.add_dependency 'dm-core', '1.2.1'
19
+ gem.add_dependency 'multi_json'
20
+ gem.add_development_dependency 'rspec', '~> 2.9.0'
21
+ gem.add_development_dependency 'mimic', '~> 0.4.3'
22
+ gem.add_development_dependency 'activerecord'
23
+ gem.add_development_dependency 'sqlite3'
24
+ gem.add_development_dependency 'database_cleaner'
25
+ end
@@ -0,0 +1,61 @@
1
+ module Restful
2
+ class Adapter < DataMapper::Adapters::AbstractAdapter
3
+
4
+ def create(resources)
5
+ resources.each { |resource|
6
+ dirty_attributes = resource.dirty_attributes.inject({}) { |hash, (k,v)| hash.update(k.name => v) }
7
+ resource.attributes = Request.post(resource.model.name, dirty_attributes)
8
+ }.size
9
+ end
10
+
11
+ def read(query)
12
+ Request.get(query.model.name, query.params)
13
+ end
14
+
15
+ def update(attrs, resources)
16
+ resources.each do |resource|
17
+ attr_hash = attrs.inject({}) { |h, (k, v)| h.merge(k.name => v) }
18
+ response = Request.put(resource.model.name, resource.key, attr_hash)
19
+ properties = resource.model.properties.inspect
20
+ response.except(:id).each do |k, v|
21
+ if prop = properties[k.to_sym]
22
+ prop.set!(resource, v)
23
+ end
24
+ end
25
+ end.size
26
+ end
27
+
28
+ def delete(resources)
29
+ resources.each do |resource|
30
+ Request.delete(resource.model.name, resource.key)
31
+ end.size
32
+ end
33
+ end
34
+ end
35
+
36
+ class DataMapper::Query
37
+
38
+ def params
39
+ options.inject({}) do |hash, (k,v)|
40
+ k = case k
41
+ when DataMapper::Query::Operator
42
+ [k.target, '.', k.operator].join
43
+ when DataMapper::Property::Serial
44
+ k.name
45
+ else
46
+ k
47
+ end
48
+ k,v = fix_array_param_key(k,v)
49
+ hash.merge(k => v)
50
+ end
51
+ end
52
+
53
+ def fix_array_param_key(key, value)
54
+ if Array === value
55
+ ["#{key}[]", value]
56
+ else
57
+ [key, value]
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,12 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+
4
+ module Restful
5
+ module Backends
6
+ class Net::HTTP
7
+ def self.call(method, path, params={})
8
+ raise 'Use typhoeus or write this your damn yourself!'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Restful
2
+ module Backends
3
+ class Typhoeus
4
+ def self.call(method, path, params={})
5
+ response = ::Typhoeus::Request.run(path, :method => method, :params => params)
6
+ Configuration.parser.decode(response.body)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ module Restful
2
+ module Configuration
3
+ extend self
4
+
5
+ def backend
6
+ @backend ||= Backends::Typhoeus
7
+ end
8
+
9
+ def backend=(backend)
10
+ @backend = backend
11
+ end
12
+
13
+ def domain
14
+ @domain or raise 'You must define a domain: Restful::Configuration.domain = "www.example.com"'
15
+ end
16
+
17
+ def domain=(domain)
18
+ @domain = domain
19
+ end
20
+
21
+ def parser
22
+ @parser ||= MultiJson
23
+ end
24
+
25
+ def parser=(parser)
26
+ @parser = parser
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ module Restful
2
+ module Request
3
+ extend self
4
+
5
+ def post(model_name, attrs)
6
+ Configuration.backend.call(:post, resourceify(model_name), attrs)
7
+ end
8
+
9
+ def get(model_name, attrs)
10
+ Configuration.backend.call(:get, resourceify(model_name), attrs)
11
+ end
12
+
13
+ def put(model_name, id, attrs)
14
+ Configuration.backend.call(:put, resourceify(model_name, id), model_name.downcase => attrs)
15
+ end
16
+
17
+ def delete(model_name, id)
18
+ Configuration.backend.call(:delete, resourceify(model_name, id))
19
+ end
20
+
21
+ def resourceify(model_name, id=nil)
22
+ [Configuration.domain, model_name.downcase.pluralize, id].compact.join('/')
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ module DataMapper
2
+ module Adapters
3
+ module RestfulAdapter
4
+ VERSION = '0.0.1'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ require 'dm-core'
2
+ require 'typhoeus'
3
+ require 'multi_json'
4
+ require 'dm-restful-adapter/version'
5
+
6
+ module Restful
7
+ autoload :Adapter, 'dm-restful-adapter/adapter'
8
+ autoload :Request, 'dm-restful-adapter/request'
9
+ autoload :Configuration, 'dm-restful-adapter/configuration'
10
+
11
+ module Backends
12
+ module Net
13
+ autoload :HTTP, 'dm-restful-adapter/backends/net_http'
14
+ end
15
+ autoload :Typhoeus, 'dm-restful-adapter/backends/typhoeus'
16
+ end
17
+ end
18
+
19
+ DataMapper::Adapters::RestfulAdapter = Restful::Adapter
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'dm-core/spec/shared/adapter_spec'
4
+
5
+ describe DataMapper::Adapters::RestfulAdapter do
6
+ before :all do
7
+ @adapter = DataMapper.setup(:default, :adapter => 'restful')
8
+ end
9
+
10
+ def self.described_type
11
+ described_class
12
+ end
13
+
14
+ it_should_behave_like 'An Adapter'
15
+ end
@@ -0,0 +1,31 @@
1
+ require 'dm-restful-adapter'
2
+ require 'spec/support/mimic'
3
+ require 'database_cleaner'
4
+
5
+ # This file was generated by the `rspec --init` command. Conventionally, all
6
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
7
+ # Require this file using `require "spec_helper.rb"` to ensure that it is only
8
+ # loaded once.
9
+ #
10
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
11
+ RSpec.configure do |config|
12
+ config.treat_symbols_as_metadata_keys_with_true_values = true
13
+ config.run_all_when_everything_filtered = true
14
+ config.fail_fast = true
15
+ config.filter_run :focus
16
+
17
+ config.before(:suite) do
18
+ DatabaseCleaner.strategy = :transaction
19
+ DatabaseCleaner.clean_with(:truncation)
20
+ end
21
+
22
+ config.before(:each) do
23
+ DatabaseCleaner.start
24
+ end
25
+
26
+ config.after(:each) do
27
+ DatabaseCleaner.clean
28
+ end
29
+ end
30
+
31
+ Restful::Configuration.domain = 'http://localhost:4000'
@@ -0,0 +1,2 @@
1
+ adapter: sqlite3
2
+ database: ":memory:"
@@ -0,0 +1,9 @@
1
+ class CreateHeffalumpModels < ActiveRecord::Migration
2
+ def change
3
+ create_table :heffalump_models do |t|
4
+ t.string :color
5
+ t.integer :num_spots
6
+ t.boolean :striped
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,115 @@
1
+ require 'mimic'
2
+ require 'active_record'
3
+ require 'spec/support/setup_mimic_db'
4
+
5
+ class HeffalumpModel < ActiveRecord::Base
6
+ self.include_root_in_json = false
7
+
8
+ def self.search(params)
9
+ params = format_params(params)
10
+ params, regex_params = extract_regex_params(params)
11
+ result = query(params)
12
+ filter_from_regexps(regex_params, result)
13
+ end
14
+
15
+ def self.format_params(params)
16
+ params.inject({}) do |new_hash, (k, v)|
17
+ new_hash.merge(k => coerce_value(v))
18
+ end
19
+ end
20
+
21
+ def self.coerce_value(value)
22
+ case value
23
+ when /(.+)(\.{3})(.+)/
24
+ Range.new($1.to_i, $3.to_i - 1)
25
+ when /(.+)(\.{2})(.+)/
26
+ Range.new($1.to_i, $3.to_i)
27
+ when /\(\?[m|i|x|\-]{4}\:.*\)/
28
+ Regexp.new(value)
29
+ else
30
+ value
31
+ end
32
+ end
33
+
34
+ def self.extract_regex_params(params)
35
+ params.partition { |k,v| !v.is_a?(Regexp) }
36
+ end
37
+
38
+ def self.query(params)
39
+ params.inject(scoped) do |s, (k, v)|
40
+ s = case k
41
+ when /(.*)(\.not)/
42
+ s.where(arel_table[$1].not_in(v))
43
+ when /(.*)(\.gte)$/
44
+ s.where(arel_table[$1].gteq(v))
45
+ when /(.*)(\.gt)$/
46
+ s.where(arel_table[$1].gt(v))
47
+ when /(.*)(\.lte)$/
48
+ s.where(arel_table[$1].lteq(v))
49
+ when /(.*)(\.lt)$/
50
+ s.where(arel_table[$1].lt(v))
51
+ when /(.*)(\.like)/
52
+ s.where(arel_table[$1].matches(v))
53
+ when 'limit'
54
+ s.limit(v)
55
+ when 'conditions'
56
+ s.where(:num_spots => 5)
57
+ when 'order'
58
+ s.order(v)
59
+ when 'offset'
60
+ s.offset(v)
61
+ else
62
+ s.where(k => v)
63
+ end
64
+ end
65
+ end
66
+
67
+ def self.filter_from_regexps(params, result)
68
+ params.each do |k,v|
69
+ result = case k
70
+ when /(.*)(\.not)/
71
+ result.reject { |rec| v.match rec[$1] }
72
+ else
73
+ result.select { |rec| v.match rec[k] }
74
+ end
75
+ end
76
+ result
77
+ end
78
+ end
79
+
80
+ Mimic.mimic(:port => 4000) do
81
+ post "/heffalumps" do
82
+ heffalump = HeffalumpModel.new(params)
83
+ if heffalump.save
84
+ response = heffalump.to_json
85
+ [200, {'Content-Type' => 'application/json', 'Content-Length' => response.bytesize}, response]
86
+ else
87
+ response = heffalump.to_json
88
+ [422, {'Content-Type' => 'application/json', 'Content-Length' => response.bytesize}, response]
89
+ end
90
+ end
91
+
92
+ get "/heffalumps" do
93
+ if params.empty?
94
+ lumps = HeffalumpModel.all
95
+ else
96
+ lumps = HeffalumpModel.search(params)
97
+ end
98
+ response = lumps.to_json
99
+ [200, {'Content-Type' => 'application/json', 'Content-Length' => response.bytesize}, response]
100
+ end
101
+
102
+ put "/heffalumps/:id" do
103
+ heffalump = HeffalumpModel.find(params['id'])
104
+ heffalump.update_attributes(params['heffalump'])
105
+ response = heffalump.to_json
106
+ [200, {'Content-Type' => 'application/json', 'Content-Length' => response.bytesize}, response]
107
+ end
108
+
109
+ delete "/heffalumps/:id" do
110
+ heffalump = HeffalumpModel.find(params['id'])
111
+ heffalump.destroy
112
+ response = [].to_json
113
+ [200, {'Content-Type' => 'application/json', 'Content-Length' => response.bytesize}, response]
114
+ end
115
+ end
@@ -0,0 +1,17 @@
1
+ dbconf = YAML::load(File.open('spec/support/database.yml'))
2
+ ActiveRecord::Base.establish_connection(dbconf)
3
+
4
+ class ActiveRecord::Base
5
+ mattr_accessor :shared_connection
6
+ @@shared_connection = nil
7
+
8
+ def self.connection
9
+ @@shared_connection || retrieve_connection
10
+ end
11
+ end
12
+
13
+ # Forces all threads to share the same connection. This works on
14
+ # Capybara because it starts the web server in a thread.
15
+ ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
16
+ ActiveRecord::Base.logger = Logger.new($STDOUT)
17
+ ActiveRecord::Migrator.up('spec/support/migrations')
metadata ADDED
@@ -0,0 +1,199 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-restful-adapter
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Ryan Moran
14
+ - Hubert Huang
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2012-04-11 00:00:00 -07:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: dm-core
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - "="
29
+ - !ruby/object:Gem::Version
30
+ hash: 29
31
+ segments:
32
+ - 1
33
+ - 2
34
+ - 1
35
+ version: 1.2.1
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: multi_json
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 3
47
+ segments:
48
+ - 0
49
+ version: "0"
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: rspec
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 43
61
+ segments:
62
+ - 2
63
+ - 9
64
+ - 0
65
+ version: 2.9.0
66
+ type: :development
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: mimic
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ hash: 9
77
+ segments:
78
+ - 0
79
+ - 4
80
+ - 3
81
+ version: 0.4.3
82
+ type: :development
83
+ version_requirements: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ name: activerecord
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ hash: 3
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ type: :development
97
+ version_requirements: *id005
98
+ - !ruby/object:Gem::Dependency
99
+ name: sqlite3
100
+ prerelease: false
101
+ requirement: &id006 !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ type: :development
111
+ version_requirements: *id006
112
+ - !ruby/object:Gem::Dependency
113
+ name: database_cleaner
114
+ prerelease: false
115
+ requirement: &id007 !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ hash: 3
121
+ segments:
122
+ - 0
123
+ version: "0"
124
+ type: :development
125
+ version_requirements: *id007
126
+ description: Modular adapter for datamapper to access remote resources restfully
127
+ email:
128
+ - ryan.moran@gmail.com
129
+ - hubert77@gmail.com
130
+ executables: []
131
+
132
+ extensions: []
133
+
134
+ extra_rdoc_files: []
135
+
136
+ files:
137
+ - .autotest
138
+ - .gitignore
139
+ - .rbenv-gemsets
140
+ - .rspec
141
+ - Gemfile
142
+ - LICENSE
143
+ - README.md
144
+ - Rakefile
145
+ - dm-restful-adapter.gemspec
146
+ - lib/dm-restful-adapter.rb
147
+ - lib/dm-restful-adapter/adapter.rb
148
+ - lib/dm-restful-adapter/backends/net_http.rb
149
+ - lib/dm-restful-adapter/backends/typhoeus.rb
150
+ - lib/dm-restful-adapter/configuration.rb
151
+ - lib/dm-restful-adapter/request.rb
152
+ - lib/dm-restful-adapter/version.rb
153
+ - spec/dm-restful-adapter_spec.rb
154
+ - spec/spec_helper.rb
155
+ - spec/support/database.yml
156
+ - spec/support/migrations/1_create_heffalump_models.rb
157
+ - spec/support/mimic.rb
158
+ - spec/support/setup_mimic_db.rb
159
+ has_rdoc: true
160
+ homepage: https://github.com/optimis/dm-restful-adapter
161
+ licenses: []
162
+
163
+ post_install_message:
164
+ rdoc_options: []
165
+
166
+ require_paths:
167
+ - lib
168
+ required_ruby_version: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ hash: 3
174
+ segments:
175
+ - 0
176
+ version: "0"
177
+ required_rubygems_version: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ hash: 3
183
+ segments:
184
+ - 0
185
+ version: "0"
186
+ requirements: []
187
+
188
+ rubyforge_project:
189
+ rubygems_version: 1.6.2
190
+ signing_key:
191
+ specification_version: 3
192
+ summary: ""
193
+ test_files:
194
+ - spec/dm-restful-adapter_spec.rb
195
+ - spec/spec_helper.rb
196
+ - spec/support/database.yml
197
+ - spec/support/migrations/1_create_heffalump_models.rb
198
+ - spec/support/mimic.rb
199
+ - spec/support/setup_mimic_db.rb