amalgalite 0.1.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.
Files changed (64) hide show
  1. data/HISTORY +4 -0
  2. data/LICENSE +31 -0
  3. data/README +28 -0
  4. data/ext/amalgalite3.c +191 -0
  5. data/ext/amalgalite3.h +97 -0
  6. data/ext/amalgalite3_constants.c +179 -0
  7. data/ext/amalgalite3_database.c +458 -0
  8. data/ext/amalgalite3_statement.c +546 -0
  9. data/ext/gen_constants.rb +114 -0
  10. data/ext/mkrf_conf.rb +6 -0
  11. data/ext/sqlite3.c +87003 -0
  12. data/ext/sqlite3.h +5638 -0
  13. data/ext/sqlite3_options.h +4 -0
  14. data/ext/sqlite3ext.h +362 -0
  15. data/gemspec.rb +50 -0
  16. data/lib/amalgalite.rb +28 -0
  17. data/lib/amalgalite/blob.rb +14 -0
  18. data/lib/amalgalite/boolean.rb +42 -0
  19. data/lib/amalgalite/column.rb +83 -0
  20. data/lib/amalgalite/database.rb +505 -0
  21. data/lib/amalgalite/index.rb +27 -0
  22. data/lib/amalgalite/paths.rb +70 -0
  23. data/lib/amalgalite/profile_tap.rb +130 -0
  24. data/lib/amalgalite/schema.rb +90 -0
  25. data/lib/amalgalite/sqlite3.rb +4 -0
  26. data/lib/amalgalite/sqlite3/constants.rb +48 -0
  27. data/lib/amalgalite/sqlite3/version.rb +38 -0
  28. data/lib/amalgalite/statement.rb +307 -0
  29. data/lib/amalgalite/table.rb +34 -0
  30. data/lib/amalgalite/taps/console.rb +27 -0
  31. data/lib/amalgalite/taps/io.rb +71 -0
  32. data/lib/amalgalite/trace_tap.rb +35 -0
  33. data/lib/amalgalite/type_map.rb +60 -0
  34. data/lib/amalgalite/type_maps/default_map.rb +153 -0
  35. data/lib/amalgalite/type_maps/storage_map.rb +41 -0
  36. data/lib/amalgalite/type_maps/text_map.rb +23 -0
  37. data/lib/amalgalite/version.rb +32 -0
  38. data/lib/amalgalite/view.rb +24 -0
  39. data/spec/amalgalite_spec.rb +4 -0
  40. data/spec/boolean_spec.rb +26 -0
  41. data/spec/database_spec.rb +222 -0
  42. data/spec/default_map_spec.rb +85 -0
  43. data/spec/integeration_spec.rb +111 -0
  44. data/spec/paths_spec.rb +28 -0
  45. data/spec/schema_spec.rb +46 -0
  46. data/spec/spec_helper.rb +25 -0
  47. data/spec/sqlite3/constants_spec.rb +25 -0
  48. data/spec/sqlite3/version_spec.rb +14 -0
  49. data/spec/sqlite3_spec.rb +34 -0
  50. data/spec/statement_spec.rb +116 -0
  51. data/spec/storage_map_spec.rb +41 -0
  52. data/spec/tap_spec.rb +59 -0
  53. data/spec/text_map_spec.rb +23 -0
  54. data/spec/type_map_spec.rb +17 -0
  55. data/spec/version_spec.rb +9 -0
  56. data/tasks/announce.rake +38 -0
  57. data/tasks/config.rb +108 -0
  58. data/tasks/distribution.rake +38 -0
  59. data/tasks/documentation.rake +31 -0
  60. data/tasks/extension.rake +45 -0
  61. data/tasks/rspec.rake +32 -0
  62. data/tasks/rubyforge.rake +48 -0
  63. data/tasks/utils.rb +80 -0
  64. metadata +165 -0
