libsql 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +60 -0
  3. data/HISTORY.md +6 -0
  4. data/LICENSE +31 -0
  5. data/Manifest.txt +96 -0
  6. data/README.md +59 -0
  7. data/Rakefile +28 -0
  8. data/TODO.md +57 -0
  9. data/examples/a.rb +9 -0
  10. data/examples/blob.rb +106 -0
  11. data/examples/define_aggregate.rb +75 -0
  12. data/examples/define_function.rb +104 -0
  13. data/examples/fts5.rb +152 -0
  14. data/examples/gem-db.rb +94 -0
  15. data/examples/schema-info.rb +34 -0
  16. data/ext/libsql/c/extconf.rb +86 -0
  17. data/ext/libsql/c/gen_constants.rb +353 -0
  18. data/ext/libsql/c/libsql_blob.c +240 -0
  19. data/ext/libsql/c/libsql_constants.c +1518 -0
  20. data/ext/libsql/c/libsql_database.c +1188 -0
  21. data/ext/libsql/c/libsql_ext.c +383 -0
  22. data/ext/libsql/c/libsql_ext.h +149 -0
  23. data/ext/libsql/c/libsql_statement.c +649 -0
  24. data/ext/libsql/c/notes.txt +134 -0
  25. data/ext/libsql/c/sqlite3.c +247030 -0
  26. data/ext/libsql/c/sqlite3.h +13436 -0
  27. data/lib/libsql/aggregate.rb +73 -0
  28. data/lib/libsql/blob.rb +186 -0
  29. data/lib/libsql/boolean.rb +42 -0
  30. data/lib/libsql/busy_timeout.rb +47 -0
  31. data/lib/libsql/column.rb +99 -0
  32. data/lib/libsql/csv_table_importer.rb +75 -0
  33. data/lib/libsql/database.rb +933 -0
  34. data/lib/libsql/function.rb +61 -0
  35. data/lib/libsql/index.rb +43 -0
  36. data/lib/libsql/memory_database.rb +15 -0
  37. data/lib/libsql/paths.rb +80 -0
  38. data/lib/libsql/profile_tap.rb +131 -0
  39. data/lib/libsql/progress_handler.rb +21 -0
  40. data/lib/libsql/schema.rb +225 -0
  41. data/lib/libsql/sqlite3/constants.rb +95 -0
  42. data/lib/libsql/sqlite3/database/function.rb +48 -0
  43. data/lib/libsql/sqlite3/database/status.rb +68 -0
  44. data/lib/libsql/sqlite3/libsql_version.rb +32 -0
  45. data/lib/libsql/sqlite3/status.rb +60 -0
  46. data/lib/libsql/sqlite3/version.rb +55 -0
  47. data/lib/libsql/sqlite3.rb +7 -0
  48. data/lib/libsql/statement.rb +421 -0
  49. data/lib/libsql/table.rb +91 -0
  50. data/lib/libsql/taps/console.rb +27 -0
  51. data/lib/libsql/taps/io.rb +74 -0
  52. data/lib/libsql/taps.rb +2 -0
  53. data/lib/libsql/trace_tap.rb +35 -0
  54. data/lib/libsql/type_map.rb +63 -0
  55. data/lib/libsql/type_maps/default_map.rb +166 -0
  56. data/lib/libsql/type_maps/storage_map.rb +38 -0
  57. data/lib/libsql/type_maps/text_map.rb +21 -0
  58. data/lib/libsql/version.rb +8 -0
  59. data/lib/libsql/view.rb +26 -0
  60. data/lib/libsql-ruby.rb +1 -0
  61. data/lib/libsql.rb +51 -0
  62. data/spec/aggregate_spec.rb +158 -0
  63. data/spec/blob_spec.rb +78 -0
  64. data/spec/boolean_spec.rb +24 -0
  65. data/spec/busy_handler.rb +157 -0
  66. data/spec/data/iso-3166-country.txt +242 -0
  67. data/spec/data/iso-3166-schema.sql +22 -0
  68. data/spec/data/iso-3166-subcountry.txt +3995 -0
  69. data/spec/data/make-iso-db.sh +12 -0
  70. data/spec/database_spec.rb +505 -0
  71. data/spec/default_map_spec.rb +92 -0
  72. data/spec/function_spec.rb +78 -0
  73. data/spec/integeration_spec.rb +97 -0
  74. data/spec/iso_3166_database.rb +58 -0
  75. data/spec/json_spec.rb +24 -0
  76. data/spec/libsql_spec.rb +4 -0
  77. data/spec/paths_spec.rb +28 -0
  78. data/spec/progress_handler_spec.rb +91 -0
  79. data/spec/rtree_spec.rb +66 -0
  80. data/spec/schema_spec.rb +131 -0
  81. data/spec/spec_helper.rb +48 -0
  82. data/spec/sqlite3/constants_spec.rb +108 -0
  83. data/spec/sqlite3/database_status_spec.rb +36 -0
  84. data/spec/sqlite3/libsql_version_spec.rb +16 -0
  85. data/spec/sqlite3/status_spec.rb +22 -0
  86. data/spec/sqlite3/version_spec.rb +28 -0
  87. data/spec/sqlite3_spec.rb +53 -0
  88. data/spec/statement_spec.rb +168 -0
  89. data/spec/storage_map_spec.rb +38 -0
  90. data/spec/tap_spec.rb +57 -0
  91. data/spec/text_map_spec.rb +20 -0
  92. data/spec/type_map_spec.rb +14 -0
  93. data/spec/version_spec.rb +8 -0
  94. data/tasks/custom.rake +134 -0
  95. data/tasks/default.rake +257 -0
  96. data/tasks/extension.rake +29 -0
  97. data/tasks/this.rb +208 -0
  98. metadata +325 -0
