citier 0.1.12 → 0.1.13
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/citier.gemspec +3 -1
- data/lib/citier.rb +4 -1
- data/lib/citier/acts_as_citier.rb +6 -4
- data/lib/citier/child_instance_methods.rb +88 -45
- data/lib/citier/class_methods.rb +34 -58
- data/lib/citier/core_ext.rb +64 -9
- data/lib/citier/instance_methods.rb +33 -26
- data/lib/citier/root_instance_methods.rb +41 -2
- data/lib/citier/sql_adapters.rb +96 -88
- metadata +25 -7
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
|
|
2
2
|
require 'rake'
|
3
3
|
require 'echoe'
|
4
4
|
|
5
|
-
Echoe.new('citier', '0.1.
|
5
|
+
Echoe.new('citier', '0.1.13') do |p|
|
6
6
|
p.description = "CITIER (Class Inheritance & Table Inheritance Embeddings for Rails) is a solution for single and multiple class table inheritance.
|
7
7
|
For full information: http://peterhamilton.github.com/citier/
|
8
8
|
For the original version by ALTRABio see www.github.com/altrabio/"
|
data/citier.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{citier}
|
5
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.13"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Peter Hamilton, Originally from Laurent Buffat, Pierre-Emmanuel Jouve"]
|
@@ -36,6 +36,8 @@ Gem::Specification.new do |s|
|
|
36
36
|
s.rubyforge_project = %q{citier}
|
37
37
|
s.rubygems_version = %q{1.3.7}
|
38
38
|
s.summary = s.description
|
39
|
+
|
40
|
+
s.add_dependency('rails_sql_views') #needs the 'rails_sql_views', :git => 'git://github.com/morgz/rails_sql_views.git' fork. Set this in your apps bundle
|
39
41
|
|
40
42
|
if s.respond_to? :specification_version then
|
41
43
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
data/lib/citier.rb
CHANGED
@@ -24,4 +24,7 @@ require 'citier/child_instance_methods'
|
|
24
24
|
require 'citier/sql_adapters'
|
25
25
|
|
26
26
|
#Require acts_as_citier hook
|
27
|
-
require 'citier/acts_as_citier'
|
27
|
+
require 'citier/acts_as_citier'
|
28
|
+
|
29
|
+
# Methods that override ActiveRecord::Relation
|
30
|
+
require 'citier/relation_methods'
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module Citier
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
module ActsAsCitier
|
3
|
+
def self.included(base)
|
4
|
+
# When a class includes a module the module’s self.included method will be invoked.
|
5
|
+
base.send :extend, Citier::ClassMethods
|
6
|
+
end
|
5
7
|
end
|
6
8
|
end
|
7
9
|
|
8
|
-
ActiveRecord::Base.send :include, Citier
|
10
|
+
ActiveRecord::Base.send :include, Citier::ActsAsCitier
|
@@ -1,59 +1,102 @@
|
|
1
|
-
module
|
1
|
+
module Citier
|
2
|
+
module ChildInstanceMethods
|
2
3
|
|
3
|
-
|
4
|
+
def save(options={})
|
5
|
+
return false if (options[:validate] != false && !self.valid?)
|
6
|
+
|
7
|
+
#citier_debug("Callback (#{self.inspect})")
|
8
|
+
citier_debug("SAVING #{self.class.to_s}")
|
9
|
+
|
10
|
+
#AIT NOTE: Will change any protected values back to original values so any models onwards won't see changes.
|
11
|
+
# Run save and create/update callbacks, just like ActiveRecord does
|
12
|
+
self.run_callbacks(:save) do
|
13
|
+
self.run_callbacks(self.new_record? ? :create : :update) do
|
14
|
+
#get the attributes of the class which are inherited from it's parent.
|
15
|
+
attributes_for_parent = self.attributes.reject { |key,value| !self.class.superclass.column_names.include?(key) }
|
16
|
+
changed_attributes_for_parent = self.changed_attributes.reject { |key,value| !self.class.superclass.column_names.include?(key) }
|
4
17
|
|
5
|
-
|
6
|
-
|
18
|
+
# Get the attributes of the class which are unique to this class and not inherited.
|
19
|
+
attributes_for_current = self.attributes.reject { |key,value| self.class.superclass.column_names.include?(key) }
|
20
|
+
changed_attributes_for_current = self.changed_attributes.reject { |key,value| self.class.superclass.column_names.include?(key) }
|
7
21
|
|
8
|
-
|
9
|
-
|
22
|
+
citier_debug("Attributes for #{self.class.superclass.to_s}: #{attributes_for_parent.inspect}")
|
23
|
+
citier_debug("Changed attributes for #{self.class.superclass.to_s}: #{changed_attributes_for_parent.keys.inspect}")
|
24
|
+
citier_debug("Attributes for #{self.class.to_s}: #{attributes_for_current.inspect}")
|
25
|
+
citier_debug("Changed attributes for #{self.class.to_s}: #{changed_attributes_for_current.keys.inspect}")
|
10
26
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
27
|
+
########
|
28
|
+
#
|
29
|
+
# Parent saving
|
30
|
+
|
31
|
+
#create a new instance of the superclass, passing the inherited attributes.
|
32
|
+
parent = self.class.superclass.new
|
33
|
+
|
34
|
+
parent.force_attributes(attributes_for_parent, :merge => true)
|
35
|
+
changed_attributes_for_parent["id"] = 0 # We need to change at least something to force a timestamps update.
|
36
|
+
parent.force_changed_attributes(changed_attributes_for_parent)
|
37
|
+
|
38
|
+
parent.id = self.id if id
|
39
|
+
parent.type = self.type
|
40
|
+
|
41
|
+
parent.is_new_record(new_record?)
|
42
|
+
|
43
|
+
# If we're root (AR subclass) this will just be saved as normal through AR. If we're a child it will call this method again.
|
44
|
+
# It will try and save it's parent and then save itself through the Writable constant.
|
45
|
+
parent_saved = parent.save
|
46
|
+
self.id = parent.id
|
16
47
|
|
17
|
-
|
48
|
+
if !parent_saved
|
49
|
+
# Couldn't save parent class
|
50
|
+
citier_debug("Class (#{self.class.superclass.to_s}) could not be saved")
|
51
|
+
citier_debug("Errors = #{parent.errors.to_s}")
|
52
|
+
return false # Return false and exit run_callbacks :save and :create/:update, so the after_ callback won't run.
|
53
|
+
end
|
54
|
+
|
55
|
+
#End of parent saving
|
56
|
+
|
57
|
+
######
|
58
|
+
##
|
59
|
+
## Self Saving
|
60
|
+
##
|
18
61
|
|
19
|
-
|
20
|
-
|
62
|
+
# If there are attributes for the current class (unique & not inherited), save current model
|
63
|
+
if !attributes_for_current.empty?
|
64
|
+
current = self.class::Writable.new
|
65
|
+
|
66
|
+
current.force_attributes(attributes_for_current, :merge => true)
|
67
|
+
current.force_changed_attributes(changed_attributes_for_current)
|
68
|
+
|
69
|
+
current.id = self.id
|
70
|
+
current.is_new_record(new_record?)
|
71
|
+
|
72
|
+
current_saved = current.save
|
73
|
+
|
74
|
+
current.after_save_change_request if current.respond_to?('after_save_change_request') #Specific to an app I'm building
|
21
75
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
76
|
+
if !current_saved
|
77
|
+
citier_debug("Class (#{self.class.superclass.to_s}) could not be saved")
|
78
|
+
citier_debug("Errors = #{current.errors.to_s}")
|
79
|
+
return false # Return false and exit run_callbacks :save and :create/:update, so the after callback won't run.
|
80
|
+
end
|
81
|
+
end
|
27
82
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
current = self.class::Writable.new(attributes_for_current)
|
32
|
-
current.id = self.id
|
33
|
-
current.is_new_record(new_record?)
|
34
|
-
current_saved = current.save
|
35
|
-
|
36
|
-
# This is no longer a new record
|
37
|
-
is_new_record(false)
|
83
|
+
# at this point, parent_saved && current_saved
|
84
|
+
|
85
|
+
is_new_record(false) # This is no longer a new record
|
38
86
|
|
39
|
-
|
40
|
-
|
87
|
+
self.force_changed_attributes({}) # Reset changed_attributes so future changes will be tracked correctly
|
88
|
+
|
89
|
+
# No return, because we want the after callback to run.
|
90
|
+
end
|
41
91
|
end
|
92
|
+
return true
|
42
93
|
end
|
43
|
-
|
44
|
-
# Update root class with this 'type'
|
45
|
-
if parent_saved && current_saved
|
46
|
-
sql = "UPDATE #{self.class.root_class.table_name} SET #{self.class.inheritance_column} = '#{self.class.to_s}' WHERE id = #{self.id}"
|
47
|
-
citier_debug("SQL : #{sql}")
|
48
|
-
self.connection.execute(sql)
|
49
|
-
end
|
50
|
-
return parent_saved && current_saved
|
51
|
-
end
|
52
94
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
95
|
+
def save!(options={})
|
96
|
+
raise ActiveRecord::RecordInvalid.new(self) if (options[:validate] != false && !self.valid?)
|
97
|
+
self.save || raise(ActiveRecord::RecordNotSaved)
|
98
|
+
end
|
57
99
|
|
58
|
-
|
100
|
+
include InstanceMethods
|
101
|
+
end
|
59
102
|
end
|
data/lib/citier/class_methods.rb
CHANGED
@@ -1,74 +1,50 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
1
|
+
module Citier
|
2
|
+
module ClassMethods
|
3
|
+
# any method placed here will apply to classes
|
4
|
+
def acts_as_citier(options = {})
|
5
|
+
set_acts_as_citier(true)
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
+
# Option for setting the inheritance columns, default value = 'type'
|
8
|
+
db_type_field = (options[:db_type_field] || :type).to_s
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
+
#:table_name = option for setting the name of the current class table_name, default value = 'tableized(current class name)'
|
11
|
+
table_name = (options[:table_name] || self.name.tableize.gsub(/\//,'_')).to_s
|
10
12
|
|
11
|
-
|
13
|
+
set_inheritance_column "#{db_type_field}"
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
+
if(self.superclass!=ActiveRecord::Base)
|
16
|
+
# Non root-class
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
+
citier_debug("Non Root Class")
|
19
|
+
citier_debug("table_name -> #{table_name}")
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
+
# Set up the table which contains ALL attributes we want for this class
|
22
|
+
set_table_name "view_#{table_name}"
|
21
23
|
|
22
|
-
|
24
|
+
citier_debug("tablename (view) -> #{self.table_name}")
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
else
|
31
|
-
# Root class
|
32
|
-
|
33
|
-
after_save :updatetype
|
34
|
-
|
35
|
-
citier_debug("Root Class")
|
36
|
-
|
37
|
-
set_table_name "#{table_name}"
|
38
|
-
|
39
|
-
citier_debug("table_name -> #{self.table_name}")
|
40
|
-
#returns the root class (the highest inherited class before ActiveRecord)
|
41
|
-
def self.root_class
|
42
|
-
if(self.superclass!=ActiveRecord::Base)
|
43
|
-
self.superclass.root_class
|
44
|
-
else
|
45
|
-
return self
|
26
|
+
# The the Writable. References the write-able table for the class because
|
27
|
+
# save operations etc can't take place on the views
|
28
|
+
self.const_set("Writable", create_class_writable(self))
|
29
|
+
|
30
|
+
after_initialize do
|
31
|
+
self.id = nil if self.new_record? && self.id == 0
|
46
32
|
end
|
47
|
-
end
|
48
33
|
|
49
|
-
|
50
|
-
|
34
|
+
# Add the functions required for children only
|
35
|
+
send :include, Citier::ChildInstanceMethods
|
36
|
+
else
|
37
|
+
# Root class
|
51
38
|
|
52
|
-
|
53
|
-
return tuples.map{|x| x.reload} if tuples.kind_of?(Array)
|
39
|
+
citier_debug("Root Class")
|
54
40
|
|
55
|
-
#
|
56
|
-
# Can't use reload as would loop inifinitely, so do a search by id instead.
|
57
|
-
# Probably a nice way of cleaning this a bit
|
58
|
-
return tuples.class.where(tuples.class[:id].eq(tuples.id))[0]
|
59
|
-
end
|
41
|
+
set_table_name "#{table_name}"
|
60
42
|
|
61
|
-
|
62
|
-
# In fact destroy_all will explicitly call a destroy method on each object
|
63
|
-
# whereas delete_all doesn't and only calls specific SQL requests.
|
64
|
-
# To be even more precise call delete_all with special conditions
|
65
|
-
def self.delete_all
|
66
|
-
#call delete method for each instance of the class
|
67
|
-
self.all.each{|o| o.delete }
|
68
|
-
end
|
43
|
+
citier_debug("table_name -> #{self.table_name}")
|
69
44
|
|
70
|
-
|
71
|
-
|
45
|
+
# Add the functions required for root classes only
|
46
|
+
send :include, Citier::RootInstanceMethods
|
47
|
+
end
|
72
48
|
end
|
73
49
|
end
|
74
|
-
end
|
50
|
+
end
|
data/lib/citier/core_ext.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
class ActiveRecord::Base
|
1
|
+
class ActiveRecord::Base
|
2
|
+
|
3
|
+
def self.set_acts_as_citier(citier)
|
4
|
+
@acts_as_citier = citier
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.acts_as_citier?
|
8
|
+
@acts_as_citier || false
|
9
|
+
end
|
2
10
|
|
3
11
|
def self.[](column_name)
|
4
12
|
arel_table[column_name]
|
@@ -7,14 +15,11 @@ class ActiveRecord::Base
|
|
7
15
|
def is_new_record(state)
|
8
16
|
@new_record = state
|
9
17
|
end
|
10
|
-
|
11
|
-
def self.all(*args)
|
12
|
-
# For some reason need to override this so it uses my modified find function which reloads each object to pull in all properties.
|
13
|
-
return find(:all, *args)
|
14
|
-
end
|
15
18
|
|
16
19
|
def self.create_class_writable(class_reference) #creation of a new class which inherits from ActiveRecord::Base
|
17
20
|
Class.new(ActiveRecord::Base) do
|
21
|
+
include Citier::InstanceMethods::ForcedWriters
|
22
|
+
|
18
23
|
t_name = class_reference.table_name
|
19
24
|
t_name = t_name[5..t_name.length]
|
20
25
|
|
@@ -30,6 +35,16 @@ class ActiveRecord::Base
|
|
30
35
|
end
|
31
36
|
|
32
37
|
def create_citier_view(theclass) #function for creating views for migrations
|
38
|
+
# flush any column info in memory
|
39
|
+
# Loops through and stops once we've cleaned up to our root class.
|
40
|
+
# We MUST user Writable as that is the place where changes might reside!
|
41
|
+
reset_class = theclass::Writable
|
42
|
+
until reset_class == ActiveRecord::Base
|
43
|
+
citier_debug("Resetting column information on #{reset_class}")
|
44
|
+
reset_class.reset_column_information
|
45
|
+
reset_class = reset_class.superclass
|
46
|
+
end
|
47
|
+
|
33
48
|
self_columns = theclass::Writable.column_names.select{ |c| c != "id" }
|
34
49
|
parent_columns = theclass.superclass.column_names.select{ |c| c != "id" }
|
35
50
|
columns = parent_columns+self_columns
|
@@ -37,13 +52,53 @@ def create_citier_view(theclass) #function for creating views for migrations
|
|
37
52
|
self_write_table = theclass::Writable.table_name
|
38
53
|
parent_read_table = theclass.superclass.table_name
|
39
54
|
sql = "CREATE VIEW #{self_read_table} AS SELECT #{parent_read_table}.id, #{columns.join(',')} FROM #{parent_read_table}, #{self_write_table} WHERE #{parent_read_table}.id = #{self_write_table}.id"
|
55
|
+
|
56
|
+
#Use our rails_sql_views gem to create the view so we get it outputted to schema
|
57
|
+
create_view "#{self_read_table}", "SELECT #{parent_read_table}.id, #{columns.join(',')} FROM #{parent_read_table}, #{self_write_table} WHERE #{parent_read_table}.id = #{self_write_table}.id" do |v|
|
58
|
+
v.column :id
|
59
|
+
columns.each do |c|
|
60
|
+
v.column c.to_sym
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
40
64
|
citier_debug("Creating citier view -> #{sql}")
|
41
|
-
theclass.connection.execute sql
|
65
|
+
#theclass.connection.execute sql
|
66
|
+
|
67
|
+
|
42
68
|
end
|
43
69
|
|
44
70
|
def drop_citier_view(theclass) #function for dropping views for migrations
|
45
71
|
self_read_table = theclass.table_name
|
46
72
|
sql = "DROP VIEW #{self_read_table}"
|
73
|
+
|
74
|
+
drop_view(self_read_table.to_sym) #drop using our rails sql views gem
|
75
|
+
|
47
76
|
citier_debug("Dropping citier view -> #{sql}")
|
48
|
-
theclass.connection.execute sql
|
49
|
-
end
|
77
|
+
#theclass.connection.execute sql
|
78
|
+
end
|
79
|
+
|
80
|
+
def update_citier_view(theclass) #function for updating views for migrations
|
81
|
+
|
82
|
+
citier_debug("Updating citier view for #{theclass}")
|
83
|
+
|
84
|
+
if theclass.table_exists?
|
85
|
+
drop_citier_view(theclass)
|
86
|
+
create_citier_view(theclass)
|
87
|
+
else
|
88
|
+
citier_debug("Error: #{theclass} VIEW doesn't exist.")
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
def create_or_update_citier_view(theclass) #Convienience function for updating or creating views for migrations
|
94
|
+
|
95
|
+
citier_debug("Create or Update citier view for #{theclass}")
|
96
|
+
|
97
|
+
if theclass.table_exists?
|
98
|
+
update_citier_view(theclass)
|
99
|
+
else
|
100
|
+
citier_debug("VIEW DIDN'T EXIST. Now creating for #{theclass}")
|
101
|
+
create_citier_view(theclass)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -1,30 +1,37 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
1
|
+
module Citier
|
2
|
+
module InstanceMethods
|
3
|
+
def self.included(base)
|
4
|
+
base.send :include, ForcedWriters
|
5
|
+
end
|
6
|
+
|
7
|
+
module ForcedWriters
|
8
|
+
def force_attributes(new_attributes, options = {})
|
9
|
+
new_attributes = @attributes.merge(new_attributes) if options[:merge]
|
10
|
+
@attributes = new_attributes
|
11
|
+
|
12
|
+
if options[:clear_caches] != false
|
13
|
+
@aggregation_cache = {}
|
14
|
+
@association_cache = {}
|
15
|
+
@attributes_cache = {}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def force_changed_attributes(new_changed_attributes, options = {})
|
20
|
+
new_changed_attributes = @attributes.merge(new_changed_attributes) if options[:merge]
|
21
|
+
@changed_attributes = new_changed_attributes
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# USAGE validates :attribute, :citier_uniqueness => true
|
26
|
+
# Needed because validates :attribute, :uniqueness => true Won't work because it tries to call child_class.attribute on parents table
|
27
|
+
class CitierUniquenessValidator < ActiveModel::EachValidator
|
28
|
+
def validate_each(object, attribute, value)
|
29
|
+
existing_record = object.class.where(attribute.to_sym => value).limit(1).first
|
30
|
+
if existing_record && existing_record.as_root != object.as_root #if prev record exist and it isn't our current obj
|
31
|
+
object.errors[attribute] << (options[:message] || "has already been taken.")
|
32
|
+
end
|
33
|
+
end
|
15
34
|
end
|
16
|
-
deleted &= c.delete(id)
|
17
|
-
return deleted
|
18
|
-
end
|
19
|
-
|
20
|
-
def updatetype
|
21
|
-
sql = "UPDATE #{self.class.root_class.table_name} SET #{self.class.inheritance_column} = '#{self.class.to_s}' WHERE id = #{self.id}"
|
22
|
-
self.connection.execute(sql)
|
23
|
-
citier_debug("#{sql}")
|
24
|
-
end
|
25
35
|
|
26
|
-
def destroy
|
27
|
-
return self.delete
|
28
36
|
end
|
29
|
-
|
30
37
|
end
|
@@ -1,5 +1,44 @@
|
|
1
|
-
module
|
1
|
+
module Citier
|
2
|
+
module RootInstanceMethods
|
2
3
|
|
3
|
-
|
4
|
+
include InstanceMethods
|
5
|
+
|
6
|
+
# Instantiates the instance as it's lowest root class. Used when destroying a root class to
|
7
|
+
# make sure we're not leaving children behind
|
8
|
+
def as_child
|
9
|
+
#instance_class = Object.const_get(self.type)
|
10
|
+
return bottom_class_instance = Kernel.const_get(self.type).where(:id => self.id).first
|
11
|
+
end
|
12
|
+
|
13
|
+
# Access the root class if ever you need.
|
14
|
+
def as_root
|
15
|
+
if !self.is_root?
|
16
|
+
root_class = self.class.base_class
|
4
17
|
|
18
|
+
#get the attributes of the class which are inherited from it's parent.
|
19
|
+
attributes_for_parent = self.attributes.reject{|key,value| !root_class.column_names.include?(key) }
|
20
|
+
|
21
|
+
#create a new instance of the superclass, passing the inherited attributes.
|
22
|
+
parent = root_class.new(attributes_for_parent)
|
23
|
+
parent.id = self.id
|
24
|
+
parent.type = self.type
|
25
|
+
|
26
|
+
parent.is_new_record(new_record?)
|
27
|
+
|
28
|
+
parent
|
29
|
+
else
|
30
|
+
self #just return self if we are the root
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#For testing whther we are using the framework or not
|
35
|
+
def acts_as_citier?
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def is_root?
|
40
|
+
self.class.superclass==ActiveRecord::Base
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
5
44
|
end
|
data/lib/citier/sql_adapters.rb
CHANGED
@@ -6,118 +6,126 @@
|
|
6
6
|
#------------------------------------------------------------------------------------------------#
|
7
7
|
|
8
8
|
require 'active_record'
|
9
|
-
require 'active_record/connection_adapters/sqlite_adapter'
|
10
|
-
require 'active_record/connection_adapters/sqlite3_adapter'
|
11
|
-
require 'active_record/connection_adapters/postgresql_adapter'
|
12
9
|
|
13
10
|
# SQLite
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
11
|
+
begin
|
12
|
+
require 'active_record/connection_adapters/sqlite_adapter'
|
13
|
+
require 'active_record/connection_adapters/sqlite3_adapter'
|
14
|
+
|
15
|
+
module ActiveRecord
|
16
|
+
module ConnectionAdapters
|
17
|
+
class SQLiteAdapter < AbstractAdapter
|
18
|
+
|
19
|
+
def tables(name = nil)
|
20
|
+
sql = <<-SQL
|
21
|
+
SELECT name
|
22
|
+
FROM sqlite_master
|
23
|
+
WHERE (type = 'table' or type='view') AND NOT name = 'sqlite_sequence'
|
24
|
+
SQL
|
25
|
+
# Modification : the where clause was intially WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
26
|
+
# now it is WHERE (type = 'table' or type='view') AND NOT name = 'sqlite_sequence'
|
27
|
+
# this modification is made to consider tables AND VIEWS as tables
|
28
|
+
|
29
|
+
execute(sql, name).map do |row|
|
30
|
+
row['name']
|
31
|
+
end
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
33
|
-
end
|
34
|
-
|
35
|
+
end
|
36
|
+
rescue Gem::LoadError
|
37
|
+
# not installed
|
35
38
|
end
|
36
39
|
|
37
|
-
|
38
40
|
# PostGreSQL
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
a=
|
41
|
+
begin
|
42
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
43
|
+
|
44
|
+
module ActiveRecord
|
45
|
+
module ConnectionAdapters
|
46
|
+
class PostgreSQLAdapter < AbstractAdapter
|
47
|
+
def tables(name = nil)
|
48
|
+
a=tablesL(name)
|
49
|
+
b=viewsL(name)
|
50
|
+
if(b!=[])
|
51
|
+
a=a+b
|
52
|
+
end
|
53
|
+
return a
|
47
54
|
end
|
48
|
-
return a
|
49
|
-
end
|
50
|
-
|
51
|
-
def tablesL(name = nil)
|
52
55
|
|
53
|
-
|
54
|
-
SELECT tablename
|
55
|
-
FROM pg_tables
|
56
|
-
WHERE schemaname = ANY (current_schemas(false))
|
57
|
-
SQL
|
58
|
-
end
|
59
|
-
def viewsL(name = nil)
|
56
|
+
def tablesL(name = nil)
|
60
57
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
58
|
+
query(<<-SQL, name).map { |row| row[0] }
|
59
|
+
SELECT tablename
|
60
|
+
FROM pg_tables
|
61
|
+
WHERE schemaname = ANY (current_schemas(false))
|
62
|
+
SQL
|
63
|
+
end
|
64
|
+
def viewsL(name = nil)
|
67
65
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
66
|
+
query(<<-SQL, name).map { |row| row[0] }
|
67
|
+
SELECT viewname
|
68
|
+
FROM pg_views
|
69
|
+
WHERE schemaname = ANY (current_schemas(false))
|
70
|
+
SQL
|
71
|
+
end
|
73
72
|
|
73
|
+
def table_exists?(name)
|
74
|
+
a=table_existsB?(name)
|
75
|
+
b=views_existsB?(name)
|
76
|
+
return a||b
|
77
|
+
end
|
74
78
|
|
75
|
-
def table_existsB?(name)
|
76
|
-
name = name.to_s
|
77
|
-
schema, table = name.split('.', 2)
|
78
79
|
|
79
|
-
|
80
|
-
|
81
|
-
schema =
|
82
|
-
end
|
80
|
+
def table_existsB?(name)
|
81
|
+
name = name.to_s
|
82
|
+
schema, table = name.split('.', 2)
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
84
|
+
unless table # A table was provided without a schema
|
85
|
+
table = schema
|
86
|
+
schema = nil
|
87
|
+
end
|
88
88
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
#{schema ? "AND schemaname = '#{schema}'" : ''}
|
94
|
-
SQL
|
89
|
+
if name =~ /^"/ # Handle quoted table names
|
90
|
+
table = name
|
91
|
+
schema = nil
|
92
|
+
end
|
95
93
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
94
|
+
query(<<-SQL).first[0].to_i > 0
|
95
|
+
SELECT COUNT(*)
|
96
|
+
FROM pg_tables
|
97
|
+
WHERE tablename = '#{table.gsub(/(^"|"$)/,'')}'
|
98
|
+
#{schema ? "AND schemaname = '#{schema}'" : ''}
|
99
|
+
SQL
|
100
100
|
|
101
|
-
unless table # A table was provided without a schema
|
102
|
-
table = schema
|
103
|
-
schema = nil
|
104
101
|
end
|
102
|
+
def views_existsB?(name)
|
103
|
+
name = name.to_s
|
104
|
+
schema, table = name.split('.', 2)
|
105
|
+
|
106
|
+
unless table # A table was provided without a schema
|
107
|
+
table = schema
|
108
|
+
schema = nil
|
109
|
+
end
|
110
|
+
|
111
|
+
if name =~ /^"/ # Handle quoted table names
|
112
|
+
table = name
|
113
|
+
schema = nil
|
114
|
+
end
|
115
|
+
|
116
|
+
query(<<-SQL).first[0].to_i > 0
|
117
|
+
SELECT COUNT(*)
|
118
|
+
FROM pg_views
|
119
|
+
WHERE viewname = '#{table.gsub(/(^"|"$)/,'')}'
|
120
|
+
#{schema ? "AND schemaname = '#{schema}'" : ''}
|
121
|
+
SQL
|
105
122
|
|
106
|
-
if name =~ /^"/ # Handle quoted table names
|
107
|
-
table = name
|
108
|
-
schema = nil
|
109
123
|
end
|
110
|
-
|
111
|
-
query(<<-SQL).first[0].to_i > 0
|
112
|
-
SELECT COUNT(*)
|
113
|
-
FROM pg_views
|
114
|
-
WHERE viewname = '#{table.gsub(/(^"|"$)/,'')}'
|
115
|
-
#{schema ? "AND schemaname = '#{schema}'" : ''}
|
116
|
-
SQL
|
117
|
-
|
118
124
|
end
|
119
125
|
end
|
120
|
-
end
|
126
|
+
end
|
127
|
+
rescue Gem::LoadError
|
128
|
+
# not installed
|
121
129
|
end
|
122
130
|
|
123
131
|
# MySQL
|
metadata
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: citier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 13
|
9
|
+
version: 0.1.13
|
6
10
|
platform: ruby
|
7
11
|
authors:
|
8
12
|
- Peter Hamilton, Originally from Laurent Buffat, Pierre-Emmanuel Jouve
|
@@ -12,8 +16,19 @@ cert_chain: []
|
|
12
16
|
|
13
17
|
date: 2011-04-29 00:00:00 +01:00
|
14
18
|
default_executable:
|
15
|
-
dependencies:
|
16
|
-
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rails_sql_views
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
17
32
|
description: |-
|
18
33
|
CITIER (Class Inheritance & Table Inheritance Embeddings for Rails) is a solution for single and multiple class table inheritance.
|
19
34
|
For full information: http://peterhamilton.github.com/citier/
|
@@ -59,21 +74,24 @@ rdoc_options:
|
|
59
74
|
require_paths:
|
60
75
|
- lib
|
61
76
|
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
-
none: false
|
63
77
|
requirements:
|
64
78
|
- - ">="
|
65
79
|
- !ruby/object:Gem::Version
|
80
|
+
segments:
|
81
|
+
- 0
|
66
82
|
version: "0"
|
67
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
-
none: false
|
69
84
|
requirements:
|
70
85
|
- - ">="
|
71
86
|
- !ruby/object:Gem::Version
|
87
|
+
segments:
|
88
|
+
- 1
|
89
|
+
- 2
|
72
90
|
version: "1.2"
|
73
91
|
requirements: []
|
74
92
|
|
75
93
|
rubyforge_project: citier
|
76
|
-
rubygems_version: 1.6
|
94
|
+
rubygems_version: 1.3.6
|
77
95
|
signing_key:
|
78
96
|
specification_version: 3
|
79
97
|
summary: "CITIER (Class Inheritance & Table Inheritance Embeddings for Rails) is a solution for single and multiple class table inheritance. For full information: http://peterhamilton.github.com/citier/ For the original version by ALTRABio see www.github.com/altrabio/"
|