activerecord-tablefree 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.travis.yml +10 -0
- data/Appraisals +11 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +25 -0
- data/README.md +175 -0
- data/Rakefile +48 -0
- data/activerecord-tablefree.gemspec +46 -0
- data/features/basic_integration.feature +16 -0
- data/features/step_definitions/rails_steps.rb +141 -0
- data/features/step_definitions/tablefree.rb +37 -0
- data/features/step_definitions/web_steps.rb +140 -0
- data/features/support/env.rb +15 -0
- data/features/support/paths.rb +28 -0
- data/features/support/rails.rb +52 -0
- data/features/support/selectors.rb +19 -0
- data/gemfiles/rails50.gemfile +11 -0
- data/gemfiles/rails51.gemfile +11 -0
- data/init.rb +4 -0
- data/lib/activerecord-tablefree.rb +318 -0
- data/lib/activerecord-tablefree/version.rb +7 -0
- data/spec/lib/activerecord-tablefree_spec.rb +284 -0
- data/spec/spec_helper.rb +2 -0
- metadata +300 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
Given /^I delete all migrations$/ do
|
2
|
+
steps %{
|
3
|
+
When I successfully run `bash -c 'rm db/migrate/*.rb'`
|
4
|
+
}
|
5
|
+
end
|
6
|
+
|
7
|
+
Given /^I update my new user model to be tablefree$/ do
|
8
|
+
in_current_dir do
|
9
|
+
file_name = 'app/models/user.rb'
|
10
|
+
content = File.read(file_name)
|
11
|
+
if framework_version < "3.0"
|
12
|
+
content = "require 'activerecord-tablefree'\n" + content
|
13
|
+
end
|
14
|
+
|
15
|
+
content.gsub!(/^(class .* < ActiveRecord::Base)$/, "\\1\n" + <<-TABLELESS)
|
16
|
+
has_no_table
|
17
|
+
column :id, :integer
|
18
|
+
column :name, :string
|
19
|
+
|
20
|
+
TABLELESS
|
21
|
+
File.open(file_name, 'w') { |f| f << content }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Given /^I update my users controller to render instead of redirect$/ do
|
26
|
+
in_current_dir do
|
27
|
+
transform_file('app/controllers/users_controller.rb') do |content|
|
28
|
+
##Changes in #create method
|
29
|
+
content.gsub!(/@user = User.new\((.*?)\)/,
|
30
|
+
'@user = User.new(\1); @user.id = 1')
|
31
|
+
content.gsub!("if @user.save",
|
32
|
+
"if @user.valid?")
|
33
|
+
content.gsub!(/redirect_to([\( ])@user, .*?([\)]| \}|$)/,
|
34
|
+
"render\\1:action => 'show'\\2")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# TL;DR: YOU SHOULD DELETE THIS FILE
|
2
|
+
#
|
3
|
+
# This file was generated by Cucumber-Rails and is only here to get you a head start
|
4
|
+
# These step definitions are thin wrappers around the Capybara/Webrat API that lets you
|
5
|
+
# visit pages, interact with widgets and make assertions about page content.
|
6
|
+
#
|
7
|
+
# If you use these step definitions as basis for your features you will quickly end up
|
8
|
+
# with features that are:
|
9
|
+
#
|
10
|
+
# * Hard to maintain
|
11
|
+
# * Verbose to read
|
12
|
+
#
|
13
|
+
# A much better approach is to write your own higher level step definitions, following
|
14
|
+
# the advice in the following blog posts:
|
15
|
+
#
|
16
|
+
# * http://benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories.html
|
17
|
+
# * http://dannorth.net/2011/01/31/whose-domain-is-it-anyway/
|
18
|
+
# * http://elabs.se/blog/15-you-re-cuking-it-wrong
|
19
|
+
#
|
20
|
+
|
21
|
+
|
22
|
+
require 'uri'
|
23
|
+
require 'cgi'
|
24
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
|
25
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "selectors"))
|
26
|
+
|
27
|
+
module WithinHelpers
|
28
|
+
def with_scope(locator)
|
29
|
+
locator ? within(*selector_for(locator)) { yield } : yield
|
30
|
+
end
|
31
|
+
end
|
32
|
+
World(WithinHelpers)
|
33
|
+
|
34
|
+
# Single-line step scoper
|
35
|
+
When /^(.*) within (.*[^:])$/ do |step, parent|
|
36
|
+
with_scope(parent) { When step }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Multi-line step scoper
|
40
|
+
When /^(.*) within (.*[^:]):$/ do |step, parent, table_or_string|
|
41
|
+
with_scope(parent) { When "#{step}:", table_or_string }
|
42
|
+
end
|
43
|
+
|
44
|
+
Given /^(?:|I )am on (.+)$/ do |page_name|
|
45
|
+
visit path_to(page_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
When /^(?:|I )go to (.+)$/ do |page_name|
|
49
|
+
visit path_to(page_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
When /^(?:|I )press "([^"]*)"$/ do |button|
|
53
|
+
click_button(button)
|
54
|
+
end
|
55
|
+
|
56
|
+
When /^(?:|I )follow "([^"]*)"$/ do |link|
|
57
|
+
click_link(link)
|
58
|
+
end
|
59
|
+
|
60
|
+
When /^(?:|I )fill in "([^"]*)" with "([^"]*)"$/ do |field, value|
|
61
|
+
fill_in(field, :with => value)
|
62
|
+
end
|
63
|
+
|
64
|
+
When /^(?:|I )fill in "([^"]*)" for "([^"]*)"$/ do |value, field|
|
65
|
+
fill_in(field, :with => value)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Use this to fill in an entire form with data from a table. Example:
|
69
|
+
#
|
70
|
+
# When I fill in the following:
|
71
|
+
# | Account Number | 5002 |
|
72
|
+
# | Expiry date | 2009-11-01 |
|
73
|
+
# | Note | Nice guy |
|
74
|
+
# | Wants Email? | |
|
75
|
+
#
|
76
|
+
# TODO: Add support for checkbox, select og option
|
77
|
+
# based on naming conventions.
|
78
|
+
#
|
79
|
+
When /^(?:|I )fill in the following:$/ do |fields|
|
80
|
+
fields.rows_hash.each do |name, value|
|
81
|
+
When %{I fill in "#{name}" with "#{value}"}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
When /^(?:|I )select "([^"]*)" from "([^"]*)"$/ do |value, field|
|
86
|
+
select(value, :from => field)
|
87
|
+
end
|
88
|
+
|
89
|
+
When /^(?:|I )check "([^"]*)"$/ do |field|
|
90
|
+
check(field)
|
91
|
+
end
|
92
|
+
|
93
|
+
When /^(?:|I )uncheck "([^"]*)"$/ do |field|
|
94
|
+
uncheck(field)
|
95
|
+
end
|
96
|
+
|
97
|
+
When /^(?:|I )choose "([^"]*)"$/ do |field|
|
98
|
+
choose(field)
|
99
|
+
end
|
100
|
+
|
101
|
+
When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"$/ do |path, field|
|
102
|
+
attach_file(field, File.expand_path(path))
|
103
|
+
end
|
104
|
+
|
105
|
+
Then /^(?:|I )should (not )?see "([^"]*)"$/ do |negate, text|
|
106
|
+
should_name = negate ? :should_not : :should
|
107
|
+
if page.respond_to? should_name
|
108
|
+
page.send should_name, have_content(text)
|
109
|
+
else
|
110
|
+
assert(negate ? page.has_no_content?(text) : page.has_content?(text))
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
Then /^(?:|I )should (not )?see \/([^\/]*)\/$/ do |negate, regexp|
|
115
|
+
regexp = Regexp.new(regexp)
|
116
|
+
should_name = negate ? :should_not : :should
|
117
|
+
if page.respond_to? should_name
|
118
|
+
page.send should_name, have_xpath('//*', :text => regexp)
|
119
|
+
else
|
120
|
+
assert(negate ? page.has_no_xpath?('//*', :text => regexp) : page.has_xpath?('//*', :text => regexp))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
Then /^(?:|I )should be on (.+)$/ do |page_name|
|
125
|
+
current_path = URI.parse(current_url).path
|
126
|
+
expect(current_path).to eq path_to(page_name)
|
127
|
+
end
|
128
|
+
|
129
|
+
Then /^(?:|I )should have the following query string:$/ do |expected_pairs|
|
130
|
+
query = URI.parse(current_url).query
|
131
|
+
actual_params = query ? CGI.parse(query) : {}
|
132
|
+
expected_params = {}
|
133
|
+
expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
|
134
|
+
|
135
|
+
expect(actual_params).to eq expected_params
|
136
|
+
end
|
137
|
+
|
138
|
+
Then /^show me the page$/ do
|
139
|
+
save_and_open_page
|
140
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#require 'bundler'
|
2
|
+
begin
|
3
|
+
Bundler.setup(:default, :development)
|
4
|
+
rescue Bundler::BundlerError => e
|
5
|
+
$stderr.puts e.message
|
6
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
7
|
+
exit e.status_code
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'aruba/cucumber'
|
11
|
+
require 'capybara/cucumber'
|
12
|
+
|
13
|
+
Before do
|
14
|
+
@aruba_timeout_seconds = 120
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module NavigationHelpers
|
2
|
+
# Maps a name to a path. Used by the
|
3
|
+
#
|
4
|
+
# When /^I go to (.+)$/ do |page_name|
|
5
|
+
#
|
6
|
+
# step definition in web_steps.rb
|
7
|
+
#
|
8
|
+
def path_to(page_name)
|
9
|
+
case page_name
|
10
|
+
|
11
|
+
when /the home\s?page/
|
12
|
+
'/'
|
13
|
+
when /the new user page/
|
14
|
+
'/users/new'
|
15
|
+
else
|
16
|
+
begin
|
17
|
+
page_name =~ /the (.*) page/
|
18
|
+
path_components = $1.split(/\s+/)
|
19
|
+
self.send(path_components.push('path').join('_').to_sym)
|
20
|
+
rescue Object => e
|
21
|
+
raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
|
22
|
+
"Now, go and add a mapping in #{__FILE__}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
World(NavigationHelpers)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
|
2
|
+
APP_NAME = 'testapp'.freeze
|
3
|
+
BUNDLE_ENV_VARS = %w(RUBYOPT BUNDLE_PATH BUNDLE_BIN_PATH BUNDLE_GEMFILE)
|
4
|
+
ORIGINAL_BUNDLE_VARS = Hash[ENV.select{ |key,value| BUNDLE_ENV_VARS.include?(key) }]
|
5
|
+
|
6
|
+
ENV['RAILS_ENV'] = 'test'
|
7
|
+
|
8
|
+
Before do
|
9
|
+
ENV['BUNDLE_GEMFILE'] = File.join(Dir.pwd, ENV['BUNDLE_GEMFILE']) unless ENV['BUNDLE_GEMFILE'].start_with?(Dir.pwd)
|
10
|
+
@framework_version = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
After do
|
14
|
+
ORIGINAL_BUNDLE_VARS.each_pair do |key, value|
|
15
|
+
ENV[key] = value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
When /^I reset Bundler environment variable$/ do
|
20
|
+
BUNDLE_ENV_VARS.each do |key|
|
21
|
+
ENV[key] = nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module RailsCommandHelpers
|
26
|
+
def framework_version?(version_string)
|
27
|
+
framework_version =~ /^#{version_string}/
|
28
|
+
end
|
29
|
+
|
30
|
+
def framework_version
|
31
|
+
@framework_version ||= `rails -v`[/^Rails (.+)$/, 1]
|
32
|
+
end
|
33
|
+
|
34
|
+
def framework_major_version
|
35
|
+
framework_version.split(".").first.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def new_application_command(app_name)
|
39
|
+
framework_major_version >= 3 ? "rails new #{app_name} --skip-sprockets --skip-javascript --skip-bundle" : "rails #{app_name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def generator_command
|
43
|
+
framework_major_version >= 3 ? "rails generate" : "script/generate"
|
44
|
+
end
|
45
|
+
|
46
|
+
def runner_command
|
47
|
+
framework_major_version >= 3 ? "rails runner" : "script/runner"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
World(RailsCommandHelpers)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module HtmlSelectorsHelpers
|
2
|
+
# Maps a name to a selector. Used primarily by the
|
3
|
+
#
|
4
|
+
# When /^(.+) within (.+)$/ do |step, scope|
|
5
|
+
#
|
6
|
+
# step definitions in web_steps.rb
|
7
|
+
#
|
8
|
+
def selector_for(locator)
|
9
|
+
case locator
|
10
|
+
when "the page"
|
11
|
+
"html > body"
|
12
|
+
else
|
13
|
+
raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
|
14
|
+
"Now, go and add a mapping in #{__FILE__}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
World(HtmlSelectorsHelpers)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "mime-types", "< 2.0", :platform => :ruby_18
|
6
|
+
gem "rubyzip", "< 1.0", :platform => :ruby_18
|
7
|
+
gem "byebug"
|
8
|
+
gem "rails", "~> 5.0.0"
|
9
|
+
gem "jquery-rails"
|
10
|
+
|
11
|
+
gemspec :path => "../"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "mime-types", "< 2.0", :platform => :ruby_18
|
6
|
+
gem "rubyzip", "< 1.0", :platform => :ruby_18
|
7
|
+
gem "byebug"
|
8
|
+
gem "rails", "~> 5.1.0"
|
9
|
+
gem "jquery-rails"
|
10
|
+
|
11
|
+
gemspec :path => "../"
|
data/init.rb
ADDED
@@ -0,0 +1,318 @@
|
|
1
|
+
# See #ActiveRecord::Tablefree
|
2
|
+
require 'activerecord-tablefree/version'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
|
6
|
+
# = ActiveRecord::Tablefree
|
7
|
+
#
|
8
|
+
# Allow classes to behave like ActiveRecord models, but without an associated
|
9
|
+
# database table. A great way to capitalize on validations. Based on the
|
10
|
+
# original post at http://www.railsweenie.com/forums/2/topics/724 (which seems
|
11
|
+
# to have disappeared from the face of the earth).
|
12
|
+
#
|
13
|
+
# = Example usage
|
14
|
+
#
|
15
|
+
# class ContactMessage < ActiveRecord::Base
|
16
|
+
#
|
17
|
+
# has_no_table
|
18
|
+
#
|
19
|
+
# column :name, :string
|
20
|
+
# column :email, :string
|
21
|
+
# column :message, :string
|
22
|
+
#
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# msg = ContactMessage.new( params[:msg] )
|
26
|
+
# if msg.valid?
|
27
|
+
# ContactMessageSender.deliver_message( msg )
|
28
|
+
# redirect_to :action => :sent
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
module Tablefree
|
32
|
+
require 'active_record'
|
33
|
+
|
34
|
+
class NoDatabase < StandardError; end
|
35
|
+
class Unsupported < StandardError; end
|
36
|
+
|
37
|
+
def self.included( base ) #:nodoc:
|
38
|
+
base.send :extend, ActsMethods
|
39
|
+
end
|
40
|
+
|
41
|
+
module ActsMethods #:nodoc:
|
42
|
+
|
43
|
+
# A model that needs to be tablefree will call this method to indicate
|
44
|
+
# it.
|
45
|
+
def has_no_table(options = {:database => :fail_fast})
|
46
|
+
raise ArgumentError.new("Invalid database option '#{options[:database]}'") unless [:fail_fast, :pretend_success].member? options[:database]
|
47
|
+
# keep our options handy
|
48
|
+
class_attribute :tablefree_options
|
49
|
+
self.tablefree_options = {
|
50
|
+
:database => options[:database],
|
51
|
+
:columns_hash => {}
|
52
|
+
}
|
53
|
+
|
54
|
+
# extend
|
55
|
+
extend ActiveRecord::Tablefree::SingletonMethods
|
56
|
+
extend ActiveRecord::Tablefree::ClassMethods
|
57
|
+
|
58
|
+
# include
|
59
|
+
include ActiveRecord::Tablefree::InstanceMethods
|
60
|
+
|
61
|
+
# setup columns
|
62
|
+
include ActiveModel::AttributeAssignment
|
63
|
+
include ActiveRecord::ModelSchema
|
64
|
+
end
|
65
|
+
|
66
|
+
def tablefree?
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
module SingletonMethods
|
73
|
+
|
74
|
+
# Used internally by ActiveRecord 5. This is the special hook that makes everything else work.
|
75
|
+
def load_schema!
|
76
|
+
@columns_hash = tablefree_options[:columns_hash].except(*ignored_columns)
|
77
|
+
@columns_hash.each do |name, column|
|
78
|
+
define_attribute(
|
79
|
+
name,
|
80
|
+
connection.lookup_cast_type_from_column(column),
|
81
|
+
default: column.default,
|
82
|
+
user_provided_default: false
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Register a new column.
|
88
|
+
def column(name, sql_type = nil, default = nil, null = true)
|
89
|
+
cast_type = "ActiveRecord::Type::#{sql_type.to_s.camelize}".constantize.new
|
90
|
+
tablefree_options[:columns_hash][name.to_s] = ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, cast_type, sql_type.to_s, null)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Register a set of columns with the same SQL type
|
94
|
+
def add_columns(sql_type, *args)
|
95
|
+
args.each do |col|
|
96
|
+
column col, sql_type
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def destroy(*args)
|
101
|
+
case tablefree_options[:database]
|
102
|
+
when :pretend_success
|
103
|
+
self.new()
|
104
|
+
when :fail_fast
|
105
|
+
raise NoDatabase.new("Can't #destroy on Tablefree class")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def destroy_all(*_args)
|
110
|
+
case tablefree_options[:database]
|
111
|
+
when :pretend_success
|
112
|
+
[]
|
113
|
+
when :fail_fast
|
114
|
+
raise NoDatabase.new("Can't #destroy_all on Tablefree class")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
case ActiveRecord::VERSION::MAJOR
|
119
|
+
when 5
|
120
|
+
def find_by_sql(*args)
|
121
|
+
case tablefree_options[:database]
|
122
|
+
when :pretend_success
|
123
|
+
[]
|
124
|
+
when :fail_fast
|
125
|
+
raise NoDatabase.new("Can't #find_by_sql on Tablefree class")
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
else
|
130
|
+
raise Unsupported.new("Unsupported ActiveRecord version")
|
131
|
+
end
|
132
|
+
|
133
|
+
def transaction(&block)
|
134
|
+
# case tablefree_options[:database]
|
135
|
+
# when :pretend_success
|
136
|
+
@_current_transaction_records ||= []
|
137
|
+
yield
|
138
|
+
# when :fail_fast
|
139
|
+
# raise NoDatabase.new("Can't #transaction on Tablefree class")
|
140
|
+
# end
|
141
|
+
end
|
142
|
+
|
143
|
+
def tablefree?
|
144
|
+
true
|
145
|
+
end
|
146
|
+
|
147
|
+
def table_exists?
|
148
|
+
false
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
module ClassMethods
|
153
|
+
|
154
|
+
def from_query_string(query_string)
|
155
|
+
unless query_string.blank?
|
156
|
+
params = query_string.split('&').collect do |chunk|
|
157
|
+
next if chunk.empty?
|
158
|
+
key, value = chunk.split('=', 2)
|
159
|
+
next if key.empty?
|
160
|
+
value = value.nil? ? nil : CGI.unescape(value)
|
161
|
+
[ CGI.unescape(key), value ]
|
162
|
+
end.compact.to_h
|
163
|
+
|
164
|
+
new(params)
|
165
|
+
else
|
166
|
+
new
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def connection
|
171
|
+
conn = Object.new()
|
172
|
+
def conn.quote_table_name(*_args)
|
173
|
+
""
|
174
|
+
end
|
175
|
+
def conn.quote_column_name(*_args)
|
176
|
+
""
|
177
|
+
end
|
178
|
+
def conn.substitute_at(*_args)
|
179
|
+
nil
|
180
|
+
end
|
181
|
+
def conn.schema_cache(*_args)
|
182
|
+
schema_cache = Object.new()
|
183
|
+
def schema_cache.columns_hash(*_args)
|
184
|
+
Hash.new()
|
185
|
+
end
|
186
|
+
schema_cache
|
187
|
+
end
|
188
|
+
# Fixes Issue #17. https://github.com/softace/activerecord-tablefree/issues/17
|
189
|
+
# The following method is from the ActiveRecord gem: /lib/active_record/connection_adapters/abstract/database_statements.rb .
|
190
|
+
# Sanitizes the given LIMIT parameter in order to prevent SQL injection.
|
191
|
+
#
|
192
|
+
# The +limit+ may be anything that can evaluate to a string via #to_s. It
|
193
|
+
# should look like an integer, or a comma-delimited list of integers, or
|
194
|
+
# an Arel SQL literal.
|
195
|
+
#
|
196
|
+
# Returns Integer and Arel::Nodes::SqlLiteral limits as is.
|
197
|
+
# Returns the sanitized limit parameter, either as an integer, or as a
|
198
|
+
# string which contains a comma-delimited list of integers.
|
199
|
+
def conn.sanitize_limit(limit)
|
200
|
+
if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
|
201
|
+
limit
|
202
|
+
elsif limit.to_s.include?(',')
|
203
|
+
Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
|
204
|
+
else
|
205
|
+
Integer(limit)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# Called by bound_attributes in /lib/active_record/relation/query_methods.rb
|
210
|
+
# Returns a SQL string with the from, join, where, and having clauses, in addition to the limit and offset.
|
211
|
+
def conn.combine_bind_parameters(**_args)
|
212
|
+
""
|
213
|
+
end
|
214
|
+
|
215
|
+
def conn.lookup_cast_type_from_column(*_args)
|
216
|
+
lct = Object.new
|
217
|
+
def lct.assert_valid_value(*_args)
|
218
|
+
true
|
219
|
+
end
|
220
|
+
# Needed for Rails 5.0
|
221
|
+
def lct.serialize(args)
|
222
|
+
args
|
223
|
+
end
|
224
|
+
def lct.deserialize(args)
|
225
|
+
args
|
226
|
+
end
|
227
|
+
def lct.cast(args)
|
228
|
+
args
|
229
|
+
end
|
230
|
+
def lct.changed?(*_args)
|
231
|
+
false
|
232
|
+
end
|
233
|
+
def lct.changed_in_place?(*_args)
|
234
|
+
false
|
235
|
+
end
|
236
|
+
lct
|
237
|
+
end
|
238
|
+
|
239
|
+
# This is used in the StatementCache object. It returns an object that
|
240
|
+
# can be used to query the database repeatedly.
|
241
|
+
def conn.cacheable_query(arel) # :nodoc:
|
242
|
+
if prepared_statements
|
243
|
+
ActiveRecord::StatementCache.query visitor, arel.ast
|
244
|
+
else
|
245
|
+
ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector
|
246
|
+
end
|
247
|
+
end
|
248
|
+
conn
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
module InstanceMethods
|
254
|
+
|
255
|
+
def to_query_string(prefix = nil)
|
256
|
+
attributes.to_a.collect{|(name,value)| escaped_var_name(name, prefix) + "=" + escape_for_url(value) if value }.compact.join("&")
|
257
|
+
end
|
258
|
+
|
259
|
+
def quote_value(_value, _column = nil)
|
260
|
+
""
|
261
|
+
end
|
262
|
+
|
263
|
+
%w(create create_record _create_record update update_record _update_record).each do |method_name|
|
264
|
+
define_method(method_name) do |*args|
|
265
|
+
case self.class.tablefree_options[:database]
|
266
|
+
when :pretend_success
|
267
|
+
true
|
268
|
+
when :fail_fast
|
269
|
+
raise NoDatabase.new("Can't ##{method_name} a Tablefree object")
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def destroy
|
275
|
+
case self.class.tablefree_options[:database]
|
276
|
+
when :pretend_success
|
277
|
+
@destroyed = true
|
278
|
+
freeze
|
279
|
+
when :fail_fast
|
280
|
+
raise NoDatabase.new("Can't #destroy a Tablefree object")
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def reload(*args)
|
285
|
+
case self.class.tablefree_options[:database]
|
286
|
+
when :pretend_success
|
287
|
+
self
|
288
|
+
when :fail_fast
|
289
|
+
raise NoDatabase.new("Can't #reload a Tablefree object")
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def add_to_transaction
|
294
|
+
end
|
295
|
+
|
296
|
+
private
|
297
|
+
|
298
|
+
def escaped_var_name(name, prefix = nil)
|
299
|
+
prefix ? "#{URI.escape(prefix)}[#{URI.escape(name)}]" : URI.escape(name)
|
300
|
+
end
|
301
|
+
|
302
|
+
def escape_for_url(value)
|
303
|
+
case value
|
304
|
+
when true then "1"
|
305
|
+
when false then "0"
|
306
|
+
when nil then ""
|
307
|
+
else URI.escape(value.to_s)
|
308
|
+
end
|
309
|
+
rescue
|
310
|
+
""
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
ActiveRecord::Base.send( :include, ActiveRecord::Tablefree )
|