imparcial 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.
Files changed (59) hide show
  1. data/lib/imparcial/driver/base/expression/base.rb +104 -0
  2. data/lib/imparcial/driver/base/expression/delete.rb +72 -0
  3. data/lib/imparcial/driver/base/expression/index.rb +199 -0
  4. data/lib/imparcial/driver/base/expression/insert.rb +33 -0
  5. data/lib/imparcial/driver/base/expression/lock.rb +11 -0
  6. data/lib/imparcial/driver/base/expression/select.rb +36 -0
  7. data/lib/imparcial/driver/base/expression/sequence.rb +189 -0
  8. data/lib/imparcial/driver/base/expression/statement.rb +128 -0
  9. data/lib/imparcial/driver/base/expression/table_diff.rb +154 -0
  10. data/lib/imparcial/driver/base/expression/table_evolution.rb +94 -0
  11. data/lib/imparcial/driver/base/expression/table_metadata.rb +122 -0
  12. data/lib/imparcial/driver/base/expression/table_operation.rb +137 -0
  13. data/lib/imparcial/driver/base/expression/transaction.rb +59 -0
  14. data/lib/imparcial/driver/base/expression/update.rb +33 -0
  15. data/lib/imparcial/driver/base/expression/util.rb +45 -0
  16. data/lib/imparcial/driver/base/expression.rb +37 -0
  17. data/lib/imparcial/driver/base/result.rb +94 -0
  18. data/lib/imparcial/driver/base/sql/delete.rb +22 -0
  19. data/lib/imparcial/driver/base/sql/index.rb +53 -0
  20. data/lib/imparcial/driver/base/sql/insert.rb +63 -0
  21. data/lib/imparcial/driver/base/sql/select.rb +101 -0
  22. data/lib/imparcial/driver/base/sql/sequence.rb +55 -0
  23. data/lib/imparcial/driver/base/sql/table_metadata.rb +29 -0
  24. data/lib/imparcial/driver/base/sql/table_operation.rb +49 -0
  25. data/lib/imparcial/driver/base/sql/transaction.rb +43 -0
  26. data/lib/imparcial/driver/base/sql/update.rb +29 -0
  27. data/lib/imparcial/driver/base/sql.rb +25 -0
  28. data/lib/imparcial/driver/base/typemap.rb +214 -0
  29. data/lib/imparcial/driver/base/util.rb +41 -0
  30. data/lib/imparcial/driver/base.rb +156 -0
  31. data/lib/imparcial/driver/mysql/expression/index.rb +44 -0
  32. data/lib/imparcial/driver/mysql/expression/table.rb +26 -0
  33. data/lib/imparcial/driver/mysql/expression.rb +11 -0
  34. data/lib/imparcial/driver/mysql/result.rb +33 -0
  35. data/lib/imparcial/driver/mysql/sql/index.rb +51 -0
  36. data/lib/imparcial/driver/mysql/sql/sequence.rb +39 -0
  37. data/lib/imparcial/driver/mysql/sql/table_metadata.rb +43 -0
  38. data/lib/imparcial/driver/mysql/sql/table_operation.rb +20 -0
  39. data/lib/imparcial/driver/mysql/sql.rb +15 -0
  40. data/lib/imparcial/driver/mysql/typemap.rb +13 -0
  41. data/lib/imparcial/driver/mysql/util.rb +13 -0
  42. data/lib/imparcial/driver/mysql.rb +48 -0
  43. data/lib/imparcial/driver/postgre/expression/index.rb +10 -0
  44. data/lib/imparcial/driver/postgre/expression/sequence.rb +9 -0
  45. data/lib/imparcial/driver/postgre/expression/table.rb +20 -0
  46. data/lib/imparcial/driver/postgre/expression.rb +13 -0
  47. data/lib/imparcial/driver/postgre/result.rb +35 -0
  48. data/lib/imparcial/driver/postgre/sql/index.rb +53 -0
  49. data/lib/imparcial/driver/postgre/sql/sequence.rb +28 -0
  50. data/lib/imparcial/driver/postgre/sql/table_metadata.rb +46 -0
  51. data/lib/imparcial/driver/postgre/sql/table_operation.rb +9 -0
  52. data/lib/imparcial/driver/postgre/sql.rb +15 -0
  53. data/lib/imparcial/driver/postgre/typemap.rb +29 -0
  54. data/lib/imparcial/driver/postgre/util.rb +19 -0
  55. data/lib/imparcial/driver/postgre.rb +43 -0
  56. data/lib/imparcial/driver.rb +1 -0
  57. data/lib/imparcial/exception.rb +61 -0
  58. data/lib/imparcial.rb +82 -0
  59. metadata +114 -0