@@ -0,0 +1,34 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ module Amalgalite
7
+ #
8
+ # a class representing the meta information about an SQLite table
9
+ #
10
+ class Table
11
+
12
+ # the table name
13
+ attr_reader :name
14
+
15
+ # the original sql that was used to create this table
16
+ attr_reader :sql
17
+
18
+ # an array of Index objects holding the meta informationa about the indexes
19
+ # on this table
20
+ attr_accessor :indexes
21
+
22
+ # an array of Column objects holding the meta information about the columns
23
+ # in this table
24
+ attr_accessor :columns
25
+
26
+ def initialize( name, sql )
27
+ @name = name
28
+ @sql = sql
29
+ @indexes = []
30
+ @columns = []
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,27 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ require 'amalgalite/taps/io'
7
+
8
+ module Amalgalite::Taps
9
+ #
10
+ # Class provide an IO tap that can write to $stdout
11
+ #
12
+ class Stdout < ::Amalgalite::Taps::IO
13
+ def initialize
14
+ super( $stdout )
15
+ end
16
+ end
17
+
18
+ #
19
+ # This class provide an IO tap that can write to $stderr
20
+ #
21
+ class Stderr < ::Amalgalite::Taps::IO
22
+ def initialize
23
+ super( $stderr )
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,71 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ require 'amalgalite/profile_tap'
7
+ require 'stringio'
8
+
9
+ module Amalgalite
10
+ module Taps
11
+ #
12
+ # An IOTap is an easy way to send all top information to andy IO based
13
+ # object. Both profile and trace tap information can be captured
14
+ # This means you can send the events to STDOUT with:
15
+ #
16
+ # db.profile_tap = db.trace_tap = Amalgalite::Taps::Stdout.new
17
+ #
18
+ #
19
+ class IO
20
+
21
+ attr_reader :profile_tap
22
+ attr_reader :io
23
+
24
+ def initialize( io )
25
+ @io = io
26
+ @profile_tap = ProfileTap.new( self, 'output_profile_event' )
27
+ end
28
+
29
+ def trace( msg )
30
+ io.puts msg
31
+ end
32
+
33
+ # need a profile method, it routes through the profile tap which calls back
34
+ # to output_profile_event
35
+ def profile( msg, time )
36
+ @profile_tap.profile(msg, time)
37
+ end
38
+
39
+ def output_profile_event( msg, time )
40
+ io.puts "#{time} : #{msg}"
41
+ end
42
+
43
+ def dump_profile
44
+ samplers.each do |s|
45
+ io.puts s.to_s
46
+ end
47
+ end
48
+
49
+ def samplers
50
+ profile_tap.samplers
51
+ end
52
+ end
53
+
54
+ #
55
+ # This class provides an IO tap that writes to a StringIO. The result is
56
+ # available via .to_s or .string.
57
+ #
58
+ class StringIO < ::Amalgalite::Taps::IO
59
+ def initialize
60
+ @stringio = ::StringIO.new
61
+ super( @stringio )
62
+ end
63
+
64
+ def to_s
65
+ @stringio.string
66
+ end
67
+ alias :string :to_s
68
+ end
69
+ end
70
+ end
71
+
@@ -0,0 +1,35 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ module Amalgalite
7
+ #
8
+ # A TraceTap receives tracing information from SQLite3. It receives the SQL
9
+ # statement being executed as a +msg+ just before the statement first begins
10
+ # executing.
11
+ #
12
+ # A TraceTap is a wrapper around another object and a method. The Tap object
13
+ # will receive the call to +trace+ and redirect that call to another object
14
+ # and method.
15
+ #
16
+ class TraceTap
17
+
18
+ attr_reader :delegate_obj
19
+ attr_reader :delegate_method
20
+
21
+ def initialize( wrapped_obj, send_to = 'trace' )
22
+ unless wrapped_obj.respond_to?( send_to )
23
+ raise Amalgalite::Error, "#{wrapped_obj.class.name} does not respond to #{send_to.to_s} "
24
+ end
25
+
26
+ @delegate_obj = wrapped_obj
27
+ @delegate_method = send_to
28
+ end
29
+
30
+ def trace( msg )
31
+ delegate_obj.send( delegate_method, msg )
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,60 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+ module Amalgalite
6
+ ##
7
+ # TypeMap defines the protocol used between Ruby and SQLite for mapping
8
+ # binding types, used in prepared statements; and result types, used in
9
+ # returning objects from a query.
10
+ #
11
+ #
12
+ class TypeMap
13
+ ##
14
+ # :call-seq:
15
+ # map.bind_type_of( obj ) -> DataType constant
16
+ #
17
+ # bind_type_of is called during the Statement#bind process to convert the
18
+ # bind parameter to the appropriate SQLite types. This method MUST return
19
+ # one of the valid constants in the namespace
20
+ # Amalgalite::SQLite::Constants::DataType
21
+ #
22
+ def bind_type_of( obj )
23
+ raise NotImplementedError, "bind_type_of has not been implemented"
24
+ end
25
+
26
+ ##
27
+ # :call-seq:
28
+ # map.result_value_of( declared_type, value ) -> String
29
+ #
30
+ # result_value_of is called during the result processing of column values
31
+ # to convert an SQLite database value into the appropriate Ruby class.
32
+ #
33
+ # +declared_type+ is the string from the original CREATE TABLE statment
34
+ # from which the column value originates. It may also be nil if the origin
35
+ # column cannot be determined.
36
+ #
37
+ # +value+ is the SQLite value from the column as either a Ruby String,
38
+ # Integer, Float or Amalgalite::Blob.
39
+ #
40
+ # result_value should return the value that is to be put into the result set
41
+ # for the query. It may do nothing, or it may do massive amounts of
42
+ # conversion.
43
+ def result_value_of( delcared_type, value )
44
+ raise NotImplementedError, "result_value_of has not been implemented"
45
+ end
46
+ end
47
+
48
+ ##
49
+ # The TypeMaps module holds all typemaps that ship with Amagalite. They
50
+ # currently are:
51
+ #
52
+ # DefaultMap:: does a 'best-guess' mapping to convert as many types as
53
+ # possible to known ruby classes from known SQL types.
54
+ # StorageMap:: converts to a limited set of classes directly based
55
+ # upon the SQLite storage types
56
+ # TextMap:: Everything is Text ... everything everything everything
57
+ #
58
+ module TypeMaps
59
+ end
60
+ end
@@ -0,0 +1,153 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ require 'amalgalite/type_map'
7
+ require 'amalgalite3'
8
+ require 'time'
9
+ require 'date'
10
+
11
+ module Amalgalite::TypeMaps
12
+ ##
13
+ # An Amalgalite::TypeMap that does its best to convert between Ruby classes
14
+ # and known SQL data types.
15
+ #
16
+ # Upon instantiation, DefaultMap generates a conversion map to try to figure
17
+ # out the best way to convert between populate SQL 'types' and ruby classes
18
+ #
19
+ class DefaultMap
20
+ class << self
21
+ def methods_handling_sql_types # :nodoc:
22
+ @methods_handling_sql_types ||= {
23
+ 'date' => %w[ date ],
24
+ 'datetime' => %w[ datetime ],
25
+ 'time' => %w[ timestamp ],
26
+ 'float' => %w[ double real numeric decimal ],
27
+ 'integer' => %w[ integer tinyint smallint int int2 int4 int8 bigint serial bigserial ],
28
+ 'string' => %w[ text char varchar character ],
29
+ 'boolean' => %w[ bool boolean ],
30
+ 'blob' => %w[ binary blob ],
31
+ }
32
+ end
33
+
34
+ # say what method to call to convert an sql type to a ruby type
35
+ #
36
+ def sql_to_method( sql_type ) # :nodoc:
37
+ unless @sql_to_method
38
+ @sql_to_method = {}
39
+ methods_handling_sql_types.each_pair do |method, sql_types|
40
+ sql_types.each { |t| @sql_to_method[t] = method }
41
+ end
42
+ end
43
+ return @sql_to_method[sql_type]
44
+ end
45
+ end
46
+
47
+ def initialize
48
+ end
49
+
50
+ ##
51
+ # A straight logical mapping (for me at least) of basic Ruby classes to SQLite types, if
52
+ # nothing can be found then default to TEXT.
53
+ #
54
+ def bind_type_of( obj )
55
+ case obj
56
+ when Float
57
+ ::Amalgalite::SQLite3::Constants::DataType::FLOAT
58
+ when Fixnum
59
+ ::Amalgalite::SQLite3::Constants::DataType::INTEGER
60
+ when NilClass
61
+ ::Amalgalite::SQLite3::Constants::DataType::NULL
62
+ when ::Amalgalite::Blob
63
+ ::Amalgalite::SQLite3::Constants::DataType::BLOB
64
+ else
65
+ ::Amalgalite::SQLite3::Constants::DataType::TEXT
66
+ end
67
+ end
68
+
69
+ ##
70
+ # Map the incoming value to an outgoing value. For some incoming values,
71
+ # there will be no change, but for some (i.e. Dates and Times) there is some
72
+ # conversion
73
+ #
74
+ def result_value_of( declared_type, value )
75
+ case value
76
+ when Numeric
77
+ return value
78
+ when NilClass
79
+ return value
80
+ when String
81
+ if declared_type then
82
+ conversion_method = DefaultMap.sql_to_method( declared_type.downcase )
83
+ if conversion_method then
84
+ return send(conversion_method, value)
85
+ else
86
+ raise ::Amalgalite::Error, "Unable to convert SQL type of #{declared_type} to a Ruby class"
87
+ end
88
+ else
89
+ # unable to do any other conversion, just return what we have.
90
+ return value
91
+ end
92
+ else
93
+ raise ::Amalgalite::Error, "Unable to convert a class #{value.class.name} with value #{value.inspect}"
94
+ end
95
+ end
96
+
97
+ ##
98
+ # convert a string to a date
99
+ #
100
+ def date( str )
101
+ Date.parse( str )
102
+ end
103
+
104
+ ##
105
+ # convert a string to a datetime
106
+ #
107
+ def datetime( str )
108
+ DateTime.parse( str )
109
+ end
110
+
111
+ ##
112
+ # convert a string to a Time
113
+ #
114
+ def time( str )
115
+ Time.parse( str )
116
+ end
117
+
118
+ ##
119
+ # convert a string to a Float
120
+ #
121
+ def float( str )
122
+ Float( str )
123
+ end
124
+
125
+ ##
126
+ # convert an string to an Integer
127
+ #
128
+ def integer( str )
129
+ Float( str ).to_i
130
+ end
131
+
132
+ ##
133
+ # convert a string to a String, yes redundant I know.
134
+ #
135
+ def string( str )
136
+ str
137
+ end
138
+
139
+ ##
140
+ # convert a string to true of false
141
+ #
142
+ def boolean( str )
143
+ ::Amalgalite::Boolean.to_bool( str )
144
+ end
145
+
146
+ ##
147
+ # convert a string to a blog
148
+ #
149
+ def blob( str )
150
+ raise NotImplementedError, "Blob type conversion is not implemented"
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,41 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ require 'amalgalite/type_map'
7
+ require 'amalgalite3'
8
+
9
+ module Amalgalite::TypeMaps
10
+ ##
11
+ # An Amalagliate TypeMap that has a one-to-one conversion between SQLite types
12
+ # and Ruby classes
13
+ #
14
+ class StorageMap < ::Amalgalite::TypeMap
15
+ ##
16
+ # A straight logical mapping (for me at least) of basic Ruby classes to SQLite types, if
17
+ # nothing can be found then default to TEXT.
18
+ #
19
+ def bind_type_of( obj )
20
+ case obj
21
+ when Float
22
+ ::Amalgalite::SQLite3::Constants::DataType::FLOAT
23
+ when Fixnum
24
+ ::Amalgalite::SQLite3::Constants::DataType::INTEGER
25
+ when NilClass
26
+ ::Amalgalite::SQLite3::Constants::DataType::NULL
27
+ when ::Amalgalite::Blob
28
+ ::Amalgalite::SQLite3::Constants::DataType::BLOB
29
+ else
30
+ ::Amalgalite::SQLite3::Constants::DataType::TEXT
31
+ end
32
+ end
33
+
34
+ ##
35
+ # Do no mapping, just return the value as it was retrieved from SQLite.
36
+ #
37
+ def result_value_of( delcared_type, value )
38
+ return value
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+ #
6
+ require 'amalgalite/type_map'
7
+ require 'amalgalite3'
8
+
9
+ module Amalgalite::TypeMaps
10
+ ##
11
+ # An Amalagliate TypeMap that converts both bind parameters and result
12
+ # parameters to a String, no matter what.
13
+ #
14
+ class TextMap < ::Amalgalite::TypeMap
15
+ def bind_type_of( obj )
16
+ return ::Amalgalite::SQLite3::Constants::DataType::TEXT
17
+ end
18
+
19
+ def result_value_of( delcared_type, value )
20
+ return value.to_s
21
+ end
22
+ end
23
+ end