amalgalite 0.7.7 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY CHANGED
@@ -1,4 +1,13 @@
1
1
  = Amalgalite Changelog
2
+ == Version 0.8.0 - 2009-03-23
3
+
4
+ == Enhancements
5
+
6
+ * Add in support for obtaining limited schema information on temporary tables
7
+ and indexes
8
+ * Add support for returning the primary key columns of a table
9
+ * Other miscellaneous items to support the ActiveRecord adapter
10
+
2
11
  == Version 0.7.7 - 2009-03-03
3
12
 
4
13
  === Bug Fixes
@@ -38,15 +38,6 @@ module Amalgalite
38
38
  # the collation sequence name of the column
39
39
  attr_accessor :collation_sequence_name
40
40
 
41
- # true if the column has a NOT NULL constraint, false otherwise
42
- attr_accessor :not_null_constraint
43
-
44
- # true if the column is part of a primary key, false otherwise
45
- attr_accessor :primary_key
46
-
47
- # true if the column is AUTO INCREMENT, false otherwise
48
- attr_accessor :auto_increment
49
-
50
41
  # The index (starting with 0) of this column in the table definition
51
42
  # or result set
52
43
  attr_accessor :order
@@ -70,22 +61,37 @@ module Amalgalite
70
61
 
71
62
  # true if the column may have a NULL value
72
63
  def nullable?
73
- not_null_constraint == false
64
+ @not_null_constraint == false
65
+ end
66
+
67
+ # set whether or not the column has a not null constraint
68
+ def not_null_constraint=( other )
69
+ @not_null_constraint = Boolean.to_bool( other )
74
70
  end
75
71
 
76
72
  # true if the column as a NOT NULL constraint
77
73
  def not_null_constraint?
78
- not_null_constraint
74
+ @not_null_constraint
75
+ end
76
+
77
+ # set whether or not the column is a primary key column
78
+ def primary_key=( other )
79
+ @primary_key = Boolean.to_bool( other )
79
80
  end
80
81
 
81
82
  # true if the column is a primary key column
82
83
  def primary_key?
83
- primary_key
84
+ @primary_key
85
+ end
86
+
87
+ # set whether or not the column is auto increment
88
+ def auto_increment=( other )
89
+ @auto_increment = Boolean.to_bool( other )
84
90
  end
85
91
 
86
92
  # true if the column is auto increment
87
93
  def auto_increment?
88
- auto_increment
94
+ @auto_increment
89
95
  end
90
96
  end
91
97
  end
@@ -55,7 +55,8 @@ module Amalgalite
55
55
  # load all the tables
56
56
  #
57
57
  def load_tables
58
- @db.execute("SELECT tbl_name FROM sqlite_master WHERE type = 'table'") do |table_info|
58
+ @tables = {}
59
+ @db.execute("SELECT tbl_name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence'") do |table_info|
59
60
  table = load_table( table_info['tbl_name'] )
60
61
  table.indexes = load_indexes( table )
61
62
  @tables[table.name] = table
@@ -74,8 +75,18 @@ module Amalgalite
74
75
  table.columns = load_columns( table )
75
76
  table.schema = self
76
77
  table.indexes = load_indexes( table )
78
+ @tables[table.name] = table
79
+ else
80
+ # might be a temporary table
81
+ table = Amalgalite::Table.new( table_name, nil )
82
+ cols = load_columns( table )
83
+ if cols.size > 0 then
84
+ table.columns = cols
85
+ table.schema = self
86
+ table.indexes = load_indexes( table )
87
+ @tables[table.name] = table
88
+ end
77
89
  end
78
- @tables[table.name] = table
79
90
  return table
80
91
  end
81
92
 
@@ -94,6 +105,12 @@ module Amalgalite
94
105
  @db.execute("PRAGMA index_list( #{@db.quote(table.name)} );") do |idx_list|
95
106
  idx = indexes[idx_list['name']]
96
107
 
108
+ # temporary indexes do not show up in the previous list
109
+ if idx.nil? then
110
+ idx = Amalgalite::Index.new( idx_list['name'], nil, table )
111
+ indexes[idx_list['name']] = idx
112
+ end
113
+
97
114
  idx.sequence_number = idx_list['seq']
98
115
  idx.unique = Boolean.to_bool( idx_list['unique'] )
99
116
 
@@ -113,9 +130,26 @@ module Amalgalite
113
130
  @db.execute("PRAGMA table_info(#{@db.quote(table.name)})") do |row|
114
131
  col = Amalgalite::Column.new( "main", table.name, row['name'], row['cid'])
115
132
 
116
- col.default_value = row['dflt_value']
117
- @db.api.table_column_metadata( "main", table.name, col.name ).each_pair do |key, value|
118
- col.send("#{key}=", value)
133
+ col.default_value = row['dflt_value']
134
+
135
+ col.declared_data_type = row['type']
136
+ col.not_null_constraint = row['notnull']
137
+ col.primary_key = row['pk']
138
+
139
+ # need to remove leading and trailing ' or " from the default value
140
+ if col.default_value and col.default_value.kind_of?( String ) and ( col.default_value.length >= 2 ) then
141
+ fc = col.default_value[0].chr
142
+ lc = col.default_value[-1].chr
143
+ if fc == lc and ( fc == "'" || fc == '"' ) then
144
+ col.default_value = col.default_value[1..-2]
145
+ end
146
+ end
147
+
148
+ unless table.temporary? then
149
+ # get more exact information
150
+ @db.api.table_column_metadata( "main", table.name, col.name ).each_pair do |key, value|
151
+ col.send("#{key}=", value)
152
+ end
119
153
  end
