imparcial 0.0.4 → 0.0.5

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 (80) hide show
  1. data/History.txt +2 -5
  2. data/Manifest.txt +79 -5
  3. data/README.txt +71 -7
  4. data/Rakefile +1 -1
  5. data/lib/imparcial/driver/abstract/expression/column.rb +313 -0
  6. data/lib/imparcial/driver/abstract/expression/constraint.rb +149 -0
  7. data/lib/imparcial/driver/abstract/expression/delete.rb +88 -0
  8. data/lib/imparcial/driver/abstract/expression/index.rb +206 -0
  9. data/lib/imparcial/driver/abstract/expression/insert.rb +49 -0
  10. data/lib/imparcial/driver/abstract/expression/lock.rb +11 -0
  11. data/lib/imparcial/driver/abstract/expression/record.rb +41 -0
  12. data/lib/imparcial/driver/abstract/expression/select.rb +38 -0
  13. data/lib/imparcial/driver/abstract/expression/sequence.rb +260 -0
  14. data/lib/imparcial/driver/abstract/expression/statement.rb +128 -0
  15. data/lib/imparcial/driver/abstract/expression/table.rb +416 -0
  16. data/lib/imparcial/driver/abstract/expression/transaction.rb +143 -0
  17. data/lib/imparcial/driver/abstract/expression/update.rb +50 -0
  18. data/lib/imparcial/driver/abstract/expression.rb +23 -0
  19. data/lib/imparcial/driver/abstract/result.rb +95 -0
  20. data/lib/imparcial/driver/abstract/sql/column.rb +103 -0
  21. data/lib/imparcial/driver/abstract/sql/constraint.rb +42 -0
  22. data/lib/imparcial/driver/abstract/sql/delete.rb +22 -0
  23. data/lib/imparcial/driver/abstract/sql/index.rb +45 -0
  24. data/lib/imparcial/driver/abstract/sql/insert.rb +63 -0
  25. data/lib/imparcial/driver/abstract/sql/record.rb +19 -0
  26. data/lib/imparcial/driver/abstract/sql/select.rb +101 -0
  27. data/lib/imparcial/driver/abstract/sql/sequence.rb +55 -0
  28. data/lib/imparcial/driver/abstract/sql/table.rb +42 -0
  29. data/lib/imparcial/driver/abstract/sql/transaction.rb +43 -0
  30. data/lib/imparcial/driver/abstract/sql/update.rb +29 -0
  31. data/lib/imparcial/driver/abstract/sql.rb +21 -0
  32. data/lib/imparcial/driver/abstract/typemap.rb +168 -0
  33. data/lib/imparcial/driver/abstract/util.rb +53 -0
  34. data/lib/imparcial/driver/abstract.rb +255 -0
  35. data/lib/imparcial/driver/mysql/expression/table.rb +17 -0
  36. data/lib/imparcial/driver/mysql/expression.rb +11 -0
  37. data/lib/imparcial/driver/mysql/result.rb +33 -0
  38. data/lib/imparcial/driver/mysql/sql/column.rb +59 -0
  39. data/lib/imparcial/driver/mysql/sql/constraint.rb +39 -0
  40. data/lib/imparcial/driver/mysql/sql/index.rb +42 -0
  41. data/lib/imparcial/driver/mysql/sql/sequence.rb +39 -0
  42. data/lib/imparcial/driver/mysql/sql/table.rb +67 -0
  43. data/lib/imparcial/driver/mysql/sql.rb +15 -0
  44. data/lib/imparcial/driver/mysql/typemap.rb +13 -0
  45. data/lib/imparcial/driver/mysql/util.rb +13 -0
  46. data/lib/imparcial/driver/mysql.rb +49 -0
  47. data/lib/imparcial/driver/postgre/expression.rb +32 -0
  48. data/lib/imparcial/driver/postgre/result.rb +35 -0
  49. data/lib/imparcial/driver/postgre/sql/column.rb +53 -0
  50. data/lib/imparcial/driver/postgre/sql/constraint.rb +37 -0
  51. data/lib/imparcial/driver/postgre/sql/index.rb +53 -0
  52. data/lib/imparcial/driver/postgre/sql/sequence.rb +30 -0
  53. data/lib/imparcial/driver/postgre/sql/table.rb +46 -0
  54. data/lib/imparcial/driver/postgre/sql.rb +15 -0
  55. data/lib/imparcial/driver/postgre/typemap.rb +36 -0
  56. data/lib/imparcial/driver/postgre/util.rb +19 -0
  57. data/lib/imparcial/driver/postgre.rb +43 -0
  58. data/lib/imparcial/driver.rb +1 -0
  59. data/lib/imparcial/exception.rb +71 -0
  60. data/lib/imparcial/extension.rb +90 -0
  61. data/lib/imparcial/initializer.rb +30 -0
  62. data/lib/imparcial.rb +1 -1
  63. data/test/unit/base/common/tc_quote.rb +30 -0
  64. data/test/unit/base/expression/tc_column.rb +84 -0
  65. data/test/unit/base/expression/tc_constraint.rb +39 -0
  66. data/test/unit/base/expression/tc_delete.rb +51 -0
  67. data/test/unit/base/expression/tc_index.rb +43 -0
  68. data/test/unit/base/expression/tc_insert.rb +44 -0
  69. data/test/unit/base/expression/tc_select.rb +142 -0
  70. data/test/unit/base/expression/tc_sequence.rb +48 -0
  71. data/test/unit/base/expression/tc_table.rb +68 -0
  72. data/test/unit/base/expression/tc_table_diff.rb +41 -0
  73. data/test/unit/base/expression/tc_transaction.rb +46 -0
  74. data/test/unit/base/expression/tc_update.rb +29 -0
  75. data/test/unit/base/statement/tc_conditions.rb +84 -0
  76. data/test/unit/base/statement/tc_limit.rb +25 -0
  77. data/test/unit/base/statement/tc_order.rb +25 -0
  78. data/test/unit/helper.rb +64 -0
  79. data/test/unit/mysql/tc_sequence.rb +41 -0
  80. metadata +102 -10