@@ -0,0 +1,214 @@
1
+ module Imparcial
2
+ module Driver
3
+ module TypemapBase
4
+
5
+ public
6
+
7
+ # Those are types shared among all databases.
8
+ # Of course they are not enough. Feel free to override them
9
+ # if necessary.
10
+
11
+ def regular_types
12
+
13
+ {
14
+ :integer => 'INTEGER',
15
+ :string => 'VARCHAR',
16
+ :float => 'FLOAT',
17
+ :datetime => 'DATETIME',
18
+ :time => 'TIME',
19
+ :date => 'DATE',
20
+ :text => 'TEXT',
21
+ :boolean => 'TINYINT',
22
+ :serial => 'SERIAL'
23
+ }
24
+
25
+ end
26
+
27
+ # The opposite of above.
28
+
29
+ def sql_types
30
+
31
+ regular_types.invert
32
+
33
+ end
34
+
35
+ # Default size can be very handy when users are lazy to supply them
36
+ # or they expect a given type to be in a default size.
37
+
38
+ def default_size_for_types
39
+
40
+ {
41
+ :string => 255,
42
+ :boolean => 1
43
+ }
44
+
45
+ end
46
+
47
+ public
48
+
49
+ # Transform regular user defined hash fields into a proper one.
50
+
51
+ def parse_field ( field )
52
+
53
+ # No name? error!
54
+
55
+ if not field[:name]
56
+
57
+ raise OptionError.new('A name must be supplied')
58
+
59
+ end
60
+
61
+ # No type? error!
62
+
63
+ if not field[:type]
64
+
65
+ raise OptionError.new('A type must be supplied')
66
+
67
+ end
68
+
69
+ # Simple conversions.
70
+
71
+ field[:name] = field[:name].to_s
72
+ field[:type] = field[:type].to_sym
73
+
74
+ # Set default size if nothing has been supplied.
75
+
76
+ field[:size] = default_size_for_types[field[:type]] unless field[:size]
77
+
78
+ # Primary key is set as false.
79
+
80
+ field[:pk] ||= false
81
+
82
+ # Allow Null is set as true.
83
+
84
+ field[:allow_null] = true if field[:allow_null] == nil
85
+
86
+ # let's verify if everything is okay.
87
+
88
+ if field[:auto_increment] && !field[:pk]
89
+
90
+ raise OptionError.new("To auto increment field must be primary key")
91
+
92
+ end
93
+
94
+ field[:indexed] ||= false
95
+
96
+ end
97
+
98
+ # In order to work with fields in RDBAL, you have to provide
99
+ # field datas in hashes.
100
+ # This function is basically evaluate them and pass into a block.
101
+
102
+ def parse_fields ( fields = [], &block )
103
+
104
+ # At least a field must be supplied.
105
+
106
+ raise OptionError.new unless fields
107
+ raise OptionError.new if fields.length < 1
108
+
109
+ for field in fields
110
+
111
+ parse_field field
112
+ yield field
113
+
114
+ end
115
+
116
+ end
117
+
118
+ # Transform a regular SQL column into RDBAL's hash.
119
+
120
+ def parse_column ( column )
121
+
122
+ # Apply the appropriate type.
123
+
124
+ type = sql_types[column[:type].upcase]
125
+
126
+ if not type
127
+
128
+ raise OptionError.new('Cannot map column type: ' + column[:type].to_s)
129
+
130
+ end
131
+
132
+ column[:type] = type
133
+
134
+ if column[:size]
135
+
136
+ column[:size] = unquote_value(column[:size])
137
+
138
+ end
139
+
140
+ # Let's work on default value.
141
+
142
+ if column[:default_value]
143
+
144
+ column[:default_value].gsub!("'",'')
145
+
146
+ end
147
+
148
+ # Allow null?
149
+
150
+ if column[:allow_null] == 't' || column[:allow_null] == 1
151
+
152
+ column[:allow_null] = true
153
+
154
+ else
155
+
156
+ column[:allow_null] = false
157
+
158
+ end
159
+
160
+ # Is primary key?
161
+
162
+ if column[:pk] == 't' || column[:pk] == 1
163
+
164
+ column[:pk] = true
165
+
166
+ else
167
+
168
+ column[:pk] = false
169
+
170
+ end
171
+
172
+ # Is automagically incremented?
173
+
174
+ if column[:auto_increment] == 1
175
+
176
+ column[:auto_increment] = true
177
+
178
+ else
179
+
180
+ column[:auto_increment] = false
181
+
182
+ end
183
+
184
+ if column[:indexed] == 't' || column[:indexed] == 1
185
+
186
+ column[:indexed] = true
187
+
188
+ else
189
+
190
+ column[:indexed] = false
191
+
192
+ end
193
+
194
+ end
195
+
196
+ # Iterate columns by parsing them.
197
+
198
+ def parse_columns ( columns, &block )
199
+
200
+ raise OptionError.new unless columns
201
+ raise OptionError.new if columns.length < 1
202
+
203
+ for column in columns
204
+
205
+ parse_column column
206
+ yield column
207
+
208
+ end
209
+
210
+ end
211
+
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,41 @@
1
+ module Imparcial
2
+ module Driver
3
+ module UtilBase
4
+
5
+ # This method possibly will work for many databases.
6
+
7
+ def quote_value ( val )
8
+
9
+ if val.class == String || val.class == Symbol
10
+
11
+ "\"#{val}\""
12
+
13
+ else
14
+
15
+ val.to_s
16
+
17
+ end
18
+
19
+ end
20
+
21
+ # This method possibly will work for many databases.
22
+
23
+ def unquote_value ( val )
24
+
25
+ return 0 if val == '0'
26
+
27
+ val.to_i == 0 ? val : val.to_i
28
+
29
+ end
30
+
31
+ # Subclasses need to override it.
32
+
33
+ def quote ( val )
34
+
35
+ raise FeatureNotFound
36
+
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,156 @@
1
+ require 'imparcial/driver/base/util'
2
+ require 'imparcial/driver/base/typemap'
3
+ require 'imparcial/driver/base/result'
4
+ require 'imparcial/driver/base/sql'
5
+ require 'imparcial/driver/base/expression'
6
+
7
+ module Imparcial
8
+ module Driver
9
+
10
+ # You have seriously to pay attention on this class.
11
+ # Basically speaking, it servers as base for all new drivers.
12
+ # The idea behind Imparcial is to keep an abstract interface without
13
+ # exposing any database-specific-features.
14
+ # Of course, it's an impossible mission anyhow. There are so many
15
+ # databases out there and there are so many cool features that
16
+ # make impossible not to expose them.
17
+ # We recommend you to obey the interface as much as possible.
18
+ # However you may develop some specific features.
19
+
20
+ class AdapterBase
21
+
22
+ # Include SQL syntax generation.
23
+ # Here where all SQL syntax lies on.
24
+
25
+ include SQLBase
26
+
27
+ # Include the expression mechanism.
28
+ # Things like create table, drop table, select and so forth.
29
+ # They all come from this module.
30
+
31
+ include ExpressionBase
32
+
33
+ # Include some util methods.
34
+ # Things like quoting columns, tables and values.
35
+
36
+ include UtilBase
37
+
38
+ # Include Typemap mechanism.
39
+
40
+ include TypemapBase
41
+
42
+ # Let's keep a track of the initializer. We'll need some info eventually.
43
+
44
+ attr_reader :initializer
45
+
46
+ # Let's also keep a track of the connection.
47
+
48
+ attr_accessor :conn
49
+ alias_method :connection, :conn
50
+
51
+ attr_reader :host, :user, :pass, :database, :socket, :port
52
+
53
+ def initialize ( initializer )
54
+
55
+ # Cannot accept classes different from Initializer.
56
+
57
+ if initializer.class != Imparcial::Initializer
58
+
59
+ msg = 'An initializer is needed in order to start a driver'
60
+ raise AdapterConfigError.new(msg)
61
+
62
+ end
63
+
64
+ @initializer = initializer
65
+
66
+ @host = initializer.host
67
+
68
+ if not initializer.user
69
+
70
+ raise AdapterConfigError.new('Adapter requires an username')
71
+
72
+ end
73
+
74
+ @user = initializer.user
75
+
76
+ if not initializer.pass
77
+
78
+ raise AdapterConfigError.new('Adapter requires a password')
79
+
80
+ end
81
+
82
+ @pass = initializer.pass
83
+
84
+ if not initializer.database
85
+
86
+ raise AdapterConfigErrornew('Adapter requires a database')
87
+
88
+ end
89
+
90
+ @database = initializer.database
91
+ @socket = initializer.socket
92
+ @port = initializer.port
93
+
94
+ end
95
+
96
+ #####################################################
97
+ # #
98
+ # Those are methods shared among all databases. #
99
+ # Hardly, one will need to override them. #
100
+ # #
101
+ #####################################################
102
+
103
+ def conn
104
+
105
+ raise AdapterConnectionError.new('Have you connected?') unless @conn
106
+ @conn
107
+
108
+ end
109
+
110
+ def close
111
+
112
+ conn.close
113
+
114
+ end
115
+
116
+ def result
117
+
118
+ raise ResultError.new('Have you made a query?') unless @result
119
+ @result
120
+
121
+ end
122
+
123
+ #####################################################
124
+ # #
125
+ # Subclasses must override those following methods. #
126
+ # They are driver-specific. #
127
+ # #
128
+ #####################################################
129
+
130
+ def connect
131
+
132
+ raise FeatureNotFound
133
+
134
+ end
135
+
136
+ def version
137
+
138
+ raise FeatureNotFound
139
+
140
+ end
141
+
142
+ def query ( sql )
143
+
144
+ raise FeatureNotFound
145
+
146
+ end
147
+
148
+ def adapter_specific_exception
149
+
150
+ raise FeatureNotFound
151
+
152
+ end
153
+
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,44 @@
1
+ module Imparcial
2
+ module Driver
3
+ module ExpressionMysql
4
+ module Index
5
+
6
+ public
7
+
8
+ def drop_all_indexes
9
+
10
+ for index in retrieve_indexes
11
+
12
+ meta = {:index_name => index[:name], :table_name => index[:table]}
13
+ query sql_for_dropping_index(meta)
14
+
15
+ end
16
+
17
+ rescue adapter_specific_exception => ex
18
+
19
+ raise IndexDropError.new(ex.message)
20
+
21
+ end
22
+
23
+ def drop_all_indexes_for_table ( options = {} )
24
+
25
+ check_options expected_options_for_index_table, options
26
+
27
+ for index in retrieve_indexes_for_table options
28
+
29
+ meta = {:index_name => index[:name], :table_name => options[:table_name]}
30
+ query sql_for_dropping_index(meta)
31
+
32
+ end
33
+
34
+ rescue adapter_specific_exception => ex
35
+
36
+ raise IndexDropError.new(ex.message)
37
+
38
+ end
39
+
40
+
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,26 @@
1
+ module Imparcial
2
+ module Driver
3
+ module ExpressionMysql
4
+ module Table
5
+
6
+ private
7
+
8
+ def expected_options_for_creating_table
9
+
10
+ super.merge :engine => :optional
11
+
12
+ end
13
+
14
+ def field_to_column ( field )
15
+
16
+ column = super
17
+ column[:auto_increment] = field[:auto_increment] ? ' AUTO_INCREMENT' : ''
18
+
19
+ column
20
+
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ require 'imparcial/driver/mysql/expression/table'
2
+ require 'imparcial/driver/mysql/expression/index'
3
+
4
+ module Imparcial
5
+ module Driver
6
+ module ExpressionMysql
7
+ include Table
8
+ include Index
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ module Imparcial
2
+ module Driver
3
+ class ResultMysql < ResultBase
4
+
5
+ def rows
6
+
7
+ @specific.num_rows
8
+
9
+ end
10
+
11
+ def fetch
12
+
13
+ fields = @specific.fetch_fields
14
+
15
+ @specific.each do |row|
16
+
17
+ v = []
18
+
19
+ row.each_with_index do |r, index|
20
+
21
+ v << Row.new(fields[index].name, r)
22
+
23
+ end
24
+
25
+ yield(*v)
26
+
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,51 @@
1
+ module Imparcial
2
+ module Driver
3
+ module SQLMysql
4
+ module Index
5
+
6
+ private
7
+
8
+ def sql_for_dropping_index ( options )
9
+
10
+ %{
11
+ DROP INDEX #{options[:index_name]} ON
12
+ #{quote(options[:table_name])}
13
+ }
14
+
15
+ end
16
+
17
+ # Generate SQL statement for verifying if a given index exists.
18
+
19
+ def sql_for_index_exists? ( options )
20
+
21
+ %{
22
+ SELECT 1 FROM INFORMATION_SCHEMA.statistics
23
+ WHERE INDEX_NAME = #{quote_value(options[:index_name])}
24
+ }
25
+
26
+ end
27
+
28
+ def sql_for_retrieving_indexes
29
+
30
+ %{
31
+ SELECT
32
+ TABLE_NAME AS 'table',
33
+ COLUMN_NAME AS 'column',
34
+ INDEX_NAME AS 'index'
35
+ FROM INFORMATION_SCHEMA.statistics
36
+ }
37
+
38
+ end
39
+
40
+ def sql_for_retrieving_indexes_for_table ( options )
41
+
42
+ sql_for_retrieving_indexes + %{
43
+ WHERE TABLE_NAME = #{quote_value(options[:table_name])}
44
+ }
45
+
46
+ end
47
+
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,39 @@
1
+ module Imparcial
2
+ module Driver
3
+ module SQLMysql
4
+
5
+ # Mysql doesn't support sequences.
6
+ # We have to disable all them.
7
+
8
+ module Sequence
9
+
10
+ private
11
+
12
+ def sql_for_creating_sequence ( options )
13
+
14
+ raise FeatureNotFound
15
+
16
+ end
17
+
18
+ def sql_for_dropping_sequence ( options )
19
+
20
+ raise FeatureNotFound
21
+
22
+ end
23
+
24
+ def sql_for_sequence_exists? ( options )
25
+
26
+ raise FeatureNotFound
27
+
28
+ end
29
+
30
+ def sql_for_retrieving_sequences
31
+
32
+ raise FeatureNotFound
33
+
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ module Imparcial
2
+ module Driver
3
+ module SQLMysql
4
+ module TableMetadata
5
+
6
+ private
7
+
8
+ # Generate SQL statement for retrieving tables.
9
+
10
+ def sql_for_retrieving_tables
11
+
12
+ 'SHOW TABLES'
13
+
14
+ end
15
+
16
+ # Generate SQL statement for retrieving columns.
17
+
18
+ def sql_for_retrieving_columns ( options = {} )
19
+
20
+ %{
21
+ SELECT
22
+ A.column_name, A.data_type, A.character_maximum_length as size,
23
+ (A.is_nullable = 'YES') as allow_null,
24
+ (A.column_name = B.column_name) as pk,
25
+ A.column_default,
26
+ A.extra = 'auto_increment' as auto_inc,
27
+ A.column_name in (
28
+ SELECT s.COLUMN_NAME FROM INFORMATION_SCHEMA.statistics s
29
+ WHERE s.COLUMN_NAME = A.column_name
30
+ ) as indexed
31
+
32
+ FROM information_schema.columns A
33
+ LEFT JOIN information_schema.key_column_usage B ON A.table_name = B.table_name
34
+ WHERE A.table_name = #{quote_value(options[:table_name])}
35
+
36
+ }
37
+
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,20 @@
1
+ module Imparcial
2
+ module Driver
3
+ module SQLMysql
4
+ module TableOperation
5
+
6
+ private
7
+
8
+ def sql_for_creating_table ( options = {} )
9
+
10
+ syntax = super
11
+ syntax += 'ENGINE = ' + options[:engine].to_s if options[:engine]
12
+
13
+ syntax
14
+
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ require 'imparcial/driver/mysql/sql/table_operation'
2
+ require 'imparcial/driver/mysql/sql/table_metadata'
3
+ require 'imparcial/driver/mysql/sql/sequence'
4
+ require 'imparcial/driver/mysql/sql/index'
5
+
6
+ module Imparcial
7
+ module Driver
8
+ module SQLMysql
9
+ include TableOperation
10
+ include TableMetadata
11
+ include Sequence
12
+ include Index
13
+ end
14
+ end
15
+ end