120
154
  col.schema = self
121
155
  cols[col.name] = col
@@ -158,11 +158,11 @@ module Amalgalite
158
158
  check_parameter_count!( params.size )
159
159
  params.each_pair do | param, value |
160
160
  position = param_position_of( param )
161
- if position > 0 then
162
- bind_parameter_to( position, value )
163
- else
164
- raise Amalgalite::Error, "Unable to find parameter '#{param}' in SQL statement [#{sql}]"
165
- end
161
+ if position > 0 then
162
+ bind_parameter_to( position, value )
163
+ else
164
+ raise Amalgalite::Error, "Unable to find parameter '#{param}' in SQL statement [#{sql}]"
165
+ end
166
166
  end
167
167
  end
168
168
 
@@ -280,7 +280,7 @@ module Amalgalite
280
280
  col.schema.table,
281
281
  col.schema.name,
282
282
  @stmt_api.column_int64( @rowid_index ),
283
- "r"),
283
+ "r"),
284
284
  :column => col.schema)
285
285
  else
286
286
  value = Amalgalite::Blob.new( :string => @stmt_api.column_blob( idx ), :column => col.schema )
@@ -406,7 +406,7 @@ module Amalgalite
406
406
  # has been closed.
407
407
  #
408
408
  def close
409
- if open?
409
+ if open? then
410
410
  @stmt_api.close
411
411
  @open = false
412
412
  end
@@ -2,7 +2,7 @@
2
2
  # Copyright (c) 2008 Jeremy Hinegardner
3
3
  # All rights reserved. See LICENSE and/or COPYING for details.
4
4
  #++
5
-
5
+ require 'set'
6
6
  module Amalgalite
7
7
  #
8
8
  # a class representing the meta information about an SQLite table
@@ -25,13 +25,19 @@ module Amalgalite
25
25
  # in this table. keys are the column names
26
26
  attr_accessor :columns
27
27
 
28
- def initialize( name, sql )
28
+ def initialize( name, sql = nil )
29
29
  @name = name
30
30
  @sql = sql
31
31
  @indexes = {}
32
32
  @columns = {}
33
33
  end
34
34
 
35
+ # Is the table a temporary table or not
36
+ def temporary?
37
+ !sql
38
+ end
39
+
40
+
35
41
  # the Columns in original definition order
36
42
  def columns_in_order
37
43
  @columns.values.sort_by { |c| c.order }
@@ -41,6 +47,44 @@ module Amalgalite
41
47
  def column_names
42
48
  columns_in_order.map { |c| c.name }
43
49
  end
50
+
51
+ # the columns that make up the primary key
52
+ def primary_key_columns
53
+ @columns.values.find_all { |c| c.primary_key? }
54
+ end
55
+
56
+ # the array of colmuns that make up the primary key of the table
57
+ # since a primary key has an index, we loop over all the indexes for the
58
+ # table and pick the first one that is unique, and all the columns in the
59
+ # index have primary_key? as true.
60
+ #
61
+ # we do this instead of just looking for the columns where primary key is
62
+ # true because we want the columns in primary key order
63
+ def primary_key
64
+ unless @primary_key
65
+ pk_column_names = Set.new( primary_key_columns.collect { |c| c.name } )
66
+ unique_indexes = indexes.values.find_all { |i| i.unique? }
67
+
68
+ pk_result = []
69
+
70
+ unique_indexes.each do |idx|
71
+ idx_column_names = Set.new( idx.columns.collect { |c| c.name } )
72
+ r = idx_column_names ^ pk_column_names
73
+ if r.size == 0 then
74
+ pk_result = idx.columns
75
+ break
76
+ end
77
+ end
78
+
79
+ # no joy, see about just using all the columns that say the are primary
80
+ # keys
81
+ if pk_result.empty? then
82
+ pk_result = self.primary_key_columns
83
+ end
84
+ @primary_key = pk_result
85
+ end
86
+ return @primary_key
87
+ end
44
88
  end
45
89
  end
46
90
 
@@ -116,7 +116,8 @@ module Amalgalite::TypeMaps
116
116
  end
117
117
 
118
118
  ##
119
- # convert a string to a datetime
119
+ # convert a string to a datetime, if no timzone is found in the parsed
120
+ # string, set it to the local offset.
120
121
  #
121
122
  def datetime( str )
122
123
  DateTime.parse( str )
@@ -8,8 +8,8 @@ module Amalgalite
8
8
  module Version
9
9
 
10
10
  MAJOR = 0
11
- MINOR = 7
12
- BUILD = 7
11
+ MINOR = 8
12
+ BUILD = 0
13
13
 