@@ -0,0 +1,61 @@
1
+ require 'libsql/sqlite3/database/function'
2
+ module ::Libsql
3
+ #
4
+ # A Base class to inherit from for creating your own SQL scalar functions
5
+ # in ruby.
6
+ #
7
+ # These are SQL functions similar to _abs(X)_, _length(X)_, _random()_. Items
8
+ # that take parameters and return value. They have no state between
9
+ # calls. Built in SQLite scalar functions are :
10
+ #
11
+ # * http://www.sqlite.org/lang_corefunc.html
12
+ # * http://www.sqlite.org/lang_datefunc.html
13
+ #
14
+ # Functions defined in ::Libsql databases conform to the Proc interface.
15
+ # Everything that is defined in an ::Libsql database using +define_function+
16
+ # has its +to_proc+ method called. As a result, any Function must also
17
+ # conform to the +to_proc+ protocol.
18
+ #
19
+ # If you choose to use Function as a parent class of your SQL scalar function
20
+ # implementation you should only have implement +call+ with the appropriate
21
+ # _arity_.
22
+ #
23
+ # For instance to implement a _sha1(X)_ SQL function you could implement it as
24
+ #
25
+ # class SQLSha1 < ::Libsql::Function
26
+ # def initialize
27
+ # super( 'md5', 1 )
28
+ # end
29
+ # def call( s )
30
+ # ::Digest::MD5.hexdigest( s.to_s )
31
+ # end
32
+ # end
33
+ #
34
+ class Function
35
+ # The name of the SQL function
36
+ attr_accessor :name
37
+
38
+ # The arity of the SQL function
39
+ attr_accessor :arity
40
+
41
+ # Initialize the function with a name and arity
42
+ def initialize( name, arity )
43
+ @name = name
44
+ @arity = arity
45
+ end
46
+
47
+ # All SQL functions defined foloow the +to_proc+ protocol
48
+ def to_proc
49
+ self
50
+ end
51
+
52
+ # <b>Do Not Override</b>
53
+ #
54
+ # The function signature for use by the Amaglaite datase in tracking
55
+ # function definition and removal.
56
+ #
57
+ def signature
58
+ @signature ||= ::Libsql::SQLite3::Database::Function.signature( self.name, self.arity )
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,43 @@
1
+ #--
2
+ # Copyright (c) 2023 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ module ::Libsql
7
+ #
8
+ # a class representing the meta information about an SQLite index
9
+ #
10
+ class Index
11
+ # the name of the index
12
+ attr_reader :name
13
+
14
+ # the sql statement that created the index
15
+ attr_reader :sql
16
+
17
+ # the table the index is for
18
+ attr_accessor :table
19
+
20
+ # the columns that make up this index, in index order
21
+ attr_accessor :columns
22
+
23
+ # sqlite sequence number of the index
24
+ attr_accessor :sequence_number
25
+
26
+ # is the index unique
27
+ attr_writer :unique
28
+
29
+ def initialize( name, sql, table )
30
+ @name = name
31
+ @sql = sql
32
+ @table = table
33
+ @columns = []
34
+ @sequence_number = nil
35
+ @unique = nil
36
+ end
37
+
38
+ def unique?
39
+ return @unique
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,15 @@
1
+ require 'libsql/database'
2
+ module ::Libsql
3
+ #
4
+ # The encapsulation of a connection to an SQLite3 in-memory database.
5
+ #
6
+ # Open an in-memory database:
7
+ #
8
+ # db = ::Libsql::MemoryDatabase.new
9
+ #
10
+ class MemoryDatabase < Database
11
+ def initialize
12
+ super( ":memory:" )
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,80 @@
1
+ #--
2
+ # Copyright (c) 2023 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+ module ::Libsql
6
+ #
7
+ # Paths contains helpful methods to determine paths of files inside the
8
+ # ::Libsql library
9
+ #
10
+ module Paths
11
+ #
12
+ # The root directory of the project is considered to be the parent directory
13
+ # of the 'lib' directory.
14
+ #
15
+ # returns:: [String] The full expanded path of the parent directory of 'lib'
16
+ # going up the path from the current file. Trailing
17
+ # File::SEPARATOR is guaranteed.
18
+ #
19
+ def self.root_dir
20
+ @root_dir ||= (
21
+ path_parts = ::File.expand_path(__FILE__).split(::File::SEPARATOR)
22
+ lib_index = path_parts.rindex("lib")
23
+ path_parts[0...lib_index].join(::File::SEPARATOR) + ::File::SEPARATOR
24
+ )
25
+ return @root_dir
26
+ end
27
+
28
+ # returns:: [String] The full expanded path of the +config+ directory
29
+ # below _root_dir_. All parameters passed in are joined onto the
30
+ # result. Trailing File::SEPARATOR is guaranteed if _args_ are
31
+ # *not* present.
32
+ #
33
+ def self.config_path(*args)
34
+ self.sub_path("config", *args)
35
+ end
36
+
37
+ # returns:: [String] The full expanded path of the +data+ directory below
38
+ # _root_dir_. All parameters passed in are joined onto the
39
+ # result. Trailing File::SEPARATOR is guaranteed if
40
+ # _*args_ are *not* present.
41
+ #
42
+ def self.data_path(*args)
43
+ self.sub_path("data", *args)
44
+ end
45
+
46
+ # returns:: [String] The full expanded path of the +lib+ directory below
47
+ # _root_dir_. All parameters passed in are joined onto the
48
+ # result. Trailing File::SEPARATOR is guaranteed if
49
+ # _*args_ are *not* present.
50
+ #
51
+ def self.lib_path(*args)
52
+ self.sub_path("lib", *args)
53
+ end
54
+
55
+ # returns:: [String] The full expanded path of the +ext+ directory below
56
+ # _root_dir_. All parameters passed in are joined onto the
57
+ # result. Trailing File::SEPARATOR is guaranteed if
58
+ # _*args_ are *not* present.
59
+ #
60
+ def self.ext_path(*args)
61
+ self.sub_path("ext", *args)
62
+ end
63
+
64
+ # returns:: [String] The full expanded path of the +spec+ directory below
65
+ # _root_dir_. All parameters passed in are joined onto the
66
+ # result. Trailing File::SEPARATOR is guaranteed if
67
+ # _*args_ are *not* present.
68
+ #
69
+ def self.spec_path(*args)
70
+ self.sub_path("spec", *args)
71
+ end
72
+
73
+
74
+ def self.sub_path(sub,*args)
75
+ sp = ::File.join(root_dir, sub) + File::SEPARATOR
76
+ sp = ::File.join(sp, *args) if args
77
+ end
78
+ end
79
+ end
80
+
@@ -0,0 +1,131 @@
1
+ #--
2
+ # Copyright (c) 2023 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ module ::Libsql
7
+ #
8
+ # A ProfileSampler is a sampler of profile times. It aggregates up profile
9
+ # events that happen for the same source. It is based upon the RFuzz::Sampler
10
+ # class from the rfuzz gem
11
+ #
12
+ class ProfileSampler
13
+ #
14
+ # create a new sampler with the given name
15
+ #
16
+ def initialize( name )
17
+ @name = name
18
+ reset!
19
+ end
20
+
21
+ ##
22
+ # reset the internal state so it may be used again
23
+ #
24
+ def reset!
25
+ @sum = 0.0
26
+ @sumsq = 0.0
27
+ @n = 0
28
+ @min = 0.0
29
+ @max = 0.0
30
+ end
31
+
32
+ ##
33
+ # add a sample to the calculations
34
+ #
35
+ def sample( value )
36
+ @sum += value
37
+ @sumsq += (value * value)
38
+ if @n == 0 then
39
+ @min = @max = value
40
+ else
41
+ @min = value if value < @min
42
+ @max = value if value > @max
43
+ end
44
+ @n += 1
45
+ end
46
+
47
+ ##
48
+ # return the mean of the data
49
+ #
50
+ def mean
51
+ @sum / @n
52
+ end
53
+
54
+ ##
55
+ # returns the standard deviation of the data
56
+ #
57
+ def stddev
58
+ begin
59
+ return 0.0 if ( 1 == @n )
60
+ Math.sqrt( (@sumsq - ( @sum * @sum / @n)) / (@n-1) )
61
+ rescue Errno::EDOM
62
+ return 0.0
63
+ end
64
+ end
65
+
66
+ ##
67
+ # return all the values as an array
68
+ #
69
+ def to_a
70
+ [ @name, @sum, @sumsq, @n, mean, stddev, @min, @max ]
71
+ end
72
+
73
+ ##
74
+ # return all the values as a hash
75
+ #
76
+ def to_h
77
+ { 'name' => @name, 'n' => @n,
78
+ 'sum' => @sum, 'sumsq' => @sumsq, 'mean' => mean,
79
+ 'stddev' => stddev, 'min' => @min, 'max' => @max }
80
+ end
81
+
82
+ ##
83
+ # return a string containing the sampler summary
84
+ #
85
+ def to_s
86
+ "[%s] => sum: %d, sumsq: %d, n: %d, mean: %0.6f, stddev: %0.6f, min: %d, max: %d" % self.to_a
87
+ end
88
+
89
+ end
90
+
91
+ #
92
+ # A Profile Tap recives +profile+ events from SQLite which involve the number of
93
+ # nanoseconds in wall-clock time it took for a particular thing to happen. In
94
+ # general this +thing+ is an SQL statement.
95
+ #
96
+ # It has a well known +profile+ method which when invoked will write the event
97
+ # to a delegate object.
98
+ #
99
+ #
100
+ class ProfileTap
101
+
102
+ attr_reader :samplers
103
+
104
+ #
105
+ # Create a new ProfileTap object that wraps the given object and calls the
106
+ # method named in +send_to+ ever time a profile event happens.
107
+ #
108
+ def initialize( wrapped_obj, send_to = 'profile' )
109
+ unless wrapped_obj.respond_to?( send_to )
110
+ raise ::Libsql::Error, "#{wrapped_obj.class.name} does not respond to #{send_to.to_s} "
111
+ end
112
+
113
+ @delegate_obj = wrapped_obj
114
+ @delegate_method = send_to
115
+ @samplers = {}
116
+ end
117
+
118
+ #
119
+ # Record the profile information and send the delegate object the msg and
120
+ # time information.
121
+ #
122
+ def profile( msg, time )
123
+ msg = msg.gsub(/\s+/,' ')
124
+ unless sampler = @samplers[msg]
125
+ sampler = @samplers[msg] = ProfileSampler.new( msg )
126
+ end
127
+ sampler.sample( time )
128
+ @delegate_obj.send( @delegate_method, msg, time )
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,21 @@
1
+ module ::Libsql
2
+ ##
3
+ # A base class for use in creating your own progress handler classes
4
+ #
5
+ class ProgressHandler
6
+ def to_proc
7
+ self
8
+ end
9
+
10
+ # the arity of the call method
11
+ def arity() 0 ; end
12
+
13
+ ##
14
+ # Override this method, returning +false+ if the SQLite should act as if
15
+ # +interrupt!+ had been invoked.
16
+ #
17
+ def call
18
+ raise NotImplementedError, "The progress handler call() method must be implemented"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,225 @@
1
+ #--
2
+ # Copyright (c) 2023 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ require 'libsql/table'
7
+ require 'libsql/index'
8
+ require 'libsql/column'
9
+ require 'libsql/view'
10
+
11
+ module ::Libsql
12
+ #
13
+ # An object view of the schema in the SQLite database. If the schema changes
14
+ # after this class is created, it has no knowledge of that.
15
+ #
16
+ class Schema
17
+
18
+ # The internal database that this schema is for. Most of the time this will
19
+ # be 'main' for the main database. For the temp tables, this will be 'temp'
20
+ # and for any attached databsae, this is the name of attached database.
21
+ attr_reader :catalog
22
+
23
+ # The schema_version at the time this schema was taken.
24
+ attr_reader :schema_version
25
+
26
+ # The Amalagalite::Database this schema is associated with.
27
+ attr_reader :db
28
+
29
+ #
30
+ # Create a new instance of Schema
31
+ #
32
+ def initialize( db, catalog = 'main', master_table = 'sqlite_master' )
33
+ @db = db
34
+ @catalog = catalog
35
+ @schema_version = nil
36
+ @tables = {}
37
+ @views = {}
38
+ @master_table = master_table
39
+
40
+ if @master_table == 'sqlite_master' then
41
+ @temp_schema = ::Libsql::Schema.new( db, 'temp', 'sqlite_temp_master')
42
+ else
43
+ @temp_schema = nil
44
+ end
45
+ load_schema!
46
+ end
47
+
48
+ def catalog_master_table
49
+ "#{catalog}.#{@master_table}"
50
+ end
51
+
52
+ def temporary?
53
+ catalog == "temp"
54
+ end
55
+
56
+ def dirty?()
57
+ return true if (@schema_version != self.current_version)
58
+ return false unless @temp_schema
59
+ return @temp_schema.dirty?
60
+ end
61
+
62
+ def current_version
63
+ @db.first_value_from("PRAGMA #{catalog}.schema_version")
64
+ end
65
+
66
+ #
67
+ # load the schema from the database
68
+ def load_schema!
69
+ load_tables
70
+ load_views
71
+ if @temp_schema then
72
+ @temp_schema.load_schema!
73
+ end
74
+ @schema_version = self.current_version
75
+ nil
76
+ end
77
+
78
+ ##
79
+ # return the tables, reloading if dirty.
80
+ # If there is a temp table and a normal table with the same name, then the
81
+ # temp table is the one that is returned in the hash.
82
+ def tables
83
+ load_schema! if dirty?
84
+ t = @tables
85
+ if @temp_schema then
86
+ t = @tables.merge( @temp_schema.tables )
87
+ end
88
+ return t
89
+ end
90
+
91
+ ##
92
+ # load all the tables
93
+ #
94
+ def load_tables
95
+ @tables = {}
96
+ @db.execute("SELECT tbl_name FROM #{catalog_master_table} WHERE type = 'table' AND name != 'sqlite_sequence'") do |table_info|
97
+ table = load_table( table_info['tbl_name'] )
98
+ table.indexes = load_indexes( table )
99
+ @tables[table.name] = table
100
+ end
101
+ return @tables
102
+ end
103
+
104
+ ##
105
+ # Load a single table
106
+ def load_table( table_name )
107
+ rows = @db.execute("SELECT tbl_name, sql FROM #{catalog_master_table} WHERE type = 'table' AND tbl_name = ?", table_name)
108
+ table_info = rows.first
109
+ table = nil
110
+ if table_info then
111
+ table = ::Libsql::Table.new( table_info['tbl_name'], table_info['sql'] )
112
+ table.schema = self
113
+ table.columns = load_columns( table )
114
+ table.indexes = load_indexes( table )
115
+ @tables[table.name] = table
116
+ end
117
+ return table
118
+ end
119
+
120
+ ##
121
+ # load all the indexes for a particular table
122
+ #
123
+ def load_indexes( table )
124
+ indexes = {}
125
+
126
+ @db.prepare("SELECT name, sql FROM #{catalog_master_table} WHERE type ='index' and tbl_name = $name") do |idx_stmt|
127
+ idx_stmt.execute( "$name" => table.name) do |idx_info|
128
+ indexes[idx_info['name']] = ::Libsql::Index.new( idx_info['name'], idx_info['sql'], table )
129
+ end
130
+ end
131
+
132
+ @db.execute("PRAGMA index_list( #{@db.quote(table.name)} );") do |idx_list|
133
+ idx = indexes[idx_list['name']]
134
+
135
+ # temporary indexes do not show up in the previous list
136
+ if idx.nil? then
137
+ idx = ::Libsql::Index.new( idx_list['name'], nil, table )
138
+ indexes[idx_list['name']] = idx
139
+ end
140
+
141
+ idx.sequence_number = idx_list['seq']
142
+ idx.unique = Boolean.to_bool( idx_list['unique'] )
143
+
144
+ @db.execute("PRAGMA index_info( #{@db.quote(idx.name)} );") do |col_info|
145
+ idx.columns << table.columns[col_info['name']]
146
+ end
147
+ end
148
+ return indexes
149
+ end
150
+
151
+ ##
152
+ # load all the columns for a particular table
153
+ #
154
+ def load_columns( table )
155
+ cols = {}
156
+ idx = 0
157
+ @db.execute("PRAGMA #{catalog}.table_info(#{@db.quote(table.name)})") do |row|
158
+ col = ::Libsql::Column.new( catalog, table.name, row['name'], row['cid'])
159
+
160
+ col.default_value = row['dflt_value']
161
+
162
+ col.declared_data_type = row['type']
163
+ col.not_null_constraint = row['notnull']
164
+ col.primary_key = row['pk']
165
+
166
+ # need to remove leading and trailing ' or " from the default value
167
+ if col.default_value and col.default_value.kind_of?( String ) and ( col.default_value.length >= 2 ) then
168
+ fc = col.default_value[0].chr
169
+ lc = col.default_value[-1].chr
170
+ if fc == lc and ( fc == "'" || fc == '"' ) then
171
+ col.default_value = col.default_value[1..-2]
172
+ end
173
+ end
174
+
175
+ unless table.temporary? then
176
+ # get more exact information
177
+ @db.api.table_column_metadata( catalog, table.name, col.name ).each_pair do |key, value|
178
+ col.send("#{key}=", value)
179
+ end
180
+ end
181
+ col.schema = self
182
+ cols[col.name] = col
183
+ idx += 1
184
+ end
185
+ return cols
186
+ end
187
+
188
+ ##
189
+ # return the views, reloading if dirty
190
+ #
191
+ # If there is a temp view, and a regular view of the same name, then the
192
+ # temporary view is the one that is returned in the hash.
193
+ #
194
+ def views
195
+ reload_schema! if dirty?
196
+ v = @views
197
+ if @temp_schema then
198
+ v = @views.merge( @temp_schema.views )
199
+ end
200
+ return v
201
+ end
202
+
203
+ ##
204
+ # load a single view
205
+ #
206
+ def load_view( name )
207
+ rows = @db.execute("SELECT name, sql FROM #{catalog_master_table} WHERE type = 'view' AND name = ?", name )
208
+ view_info = rows.first
209
+ view = ::Libsql::View.new( view_info['name'], view_info['sql'] )
210
+ view.schema = self
211
+ return view
212
+ end
213
+
214
+ ##
215
+ # load all the views for the database
216
+ #
217
+ def load_views
218
+ @db.execute("SELECT name, sql FROM #{catalog_master_table} WHERE type = 'view'") do |view_info|
219
+ view = load_view( view_info['name'] )
220
+ @views[view.name] = view
221
+ end
222
+ return @views
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,95 @@
1
+ #--
2
+ # Copyright (c) 2023 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+ module ::Libsql::SQLite3
6
+ module Constants
7
+ module Helpers
8
+ #
9
+ # convert an integer value into the string representation of the associated
10
+ # constant. this is a helper method used by some of the other modules
11
+ #
12
+ def name_from_value( value )
13
+ unless defined? @const_map_from_value
14
+ @const_map_from_value = {}
15
+ constants.each do |const_name|
16
+ c_int = const_get( const_name )
17
+ @const_map_from_value[c_int] = const_name.to_s
18
+ end
19
+ end
20
+ return @const_map_from_value[ value ]
21
+ end
22
+
23
+ #
24
+ # convert a string into the constant value. This is helper method used by
25
+ # some of the other modules
26
+ #
27
+ def value_from_name( name )
28
+ unless defined? @const_map_from_name
29
+ @const_map_from_name = {}
30
+ constants.each do |const_name|
31
+ c_int = const_get( const_name )
32
+ @const_map_from_name[ const_name.to_s ] = c_int
33
+ end
34
+ end
35
+ return @const_map_from_name[ name.upcase ]
36
+ end
37
+ end
38
+
39
+
40
+ ##
41
+ # DataType defines the namespace for all possible SQLite data types.
42
+ #
43
+ module DataType
44
+ extend Helpers
45
+ end
46
+
47
+ ##
48
+ # Open defines the namespace for all possible flags to the Database.open
49
+ # method
50
+ #
51
+ module Open
52
+ extend Helpers
53
+ end
54
+
55
+ ##
56
+ # Status defines the namespace for all the possible status flags for
57
+ # ::Libsql::SQLite3::Status objects
58
+ #
59
+ module Status
60
+ extend Helpers
61
+ end
62
+
63
+ ##
64
+ # DBStatus defines the namespace for all the possible status codes for the
65
+ # ::Libsql::SQlite3::Database::Status objects.
66
+ #
67
+ module DBStatus
68
+ extend Helpers
69
+ end
70
+
71
+ ##
72
+ # ResultCode defines the namespace for all possible result codes from an
73
+ # SQLite API call.
74
+ #
75
+ module ResultCode
76
+ extend Helpers
77
+ end # end ResultCode
78
+
79
+ ##
80
+ # Config defines the namespace for all possible parameter for the
81
+ # sqlite config API.
82
+ #
83
+ module Config
84
+ extend Helpers
85
+ end
86
+
87
+ ##
88
+ # StatementStatus defines the namespace for all the possible status codes
89
+ # for the SQLite prepared statements
90
+ #
91
+ module StatementStatus
92
+ extend Helpers
93
+ end
94
+ end
95
+ end