@@ -0,0 +1,42 @@
1
+ module Imparcial
2
+ module Driver
3
+ module MysqlSQL
4
+ module Index
5
+
6
+ private
7
+
8
+ def sql_for_dropping_index ( options )
9
+
10
+ %{DROP INDEX #{options[:index_name]} ON
11
+ #{quote(options[:table_name])}
12
+ }
13
+
14
+ end
15
+
16
+ # Generate SQL statement for verifying if a given index exists.
17
+
18
+ def sql_for_index_exists? ( options )
19
+
20
+ %{SELECT 1 FROM INFORMATION_SCHEMA.statistics
21
+ WHERE table_schema != "mysql" AND
22
+ table_name = #{quote_value(options[:table_name])} AND
23
+ INDEX_NAME = #{quote_value(options[:index_name])}
24
+ }
25
+
26
+ end
27
+
28
+ def sql_for_getting_indexes ( options )
29
+
30
+ %{SELECT table_name AS 'table', column_name AS 'column',\
31
+ index_name AS 'index' FROM INFORMATION_SCHEMA.statistics\
32
+ WHERE table_schema != 'mysql'
33
+ AND table_name = #{quote_value(options[:table_name])}
34
+ }
35
+
36
+ end
37
+
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,39 @@
1
+ module Imparcial
2
+ module Driver
3
+ module MysqlSQL
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,67 @@
1
+ module Imparcial
2
+ module Driver
3
+ module MysqlSQL
4
+ module Table
5
+
6
+ private
7
+
8
+ def sql_for_creating_table ( options = {} )
9
+
10
+ syntax = super
11
+
12
+ syntax += 'ENGINE = '
13
+
14
+ # If any engine has not been specified, we make INNODB as default.
15
+
16
+ if options[:engine]
17
+
18
+ syntax += options[:engine].to_s
19
+
20
+ else
21
+
22
+ syntax += 'INNODB'
23
+
24
+ end
25
+
26
+ syntax
27
+
28
+ end
29
+
30
+ private
31
+
32
+ # Generate SQL statement for retrieving tables.
33
+
34
+ def sql_for_getting_tables
35
+
36
+ 'SHOW TABLES'
37
+
38
+ end
39
+
40
+ # Generate SQL statement for retrieving columns.
41
+ =begin
42
+ def sql_for_retrieving_columns ( options = {} )
43
+
44
+ %{
45
+ SELECT
46
+ A.column_name, A.data_type, A.character_maximum_length as size,
47
+ (A.is_nullable = 'YES') as allow_null,
48
+ (A.column_name = B.column_name) as pk,
49
+ A.column_default,
50
+ A.extra = 'auto_increment' as auto_inc,
51
+ A.column_name in (
52
+ SELECT s.COLUMN_NAME FROM INFORMATION_SCHEMA.statistics s
53
+ WHERE s.COLUMN_NAME = A.column_name
54
+ ) as indexed
55
+
56
+ FROM information_schema.columns A
57
+ LEFT JOIN information_schema.key_column_usage B ON A.table_name = B.table_name
58
+ WHERE A.table_name = #{quote_value(options[:table_name])}
59
+
60
+ }
61
+
62
+ end
63
+ =end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,15 @@
1
+ FileList[File.dirname(__FILE__) + '/sql/*.rb'].each do |f|
2
+ require f
3
+ end
4
+
5
+ module Imparcial
6
+ module Driver
7
+ module MysqlSQL
8
+ include Table
9
+ include Sequence
10
+ include Index
11
+ include Constraint
12
+ include Column
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module Imparcial
2
+ module Driver
3
+ module MysqlTypemap
4
+
5
+ def sql_types
6
+
7
+ super.dup.merge!('INT' => :integer)
8
+
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Imparcial
2
+ module Driver
3
+ module MysqlUtil
4
+
5
+ def quote ( val )
6
+
7
+ "`#{val}`"
8
+
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+ require 'mysql'
2
+
3
+ require 'imparcial/driver/mysql/util'
4
+ require 'imparcial/driver/mysql/result'
5
+ require 'imparcial/driver/mysql/typemap'
6
+ require 'imparcial/driver/mysql/sql'
7
+ require 'imparcial/driver/mysql/expression'
8
+
9
+ module Imparcial
10
+ module Driver
11
+ class MysqlAdapter < AbstractAdapter
12
+
13
+ include MysqlUtil
14
+ include MysqlTypemap
15
+ include MysqlSQL
16
+ include MysqlExpression
17
+
18
+ def adapter_specific_exception
19
+
20
+ Mysql::Error
21
+
22
+ end
23
+
24
+ def connect
25
+
26
+ @conn = Mysql.real_connect @host, @username, @password, @database, @port, @socket
27
+
28
+ rescue adapter_specific_exception => ex
29
+
30
+ raise AdapterConnectionError.new(ex.message)
31
+
32
+ end
33
+
34
+ def query ( sql )
35
+
36
+ result = conn.query sql
37
+ @result = MysqlResult.new result
38
+
39
+ end
40
+
41
+ def last_insert_id
42
+
43
+ conn.last_insert_id
44
+
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,32 @@
1
+ FileList[File.dirname(__FILE__) + '/expression/*.rb'].each do |f|
2
+ require f
3
+ end
4
+
5
+ module Imparcial
6
+ module Driver
7
+ module PostgreExpression
8
+
9
+ def insert ( options = {} )
10
+
11
+ super options
12
+
13
+ begin
14
+
15
+ seq_name = 'seq_' + options[:table_name].to_s + '_id'
16
+ id = conn.query "SELECT currval('#{seq_name}')"
17
+
18
+ @last_insert_id = id[0][0].to_i
19
+
20
+ rescue adapter_specific_exception; end
21
+
22
+ end
23
+
24
+ def last_insert_id
25
+
26
+ @last_insert_id
27
+
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ module Imparcial
2
+ module Driver
3
+ class PostgreResult < AbstractResult
4
+
5
+ def rows
6
+
7
+ @specific.result.length
8
+
9
+ end
10
+
11
+ def fetch
12
+
13
+ fields = @specific.fields
14
+ rows = @specific.result
15
+
16
+ rows.each do |row|
17
+
18
+ v = []
19
+
20
+ row.each_with_index do |value, index|
21
+
22
+ v << Row.new(fields[index], value)
23
+
24
+ end
25
+
26
+ yield(*v)
27
+
28
+ end
29
+
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,53 @@
1
+ module Imparcial
2
+ module Driver
3
+ module PostgreSQL
4
+ module Column
5
+
6
+ private
7
+
8
+ def sql_for_renaming_column ( options )
9
+
10
+ syntax = ''
11
+
12
+ syntax += 'ALTER TABLE ' + quote(options[:table_name]) + ' '
13
+
14
+ options[:field].each do |old_name, new_name|
15
+
16
+ syntax += "RENAME COLUMN #{old_name} TO #{new_name}"
17
+
18
+ end
19
+
20
+ logger.warn(syntax) if @table_logging
21
+
22
+ syntax
23
+
24
+ end
25
+
26
+ def sql_for_modifying_columns ( options )
27
+
28
+ syntax = ''
29
+
30
+ syntax += 'ALTER TABLE ' + quote(options[:table_name]) + ' '
31
+
32
+ options[:fields].each do |field|
33
+
34
+ column = field_to_column field
35
+
36
+ syntax += "ALTER COLUMN #{column[:name]} TYPE #{column[:type]}"
37
+ syntax += "(#{column[:size]})" if column[:size]
38
+ syntax += ","
39
+
40
+ end
41
+
42
+ syntax.chop!
43
+
44
+ logger.warn(syntax) if @table_logging
45
+
46
+ syntax
47
+
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ module Imparcial
2
+ module Driver
3
+ module PostgreSQL
4
+ module Constraint
5
+
6
+ private
7
+
8
+ def sql_for_adding_auto_increment ( options )
9
+
10
+ seq_name = 'seq_' + options[:table_name].to_s + '_' + options[:field].to_s
11
+ drop_sequence_if_necessary :sequence_name => seq_name
12
+ create_sequence :sequence_name => seq_name
13
+ sql_for_adding_default_value :table_name => options[:table_name], :fields => {options[:field] => "nextval('#{seq_name}')"}
14
+
15
+ end
16
+
17
+ def sql_for_adding_default_value ( options )
18
+
19
+ syntax = 'ALTER TABLE ' + quote(options[:table_name]) + ' '
20
+
21
+ for field, value in options[:fields]
22
+
23
+ value = quote_value(value) if not value.to_s.match('nextval')
24
+ syntax += "ALTER COLUMN #{quote(field)} SET DEFAULT #{value},"
25
+
26
+ end
27
+
28
+ syntax.chop!
29
+
30
+ syntax
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,53 @@
1
+ module Imparcial
2
+ module Driver
3
+ module PostgreSQL
4
+ module Index
5
+
6
+ private
7
+
8
+ # Generate SQL statement for verifying if a given index exists.
9
+
10
+ def sql_for_index_exists? ( options )
11
+
12
+ %{SELECT
13
+ c2.relname as "table",
14
+ (select attname from pg_attribute where attrelid = i.indexrelid AND attnum > 0) as "column" ,
15
+ c.relname as "index"
16
+ FROM pg_class c
17
+ JOIN pg_roles r ON r.oid = c.relowner
18
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
19
+ LEFT JOIN pg_index i ON i.indexrelid = c.oid
20
+ LEFT JOIN pg_class c2 ON i.indrelid = c2.oid
21
+ WHERE c.relkind = 'i'
22
+ AND n.nspname NOT IN ('pg_catalog', 'pg_toast') AND
23
+ c2.relname = #{quote_value(options[:table_name])} AND
24
+ c.relname = #{quote_value(options[:index_name])}
25
+ }
26
+
27
+ end
28
+
29
+ # Generate SQL statement for retrieving all indexes.
30
+
31
+ def sql_for_getting_indexes ( options )
32
+
33
+ %{SELECT
34
+ c2.relname as "table",
35
+ (select attname from pg_attribute where attrelid = i.indexrelid AND attnum > 0) as "column" ,
36
+ c.relname as "index"
37
+ FROM pg_class c
38
+ JOIN pg_roles r ON r.oid = c.relowner
39
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
40
+ LEFT JOIN pg_index i ON i.indexrelid = c.oid
41
+ LEFT JOIN pg_class c2 ON i.indrelid = c2.oid
42
+ WHERE c.relkind = 'i'
43
+ AND n.nspname NOT IN ('pg_catalog', 'pg_toast') AND
44
+ c2.relname = #{quote_value(options[:table_name])}
45
+ }
46
+
47
+ end
48
+
49
+
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,30 @@
1
+ module Imparcial
2
+ module Driver
3
+ module PostgreSQL
4
+ module Sequence
5
+
6
+ private
7
+
8
+ def sql_for_sequence_exists? ( options )
9
+
10
+ %{
11
+ SELECT 1 FROM pg_class WHERE relkind = 'S' AND
12
+ relname = #{quote_value(options[:sequence_name])}
13
+ }
14
+
15
+ end
16
+
17
+ # Generate SQL statement for retrieving sequences.
18
+
19
+ def sql_for_getting_sequences
20
+
21
+ %{
22
+ SELECT relname FROM pg_class WHERE relkind = 'S'
23
+ }
24
+
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,46 @@
1
+ module Imparcial
2
+ module Driver
3
+ module PostgreSQL
4
+ module Table
5
+
6
+ private
7
+
8
+ # Generate SQL statement for retrieving tables.
9
+
10
+ def sql_for_getting_tables
11
+
12
+ %{
13
+ SELECT table_name FROM information_schema.tables
14
+ WHERE table_schema = 'public'
15
+ }
16
+
17
+ end
18
+
19
+ # Generate SQL statement for retrieving columns.
20
+ =begin
21
+ def sql_for_retrieving_columns ( options )
22
+
23
+ %{
24
+ SELECT
25
+ A.column_name, A.data_type, A.character_maximum_length,
26
+ (A.is_nullable = 'YES') as allow_null,
27
+ (A.column_name = B.column_name) as pk,
28
+ A.column_default,
29
+ A.column_default LIKE 'nextval%' as auto_inc,
30
+ A.column_name in (SELECT sa.attname from pg_class sc
31
+ JOIN pg_index si ON sc.oid = si.indexrelid
32
+ JOIN pg_class sc2 ON sc2.oid = si.indrelid
33
+ JOIN pg_attribute sa ON sc.oid = sa.attrelid
34
+ WHERE sc2.relname = #{quote_value(options[:table_name])} AND sa.attname = A.column_name
35
+ ) as column_indexed
36
+ FROM information_schema.columns A
37
+ LEFT JOIN information_schema.key_column_usage B ON A.table_name = B.table_name
38
+ WHERE A.table_name = #{quote_value(options[:table_name])};
39
+ }
40
+
41
+ end
42
+ =end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ FileList[File.dirname(__FILE__) + '/sql/*.rb'].each do |f|
2
+ require f
3
+ end
4
+
5
+ module Imparcial
6
+ module Driver
7
+ module PostgreSQL
8
+ include Table
9
+ include Sequence
10
+ include Index
11
+ include Constraint
12
+ include Column
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ module Imparcial
2
+ module Driver
3
+ module PostgreTypemap
4
+
5
+ def regular_types
6
+
7
+ super.dup.merge!(:datetime => 'TIMESTAMP')
8
+
9
+ end
10
+
11
+ def sql_types
12
+
13
+ super.dup.merge!('CHARACTER VARYING' => :string,
14
+ 'DOUBLE PRECISION' => :float)
15
+
16
+ end
17
+
18
+ private
19
+
20
+ # Due to nextval, we have to format the default value
21
+
22
+ def parse_column ( column )
23
+
24
+ super
25
+
26
+ if column[:default_value]
27
+
28
+ column[:default_value].gsub!(/::.*/,'')
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ module Imparcial
2
+ module Driver
3
+ module PostgreUtil
4
+
5
+ def quote_value ( val )
6
+
7
+ conn.class.quote val
8
+
9
+ end
10
+
11
+ def quote ( val )
12
+
13
+ "\"#{val}\""
14
+
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,43 @@
1
+ require 'postgres'
2
+
3
+ require 'imparcial/driver/postgre/util'
4
+ require 'imparcial/driver/postgre/result'
5
+ require 'imparcial/driver/postgre/typemap'
6
+ require 'imparcial/driver/postgre/sql'
7
+ require 'imparcial/driver/postgre/expression'
8
+
9
+ module Imparcial
10
+ module Driver
11
+ class PostgreAdapter < AbstractAdapter
12
+
13
+ include PostgreUtil
14
+ include PostgreTypemap
15
+ include PostgreSQL
16
+ include PostgreExpression
17
+
18
+ def adapter_specific_exception
19
+
20
+ PGError
21
+
22
+ end
23
+
24
+ def connect
25
+
26
+ @conn = PGconn.connect @host, @port, '', '', @database, @username, @password
27
+
28
+ rescue adapter_specific_exception => ex
29
+
30
+ raise AdapterConnectionError.new(ex.message)
31
+
32
+ end
33
+
34
+ def query ( sql )
35
+
36
+ result = conn.exec sql
37
+ @result = PostgreResult.new result
38
+
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1 @@
1
+ require 'imparcial/driver/abstract'