14
14
  #
15
15
  # return the Version as an array of MAJOR, MINOR, BUILD
data/spec/schema_spec.rb CHANGED
@@ -42,6 +42,14 @@ describe Amalgalite::Schema do
42
42
  @iso_db.schema.views["v1"].sql.should eql(sql)
43
43
  end
44
44
 
45
+ it "removes quotes from around default values in columns" do
46
+ sql = "CREATE TABLE t1( d1 default 't' )"
47
+ @iso_db.execute( sql )
48
+ @iso_db.schema.dirty!
49
+ tt = @iso_db.schema.tables['t1']
50
+ tt.columns['d1'].default_value.should == "t"
51
+ end
52
+
45
53
  it "loads the tables and columns" do
46
54
  ct = @iso_db.schema.tables['country']
47
55
  ct.name.should eql("country")
@@ -59,6 +67,35 @@ describe Amalgalite::Schema do
59
67
  ct.columns['id'].should_not be_auto_increment
60
68
  end
61
69
 
70
+ it "knows what the primary key of a table is" do
71
+ ct = @iso_db.schema.tables['country']
72
+ ct.primary_key.should == [ ct.columns['two_letter'] ]
73
+ end
74
+
75
+ it "knows the primary key of a table even without an explicity unique index" do
76
+ sql = "CREATE TABLE u( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , other text )"
77
+ @iso_db.execute( sql )
78
+ @iso_db.schema.dirty!
79
+ ut = @iso_db.schema.tables['u']
80
+ ut.primary_key.should == [ ut.columns['id'] ]
81
+ end
82
+
83
+ it "knows the primary key of a temporary table" do
84
+ @iso_db.execute "CREATE TEMPORARY TABLE tt( a, b INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, c )"
85
+ @iso_db.schema.dirty!
86
+ tt = @iso_db.schema.load_table( 'tt' )
87
+ tt.primary_key.should == [ tt.columns['b'] ]
88
+
89
+ end
90
+
91
+ it "knows what the primary key of a table is when it is a multiple column primary key" do
92
+ sql = "CREATE TABLE m ( id1, id2, PRIMARY KEY (id2, id1) )"
93
+ @iso_db.execute( sql )
94
+ @iso_db.schema.dirty!
95
+ mt = @iso_db.schema.tables['m']
96
+ mt.primary_key.should == [ mt.columns['id2'], mt.columns['id1'] ]
97
+ end
98
+
62
99
  it "loads the indexes" do
63
100
  c = @iso_db.schema.tables['country']
64
101
  c.indexes.size.should eql(2)
@@ -72,4 +109,12 @@ describe Amalgalite::Schema do
72
109
  subc.indexes.size.should eql(3)
73
110
  subc.indexes['subcountry_country'].columns.first.should eql(@iso_db.schema.tables['subcountry'].columns['country'])
74
111
  end
112
+
113
+ it "can load the schema of a temporary table" do
114
+ @iso_db.execute "CREATE TEMPORARY TABLE tt( a, b, c )"
115
+ @iso_db.schema.dirty!
116
+ @iso_db.schema.tables['tt'].should be_nil
117
+ @iso_db.schema.load_table('tt').should_not be_nil
118
+ @iso_db.schema.tables['tt'].should be_temporary
119
+ end
75
120
  end
data/spec/tap_spec.rb CHANGED
@@ -32,7 +32,7 @@ describe Amalgalite::Taps::StringIO do
32
32
  s = ::Amalgalite::Taps::StringIO.new
33
33
  s.profile( 'test', 42 )
34
34
  s.dump_profile
35
- s.string.should == "42 : test\ntest[test] => sum: 42, sumsq: 1764, n: 1, mean: 42.000000, stddev: 0.000000, min: 42, max: 42\n"
35
+ s.string.should eql("42 : test\ntest[test] => sum: 42, sumsq: 1764, n: 1, mean: 42.000000, stddev: 0.000000, min: 42, max: 42\n")
36
36
  end
37
37
 
38
38
  it "has a stdout tap" do
data/tasks/config.rb CHANGED
@@ -61,7 +61,7 @@ Configuration.for("rubygem") {
61
61
  Configuration.for('test') {
62
62
  mode "spec"
63
63
  files Configuration.for("packaging").files.test
64
- options %w[ --format progress --color ]
64
+ options %w[ --format profile --color ]
65
65
  ruby_opts %w[ ]
66
66
  }
67
67
 
@@ -18,7 +18,7 @@ if pkg_config = Configuration.for_if_exist?("packaging") then
18
18
 
19
19
  desc "Install as a gem"
20
20
  task :install => [:clobber, :package] do
21
- sh "sudo gem install --local pkg/#{Amalgalite::GEM_SPEC.full_name}.gem"
21
+ sh "sudo gem install --local pkg/#{Amalgalite::GEM_SPEC.full_name}.gem --no-rdoc --no-ri"
22
22
  end
23
23
 
24
24
  desc "Uninstall gem"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amalgalite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.7
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Hinegardner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-04 00:00:00 -07:00
12
+ date: 2009-03-23 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency