citier 0.1.12 → 0.1.13
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/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/"
|