kansas 0.9.0

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.
@@ -0,0 +1,179 @@
1
+ class KSTable
2
+
3
+ def KSTable.is_a_kstable?
4
+ true
5
+ end
6
+
7
+ def KSTable.field(localName, remoteName=nil, conversion=nil)
8
+ remoteName = localName unless remoteName
9
+
10
+ conversionCall = conversion ? ".#{conversion}" : ''
11
+ addField(localName, remoteName)
12
+
13
+ class_eval <<-EOS
14
+ def #{localName}
15
+ @row['#{remoteName}']#{conversionCall}
16
+ end
17
+
18
+ def #{localName}=(val)
19
+ unless pending_deletion? or read_only?
20
+ @rollback_buffer.push ['#{remoteName}', @row['#{remoteName}']]
21
+ @rollback_hash['#{remoteName}'] ||= []
22
+ @rollback_hash['#{remoteName}'].push @row['#{remoteName}']
23
+ @row['#{remoteName}'] = val
24
+ changed
25
+ end
26
+ end
27
+ EOS
28
+ end
29
+
30
+ # A table can have more than one primary field?
31
+
32
+ def KSTable.primary(field)
33
+ if defined?(@primaries) && @primaries
34
+ @primaries << field unless @primaries.include?(field)
35
+ else
36
+ @primaries = [field]
37
+ end
38
+ end
39
+
40
+ def KSTable.to_one(name, local_field, foreign_table, foreign_field = nil)
41
+ foreign_table = foreign_table.to_s if Symbol === foreign_table
42
+ if foreign_table.class.to_s == 'String'
43
+ if KSDatabase.partial_to_complete_map.has_key?(foreign_table)
44
+ foreign_table = KSDatabase.const_get KSDatabase.partial_to_complete_map[foreign_table]
45
+ else
46
+ foreign_table = nil
47
+ end
48
+ end
49
+
50
+ # Need to throw an exception if foregin_table is bad.
51
+
52
+ addRelation(name.to_s, KSToOne.new(self, local_field.to_s, foreign_table, foreign_field.to_s))
53
+ class_eval <<-EOS
54
+ def #{name}
55
+ self.class.relations['#{name}'].get(self)
56
+ end
57
+
58
+ def #{name}=(val)
59
+ self.class.relations['#{name}'].set(self, val)
60
+ end
61
+ EOS
62
+ end
63
+
64
+ def KSTable.belongs_to(name, foreign_table, local_field, foreign_field = nil)
65
+ foreign_table = foreign_table.to_s if Symbol === foreign_table
66
+ if foreign_table.class.to_s == 'String'
67
+ if KSDatabase.partial_to_complete_map.has_key?(foreign_table)
68
+ foreign_table = KSDatabase.const_get KSDatabase.partial_to_complete_map[foreign_table]
69
+ else
70
+ foreign_table = nil
71
+ end
72
+ end
73
+
74
+ # Need to throw an exception if foregin_table is bad.
75
+
76
+ addRelation(name.to_s, KSBelongsTo.new(self, foreign_table, local_field.to_s, foreign_field.to_s))
77
+ class_eval <<-EOS
78
+ def #{name}
79
+ self.class.relations['#{name}'].get(self)
80
+ end
81
+
82
+ def #{name}=(val)
83
+ self.class.relations['#{name}'].set(self, val)
84
+ end
85
+ EOS
86
+ end
87
+
88
+ def KSTable.to_many(name, foreign_table, foreign_field, local_field = nil)
89
+ foreign_table = foreign_table.to_s if Symbol === foreign_table
90
+ if foreign_table.class.to_s == 'String'
91
+ if KSDatabase.partial_to_complete_map.has_key?(foreign_table)
92
+ foreign_table = KSDatabase.const_get KSDatabase.partial_to_complete_map[foreign_table]
93
+ else
94
+ foreign_table = nil
95
+ end
96
+ end
97
+
98
+ # Need to throw an exception if foregin_table is bad.
99
+
100
+ addRelation(name.to_s, KSToMany.new(self, foreign_table, foreign_field.to_s, local_field.to_s))
101
+ class_eval <<-EOS
102
+ def #{name}
103
+ self.class.relations['#{name}'].get(self)
104
+ end
105
+
106
+ def #{name}_count
107
+ self.class.relations['#{name}'].count(self)
108
+ end
109
+ EOS
110
+ end
111
+
112
+ def KSTable.all_fields
113
+ database.query do |dbh|
114
+ dbh.columns(table_name).each do |descr|
115
+ fieldName = descr['name']
116
+ field(fieldName, fieldName, conversion(descr['type_name']))
117
+ if descr['primary']
118
+ primary fieldName
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ def KSTable.primaries
125
+ @primaries
126
+ end
127
+
128
+ def KSTable.table_name
129
+ class_eval 'Name'
130
+ end
131
+
132
+ def KSTable.database
133
+ class_eval 'Database'
134
+ end
135
+
136
+ def KSTable.fields
137
+ @fields
138
+ end
139
+
140
+ def KSTable.relations
141
+ @relations
142
+ end
143
+
144
+ private
145
+
146
+ def KSTable.addField(name, field)
147
+ if defined?(@fields) && @fields
148
+ @fields[name] = field
149
+ else
150
+ @fields = {name => field}
151
+ end
152
+ end
153
+
154
+ def KSTable.addRelation(name, relation)
155
+ if defined?(@relations)
156
+ @relations[name] = relation
157
+ else
158
+ @relations = {name => relation}
159
+ end
160
+ end
161
+
162
+ def KSTable.conversion(type)
163
+ case type
164
+ when /int/
165
+ :to_i
166
+ when /float/, /double/
167
+ :to_f
168
+ else
169
+ nil
170
+ end
171
+ end
172
+
173
+ def KSTable.canonical(fieldName)
174
+ newName = fieldName.mixcase
175
+ newName[0,1] = newName[0,1].downcase
176
+ newName
177
+ end
178
+
179
+ end
@@ -0,0 +1,13 @@
1
+ class KSToMany
2
+
3
+ def initialize(*args)
4
+ @localTable, @foreignTable, @foreignField, @localField = args
5
+ @localField = @localTable.primaries.first unless @localField != ''
6
+ end
7
+
8
+ def get(parent)
9
+ sql = "SELECT * FROM #{@foreignTable.table_name} " +
10
+ "WHERE #{@foreignField} = '#{parent.row[@localField]}'"
11
+ parent.context.select(@foreignTable, sql)
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ class KSToOne
2
+
3
+ attr_reader :foreignTable, :foreignField, :localTable, :localField
4
+
5
+ def initialize(*args)
6
+ @localTable, @localField, @foreignTable, @foreignField = args
7
+ @foreignField = @foreignTable.primaries.first unless @foreignField != ''
8
+ end
9
+
10
+ def get(parent)
11
+ if @foreignField != @foreignTable.primaries.first
12
+ sql = "SELECT * FROM #{@foreignTable.table_name} " +
13
+ "WHERE #{@foreignField} = '#{parent.row[@localField]}'"
14
+ parent.context.select(@foreignTable, sql).first
15
+ else
16
+ parent.context.get_object(@foreignTable, [parent.row[@localField]])
17
+ end
18
+ end
19
+
20
+ def set(parent, child)
21
+ parent.row[@localField] = child.row[@foreignField]
22
+ parent.changed
23
+ end
24
+
25
+ def join
26
+ "#{@localTable.table_name}.#{@localField} = #{@foreignTable.table_name}.#{@foreignField}"
27
+ end
28
+
29
+ end
@@ -0,0 +1,17 @@
1
+ class KSAdaptorRule
2
+ def initialize(args, &block)
3
+ @name = args[:name] # name of adaptor
4
+ @description = args[:description] # short description of what adaptor provides
5
+ @file = args[:file] # adaptor file to require
6
+ @priority = args[:priority] # rules with a lower priority will be checked first
7
+ @klass = args[:klass] # adaptor class
8
+ @block = block # code to determine if this adaptor should be used
9
+ end
10
+
11
+ def name; @name; end
12
+ def description; @description; end
13
+ def file; @file; end
14
+ def priority; @priority; end
15
+ def klass; @klass; end
16
+ def check(*args); @block.call(args); end
17
+ end
@@ -0,0 +1,24 @@
1
+ class KSAdaptors
2
+
3
+ @@list = Hash.new {|h,k| h[k] = []}
4
+
5
+ def KSAdaptors.<<(val)
6
+ @@list[val.priority] << val
7
+ end
8
+
9
+ def KSAdaptors[]=(key,val)
10
+ @@list[key] << val
11
+ end
12
+
13
+ def KSAdaptors[](key)
14
+ @@list[key]
15
+ end
16
+
17
+ def KSAdaptors.list
18
+ @@list
19
+ end
20
+
21
+ def KSAdaptors.to_s
22
+ @@list.inspect
23
+ end
24
+ end
@@ -0,0 +1,106 @@
1
+ class Object
2
+ def expr_body
3
+ to_s
4
+ end
5
+ end
6
+
7
+ class Array
8
+ def expr_body
9
+ collect {|e| e.expr_body}.join(',')
10
+ end
11
+ end
12
+
13
+ class String
14
+ def expr_body
15
+ KSDatabase.sql_escape(self)
16
+ end
17
+ end
18
+
19
+ class KSStandardSQLMixin
20
+ def select_sql(context)
21
+ distinct_fields = []
22
+ fields = []
23
+ context.select_table.fields.each_value do |f|
24
+ if context.distinct[f]
25
+ distinct_fields.push "distinct(#{@context.select}.#{f})"
26
+ else
27
+ fields.push "#{@context.select}.#{f}"
28
+ end
29
+ end
30
+
31
+ fields = distinct_fields.concat(fields)
32
+
33
+ selectedTables = context.tables.compact.flatten.uniq.join(',')
34
+ joinConstraints = context.joins.compact.flatten.uniq.join(' AND ')
35
+ #selected_rows = context.select.compact.flatten.uniq.collect {|t| "#{t}.*"}.join(',')
36
+
37
+ if joinConstraints != ""
38
+ joinConstraints << " AND "
39
+ end
40
+
41
+ #statement = "SELECT #{context.select}.* FROM #{selectedTables} WHERE #{joinConstraints} #{expr_body}"
42
+ statement = "SELECT #{fields.join(',')} FROM #{selectedTables} WHERE #{joinConstraints} #{expr_body}"
43
+ statement << ' ORDER BY ' << context.sort_fields.collect {|f| "#{f[0].respond_to?(:expr_body) ? f[0].expr_body : f[0].to_s} #{f[1]}"}.join(',') if context.sort_fields.length > 0
44
+ statement << ' LIMIT ' << context.limits.join(',') if context.limits.length > 0
45
+
46
+ statement
47
+ end
48
+
49
+ def count_sql(context)
50
+ selectedTables = context.tables.compact.flatten.uniq.join(',')
51
+ joinConstraints = context.joins.compact.flatten.uniq.join(' AND ')
52
+ #selected_rows = context.select.compact.flatten.uniq.collect {|t| "#{t}.*"}.join(',')
53
+
54
+ if joinConstraints != ""
55
+ joinConstraints << " AND "
56
+ end
57
+
58
+ statement = "SELECT count(*) FROM #{selectedTables} WHERE #{joinConstraints} #{expr_body}"
59
+ statement << ' ORDER BY ' << context.sort_fields.collect {|f| "#{f[0].respond_to?(:expr_body) ? f[0].expr_body : f[0].to_s} #{f[1]}"}.join(',') if context.sort_fields.length > 0
60
+ statement << ' LIMIT ' << context.limits.join(',') if @context.limits.length > 0
61
+
62
+ statement
63
+ end
64
+
65
+ def delete_sql(context)
66
+ selectedTables = context.tables.compact.flatten.uniq.join(",")
67
+ joinConstraints = context.joins.compact.flatten.uniq.join(" AND ")
68
+ if joinConstraints != ""
69
+ joinConstraints << " AND "
70
+ end
71
+
72
+ statement = "DELETE FROM #{selectedTables} WHERE #{joinConstraints} #{expr_body}"
73
+
74
+ statement
75
+ end
76
+
77
+ def build_where(object)
78
+ build_where_from_key(object, object.key)
79
+ end
80
+
81
+ def build_where_from_key(object, key, tableflag = false)
82
+ table = tableflag ? object : object.class
83
+ where = " WHERE "
84
+ where_ary = []
85
+ fields = table.primaries
86
+
87
+ fields.each_index do |i|
88
+ if !tableflag && object.rollback_hash[fields[i]]
89
+ val = object.rollback_hash[fields[i]].last
90
+ else
91
+ val = key[i]
92
+ end
93
+
94
+ where_ary.push "#{fields[i]} = #{KSDatabase.sql_escape(val)}"
95
+ end
96
+ where + where_ary.join(' AND ')
97
+ end
98
+
99
+ def build_update(object)
100
+ update = "UPDATE #{object.table_name} SET "
101
+ object.row.each do |field, val|
102
+ update << " #{field} = #{KSDatabase.sql_escape(val)},"
103
+ end
104
+ update.chop!
105
+ end
106
+ end
@@ -0,0 +1,8 @@
1
+ KSAdaptors << KSAdaptorRule.new(
2
+ :name => 'General DBI Adaptor',
3
+ :description => 'Provides a generalized access to DBI; this is equivalent to the behavior of the legacy Kansas.',
4
+ :file => '',
5
+ :priority => 1000
6
+ ) {|args|
7
+ # This code block determines if this adaptor might be able to handle the request.
8
+ }
@@ -0,0 +1,54 @@
1
+ module DBI
2
+
3
+ class Row
4
+ if RUBY_VERSION =~ /^1\.9/ || RUBY_VERSION =~ /^2/
5
+ def __getobj__
6
+ @arr
7
+ end
8
+
9
+ def __setobj__(obj)
10
+ @delegate_dc_obj = @arr = obj
11
+ end
12
+ else
13
+ def clone
14
+ Marshal.load(Marshal.dump(self))
15
+ end
16
+
17
+ def dup
18
+ row = self.class.allocate
19
+ row.instance_variable_set :@column_types, @column_types
20
+ row.instance_variable_set :@convert_types, @convert_types
21
+ row.instance_variable_set :@column_map, @column_map
22
+ row.instance_variable_set :@column_names, @column_names
23
+ # this is the only one we actually dup...
24
+ row.instance_variable_set :@arr, arr = @arr.dup
25
+ row.instance_variable_set :@_dc_obj, arr
26
+ row
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ class ColumnInfo
33
+ def initialize(hash=nil)
34
+ @hash = hash.dup rescue nil
35
+ @hash ||= Hash.new
36
+
37
+ # coerce all strings to symbols
38
+ @hash.keys.each do |x|
39
+ if x.kind_of? String
40
+ sym = x.to_sym
41
+ if @hash.has_key? sym
42
+ raise ::TypeError,
43
+ "#{self.class.name} may construct from a hash keyed with strings or symbols, but not both"
44
+ end
45
+ @hash[sym] = @hash[x]
46
+ @hash.delete(x)
47
+ end
48
+ end
49
+
50
+ super(@hash)
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,3 @@
1
+ module Kansas
2
+ VERSION = "0.9.0"
3
+ end