db-mariadb 0.11.2 → 0.13.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/context/getting-started.md +37 -0
- data/context/index.yaml +12 -0
- data/lib/db/mariadb/adapter.rb +8 -2
- data/lib/db/mariadb/connection.rb +54 -11
- data/lib/db/mariadb/error.rb +1 -0
- data/lib/db/mariadb/native/connection.rb +52 -6
- data/lib/db/mariadb/native/field.rb +16 -7
- data/lib/db/mariadb/native/result.rb +29 -2
- data/lib/db/mariadb/native/types.rb +64 -5
- data/lib/db/mariadb/native.rb +8 -7
- data/lib/db/mariadb/version.rb +4 -2
- data/lib/db/mariadb.rb +5 -5
- data/license.md +1 -1
- data/readme.md +8 -0
- data/releases.md +5 -0
- data.tar.gz.sig +0 -0
- metadata +24 -12
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be804b294c1772c8839f21044deec4b397dea3b7c2212587839f64ee038d9a92
|
|
4
|
+
data.tar.gz: 19c7766d192dbe9443ef4fa0acd1dbf90be1b9d925084617603b347fbfb6095b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 82bb2012e7e245ccca60f022e55754ad05707b3c4f37432db124ba39b8c208793028964295bedd445b8905fc929abeb219575e3693870d65fd1b418592bb2f7c
|
|
7
|
+
data.tar.gz: f8f6b604648f295a6778a1ff923737a4d8278c4711b7977265509e36a4194cdd2155fec3ebfce4a01b19eb95fa2720f350e0e7739e35a0e5d68e6dfce762286e
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
This guide explains how to get started with the `db-mariadb` gem.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add the gem to your project:
|
|
8
|
+
|
|
9
|
+
~~~ bash
|
|
10
|
+
$ bundle add db-mariadb
|
|
11
|
+
~~~
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Here is an example of the basic usage of the adapter:
|
|
16
|
+
|
|
17
|
+
~~~ ruby
|
|
18
|
+
require 'async'
|
|
19
|
+
require 'db/mariadb'
|
|
20
|
+
|
|
21
|
+
# Create an event loop:
|
|
22
|
+
Sync do
|
|
23
|
+
# Create the adapter and connect to the database:
|
|
24
|
+
adapter = DB::MariaDB::Adapter.new(database: 'test')
|
|
25
|
+
connection = adapter.call
|
|
26
|
+
|
|
27
|
+
# Execute the query:
|
|
28
|
+
result = connection.send_query("SELECT VERSION()")
|
|
29
|
+
|
|
30
|
+
# Get the results:
|
|
31
|
+
pp connection.next_result.to_a
|
|
32
|
+
# => [["10.4.13-MariaDB"]]
|
|
33
|
+
ensure
|
|
34
|
+
# Return the connection to the client connection pool:
|
|
35
|
+
connection.close
|
|
36
|
+
end
|
|
37
|
+
~~~
|
data/context/index.yaml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Automatically generated context index for Utopia::Project guides.
|
|
2
|
+
# Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`.
|
|
3
|
+
---
|
|
4
|
+
description: An event-driven interface for MariaDB and MySQL servers.
|
|
5
|
+
metadata:
|
|
6
|
+
documentation_uri: https://socketry.github.io/db-mariadb/
|
|
7
|
+
funding_uri: https://github.com/sponsors/ioquatix
|
|
8
|
+
source_code_uri: https://github.com/socketry/db-mariadb.git
|
|
9
|
+
files:
|
|
10
|
+
- path: getting-started.md
|
|
11
|
+
title: Getting Started
|
|
12
|
+
description: This guide explains how to get started with the `db-mariadb` gem.
|
data/lib/db/mariadb/adapter.rb
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require_relative
|
|
6
|
+
require_relative "connection"
|
|
7
7
|
|
|
8
8
|
module DB
|
|
9
9
|
module MariaDB
|
|
10
|
+
# A database adapter for connecting to MariaDB and MySQL servers.
|
|
10
11
|
class Adapter
|
|
12
|
+
# Initialize a new adapter with connection options.
|
|
13
|
+
# @parameter options [Hash] Connection options to be passed to the connection.
|
|
11
14
|
def initialize(**options)
|
|
12
15
|
@options = options
|
|
13
16
|
end
|
|
14
17
|
|
|
18
|
+
# @attribute [Hash] The connection options.
|
|
15
19
|
attr :options
|
|
16
20
|
|
|
21
|
+
# Create a new database connection.
|
|
22
|
+
# @returns [Connection] A new connection instance.
|
|
17
23
|
def call
|
|
18
24
|
Connection.new(**@options)
|
|
19
25
|
end
|
|
@@ -1,52 +1,67 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require
|
|
6
|
+
require "async/pool/resource"
|
|
7
|
+
require "db/features"
|
|
7
8
|
|
|
8
|
-
require_relative
|
|
9
|
+
require_relative "native/connection"
|
|
9
10
|
|
|
10
11
|
module DB
|
|
11
12
|
module MariaDB
|
|
12
|
-
#
|
|
13
|
+
# A high-level database connection that implements the standardized connection interface.
|
|
14
|
+
# This class provides a bridge between the underlying native MariaDB interface and the DB gem's unified connection API.
|
|
13
15
|
class Connection < Async::Pool::Resource
|
|
16
|
+
# Initialize a new database connection.
|
|
17
|
+
# @parameter options [Hash] Connection options passed to the native connection.
|
|
14
18
|
def initialize(**options)
|
|
15
19
|
@native = Native::Connection.connect(**options)
|
|
16
20
|
|
|
17
21
|
super()
|
|
18
22
|
end
|
|
19
23
|
|
|
24
|
+
# Close the database connection and release resources.
|
|
20
25
|
def close
|
|
21
26
|
@native.close
|
|
22
27
|
|
|
23
28
|
super
|
|
24
29
|
end
|
|
25
30
|
|
|
31
|
+
# Get the type mapping for database types.
|
|
32
|
+
# @returns [Hash] The type mapping configuration.
|
|
26
33
|
def types
|
|
27
34
|
@native.types
|
|
28
35
|
end
|
|
29
36
|
|
|
37
|
+
# Append an escaped string value to the buffer.
|
|
38
|
+
# @parameter value [String] The string value to escape and append.
|
|
39
|
+
# @parameter buffer [String] The buffer to append to.
|
|
40
|
+
# @returns [String] The buffer with the escaped string appended.
|
|
30
41
|
def append_string(value, buffer = String.new)
|
|
31
42
|
buffer << "'" << @native.escape(value) << "'"
|
|
32
43
|
|
|
33
44
|
return buffer
|
|
34
45
|
end
|
|
35
46
|
|
|
47
|
+
# Append a literal value to the buffer with appropriate formatting.
|
|
48
|
+
# @parameter value [Object] The value to append (supports Time, Date, Numeric, Boolean, nil, and strings).
|
|
49
|
+
# @parameter buffer [String] The buffer to append to.
|
|
50
|
+
# @returns [String] The buffer with the formatted value appended.
|
|
36
51
|
def append_literal(value, buffer = String.new)
|
|
37
52
|
case value
|
|
38
53
|
when Time, DateTime
|
|
39
|
-
append_string(value.utc.strftime(
|
|
54
|
+
append_string(value.utc.strftime("%Y-%m-%d %H:%M:%S"), buffer)
|
|
40
55
|
when Date
|
|
41
|
-
append_string(value.strftime(
|
|
56
|
+
append_string(value.strftime("%Y-%m-%d"), buffer)
|
|
42
57
|
when Numeric
|
|
43
58
|
buffer << value.to_s
|
|
44
59
|
when TrueClass
|
|
45
|
-
buffer <<
|
|
60
|
+
buffer << "TRUE"
|
|
46
61
|
when FalseClass
|
|
47
|
-
buffer <<
|
|
62
|
+
buffer << "FALSE"
|
|
48
63
|
when nil
|
|
49
|
-
buffer <<
|
|
64
|
+
buffer << "NULL"
|
|
50
65
|
else
|
|
51
66
|
append_string(value, buffer)
|
|
52
67
|
end
|
|
@@ -54,12 +69,16 @@ module DB
|
|
|
54
69
|
return buffer
|
|
55
70
|
end
|
|
56
71
|
|
|
72
|
+
# Append an escaped identifier to the buffer.
|
|
73
|
+
# @parameter value [String | Array(String)] The identifier or array of identifiers to escape.
|
|
74
|
+
# @parameter buffer [String] The buffer to append to.
|
|
75
|
+
# @returns [String] The buffer with the escaped identifier appended.
|
|
57
76
|
def append_identifier(value, buffer = String.new)
|
|
58
77
|
case value
|
|
59
78
|
when Array
|
|
60
79
|
first = true
|
|
61
80
|
value.each do |part|
|
|
62
|
-
buffer <<
|
|
81
|
+
buffer << "." unless first
|
|
63
82
|
first = false
|
|
64
83
|
|
|
65
84
|
buffer << escape_identifier(part)
|
|
@@ -71,7 +90,12 @@ module DB
|
|
|
71
90
|
return buffer
|
|
72
91
|
end
|
|
73
92
|
|
|
74
|
-
|
|
93
|
+
# Generate a key column definition for table creation.
|
|
94
|
+
# @parameter name [String] The column name.
|
|
95
|
+
# @parameter primary [Boolean] Whether this is a primary key column.
|
|
96
|
+
# @parameter null [Boolean] Whether this column allows null values.
|
|
97
|
+
# @returns [String] The column definition string.
|
|
98
|
+
def key_column(name = "id", primary: true, null: false)
|
|
75
99
|
buffer = String.new
|
|
76
100
|
|
|
77
101
|
append_identifier(name, buffer)
|
|
@@ -87,20 +111,39 @@ module DB
|
|
|
87
111
|
return buffer
|
|
88
112
|
end
|
|
89
113
|
|
|
114
|
+
# Get the current connection status.
|
|
115
|
+
# @returns [String] The status string from the server.
|
|
90
116
|
def status
|
|
91
117
|
@native.status
|
|
92
118
|
end
|
|
93
119
|
|
|
120
|
+
# Send a query to the database server.
|
|
121
|
+
# @parameter statement [String] The SQL statement to execute.
|
|
94
122
|
def send_query(statement)
|
|
95
123
|
@native.discard_results
|
|
96
124
|
|
|
97
125
|
@native.send_query(statement)
|
|
98
126
|
end
|
|
99
127
|
|
|
128
|
+
# Get the next result set from a multi-result query.
|
|
129
|
+
# @returns [Native::Result | Nil] The next result set, or `nil` if no more results.
|
|
100
130
|
def next_result
|
|
101
131
|
@native.next_result
|
|
102
132
|
end
|
|
103
133
|
|
|
134
|
+
FEATURES = DB::Features.new(
|
|
135
|
+
modify_column: true,
|
|
136
|
+
conditional_operations: true,
|
|
137
|
+
batch_alter_table: true,
|
|
138
|
+
auto_increment: true
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Database feature detection for migration and query building.
|
|
142
|
+
# @returns [DB::Features] The supported database features.
|
|
143
|
+
def features
|
|
144
|
+
FEATURES
|
|
145
|
+
end
|
|
146
|
+
|
|
104
147
|
protected
|
|
105
148
|
|
|
106
149
|
def escape_identifier(value)
|
data/lib/db/mariadb/error.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require_relative
|
|
7
|
-
require_relative
|
|
6
|
+
require_relative "result"
|
|
7
|
+
require_relative "../error"
|
|
8
8
|
|
|
9
9
|
module DB
|
|
10
10
|
module MariaDB
|
|
@@ -51,8 +51,22 @@ module DB
|
|
|
51
51
|
|
|
52
52
|
ffi_attach_function :mysql_real_escape_string, [:pointer, :pointer, :string, :size_t], :size_t
|
|
53
53
|
|
|
54
|
+
# A native FFI connection to the MariaDB/MySQL client library.
|
|
54
55
|
class Connection < FFI::Pointer
|
|
55
|
-
|
|
56
|
+
# Establish a connection to the MariaDB/MySQL server.
|
|
57
|
+
# @parameter host [String] The hostname or IP address to connect to.
|
|
58
|
+
# @parameter username [String | Nil] The username for authentication.
|
|
59
|
+
# @parameter password [String | Nil] The password for authentication.
|
|
60
|
+
# @parameter database [String | Nil] The database name to connect to.
|
|
61
|
+
# @parameter port [Integer] The port number to connect to.
|
|
62
|
+
# @parameter unix_socket [String | Nil] The Unix socket path for local connections.
|
|
63
|
+
# @parameter client_flags [Integer] Client connection flags.
|
|
64
|
+
# @parameter compression [Boolean] Whether to enable connection compression.
|
|
65
|
+
# @parameter types [Hash] Type mapping configuration.
|
|
66
|
+
# @parameter options [Hash] Additional connection options.
|
|
67
|
+
# @returns [Connection] A new connected instance.
|
|
68
|
+
# @raises [Error] If the connection fails.
|
|
69
|
+
def self.connect(host: "localhost", username: nil, password: nil, database: nil, port: 0, unix_socket: nil, client_flags: 0, compression: false, types: DEFAULT_TYPES, **options)
|
|
56
70
|
pointer = Native.mysql_init(nil)
|
|
57
71
|
Native.mysql_options(pointer, MYSQL_OPT_NONBLOCK, nil)
|
|
58
72
|
|
|
@@ -93,6 +107,11 @@ module DB
|
|
|
93
107
|
return self.new(pointer, io, types, **options)
|
|
94
108
|
end
|
|
95
109
|
|
|
110
|
+
# Initialize a native connection wrapper.
|
|
111
|
+
# @parameter address [FFI::Pointer] The pointer to the native connection.
|
|
112
|
+
# @parameter io [IO] The IO object for the socket.
|
|
113
|
+
# @parameter types [Hash] Type mapping configuration.
|
|
114
|
+
# @parameter options [Hash] Additional options.
|
|
96
115
|
def initialize(address, io, types, **options)
|
|
97
116
|
super(address)
|
|
98
117
|
|
|
@@ -102,8 +121,11 @@ module DB
|
|
|
102
121
|
@types = types
|
|
103
122
|
end
|
|
104
123
|
|
|
124
|
+
# @attribute [Hash] The type mapping configuration.
|
|
105
125
|
attr :types
|
|
106
126
|
|
|
127
|
+
# Wait for the specified IO condition.
|
|
128
|
+
# @parameter status [Integer] The status flags indicating which IO condition to wait for.
|
|
107
129
|
def wait_for(status)
|
|
108
130
|
if status & MYSQL_WAIT_READ
|
|
109
131
|
@io.wait_readable
|
|
@@ -112,16 +134,22 @@ module DB
|
|
|
112
134
|
end
|
|
113
135
|
end
|
|
114
136
|
|
|
137
|
+
# Check for errors and raise an exception if one occurred.
|
|
138
|
+
# @parameter message [String] The error message prefix.
|
|
139
|
+
# @raises [Error] If an error occurred.
|
|
115
140
|
def check_error!(message)
|
|
116
141
|
if Native.mysql_errno(self) != 0
|
|
117
142
|
raise Error, "#{message}: #{Native.mysql_error(self)}!"
|
|
118
143
|
end
|
|
119
144
|
end
|
|
120
145
|
|
|
146
|
+
# Get the current connection status.
|
|
147
|
+
# @returns [String] The status string from the server.
|
|
121
148
|
def status
|
|
122
149
|
Native.mysql_stat(self)
|
|
123
150
|
end
|
|
124
151
|
|
|
152
|
+
# Free the current result set.
|
|
125
153
|
def free_result
|
|
126
154
|
if @result
|
|
127
155
|
Native.mysql_free_result(@result)
|
|
@@ -130,6 +158,7 @@ module DB
|
|
|
130
158
|
end
|
|
131
159
|
end
|
|
132
160
|
|
|
161
|
+
# Close the connection and release all resources.
|
|
133
162
|
def close
|
|
134
163
|
self.free_result
|
|
135
164
|
|
|
@@ -138,6 +167,9 @@ module DB
|
|
|
138
167
|
@io.close
|
|
139
168
|
end
|
|
140
169
|
|
|
170
|
+
# Escape a string value for safe inclusion in SQL queries.
|
|
171
|
+
# @parameter value [String] The value to escape.
|
|
172
|
+
# @returns [String] The escaped string.
|
|
141
173
|
def escape(value)
|
|
142
174
|
value = value.to_s
|
|
143
175
|
|
|
@@ -149,6 +181,9 @@ module DB
|
|
|
149
181
|
return out.read_string
|
|
150
182
|
end
|
|
151
183
|
|
|
184
|
+
# Send a query to the server for execution.
|
|
185
|
+
# @parameter statement [String] The SQL statement to execute.
|
|
186
|
+
# @raises [Error] If the query fails.
|
|
152
187
|
def send_query(statement)
|
|
153
188
|
self.free_result
|
|
154
189
|
|
|
@@ -167,18 +202,23 @@ module DB
|
|
|
167
202
|
end
|
|
168
203
|
end
|
|
169
204
|
|
|
170
|
-
#
|
|
205
|
+
# Check if there are more result sets available.
|
|
206
|
+
# @returns [Boolean] True if there are more results.
|
|
171
207
|
def more_results?
|
|
172
208
|
Native.mysql_more_results(self) == 1
|
|
173
209
|
end
|
|
174
210
|
|
|
211
|
+
# Get the next result set from a multi-result query.
|
|
212
|
+
# @parameter types [Hash] Type mapping to use for this result.
|
|
213
|
+
# @returns [Result | Nil] The next result set, or `nil` if no more results.
|
|
175
214
|
def next_result(types: @types)
|
|
176
215
|
if result = self.get_result
|
|
177
216
|
return Result.new(self, types, result)
|
|
178
217
|
end
|
|
179
218
|
end
|
|
180
219
|
|
|
181
|
-
# Silently discard any results that application
|
|
220
|
+
# Silently discard any results that the application did not read.
|
|
221
|
+
# @returns [Nil]
|
|
182
222
|
def discard_results
|
|
183
223
|
while result = self.get_result
|
|
184
224
|
end
|
|
@@ -186,14 +226,20 @@ module DB
|
|
|
186
226
|
return nil
|
|
187
227
|
end
|
|
188
228
|
|
|
229
|
+
# Get the number of rows affected by the last query.
|
|
230
|
+
# @returns [Integer] The number of affected rows.
|
|
189
231
|
def affected_rows
|
|
190
232
|
Native.mysql_affected_rows(self)
|
|
191
233
|
end
|
|
192
234
|
|
|
235
|
+
# Get the last auto-generated ID from an INSERT query.
|
|
236
|
+
# @returns [Integer] The last insert ID.
|
|
193
237
|
def insert_id
|
|
194
238
|
Native.mysql_insert_id(self)
|
|
195
239
|
end
|
|
196
240
|
|
|
241
|
+
# Get information about the last query execution.
|
|
242
|
+
# @returns [String | Nil] Information string about the query.
|
|
197
243
|
def info
|
|
198
244
|
Native.mysql_info(self)
|
|
199
245
|
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require_relative
|
|
6
|
+
require_relative "../native"
|
|
7
7
|
|
|
8
|
-
require_relative
|
|
8
|
+
require_relative "types"
|
|
9
9
|
|
|
10
|
-
require
|
|
11
|
-
require
|
|
10
|
+
require "date"
|
|
11
|
+
require "json"
|
|
12
12
|
|
|
13
13
|
module DB
|
|
14
14
|
module MariaDB
|
|
@@ -46,8 +46,8 @@ module DB
|
|
|
46
46
|
|
|
47
47
|
DEFAULT_TYPES = {
|
|
48
48
|
# Pseudo types:
|
|
49
|
-
primary_key: Types::Integer.new(
|
|
50
|
-
foreign_key: Types::Integer.new(
|
|
49
|
+
primary_key: Types::Integer.new("BIGINT AUTO_INCREMENT PRIMARY KEY"),
|
|
50
|
+
foreign_key: Types::Integer.new("BIGINT"),
|
|
51
51
|
text: Types::Text.new("TEXT"),
|
|
52
52
|
string: Types::Text.new("VARCHAR(255)"),
|
|
53
53
|
|
|
@@ -77,6 +77,7 @@ module DB
|
|
|
77
77
|
set: Types::Integer.new("SET"),
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
# A field (column) in a result set with metadata and type information.
|
|
80
81
|
class Field < FFI::Struct
|
|
81
82
|
layout(
|
|
82
83
|
:name, :string,
|
|
@@ -102,14 +103,20 @@ module DB
|
|
|
102
103
|
:extension, :pointer,
|
|
103
104
|
)
|
|
104
105
|
|
|
106
|
+
# Check if this field represents a boolean type.
|
|
107
|
+
# @returns [Boolean] True if the field is a boolean.
|
|
105
108
|
def boolean?
|
|
106
109
|
self[:length] == 1 && (self[:type] == :tiny || self[:type] == :long)
|
|
107
110
|
end
|
|
108
111
|
|
|
112
|
+
# Get the field name.
|
|
113
|
+
# @returns [String] The field name.
|
|
109
114
|
def name
|
|
110
115
|
self[:name]
|
|
111
116
|
end
|
|
112
117
|
|
|
118
|
+
# Get the field type, with boolean detection.
|
|
119
|
+
# @returns [Symbol] The field type.
|
|
113
120
|
def type
|
|
114
121
|
if boolean?
|
|
115
122
|
:boolean
|
|
@@ -118,6 +125,8 @@ module DB
|
|
|
118
125
|
end
|
|
119
126
|
end
|
|
120
127
|
|
|
128
|
+
# Generate a string representation of the field.
|
|
129
|
+
# @returns [String] A human-readable representation.
|
|
121
130
|
def inspect
|
|
122
131
|
"\#<#{self.class} name=#{self.name} type=#{self.type} length=#{self[:length]}>"
|
|
123
132
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require_relative
|
|
6
|
+
require_relative "field"
|
|
7
7
|
|
|
8
8
|
module DB
|
|
9
9
|
module MariaDB
|
|
@@ -16,7 +16,12 @@ module DB
|
|
|
16
16
|
|
|
17
17
|
ffi_attach_function :mysql_fetch_fields, [:pointer], :pointer
|
|
18
18
|
|
|
19
|
+
# A result set from a database query with row iteration and type casting.
|
|
19
20
|
class Result < FFI::Pointer
|
|
21
|
+
# Initialize a new result set wrapper.
|
|
22
|
+
# @parameter connection [Connection] The connection that produced this result.
|
|
23
|
+
# @parameter types [Hash] Type mapping for field conversion.
|
|
24
|
+
# @parameter address [FFI::Pointer] The pointer to the native result.
|
|
20
25
|
def initialize(connection, types = {}, address)
|
|
21
26
|
super(address)
|
|
22
27
|
|
|
@@ -26,10 +31,14 @@ module DB
|
|
|
26
31
|
@casts = nil
|
|
27
32
|
end
|
|
28
33
|
|
|
34
|
+
# Get the number of fields in this result set.
|
|
35
|
+
# @returns [Integer] The field count.
|
|
29
36
|
def field_count
|
|
30
37
|
Native.mysql_num_fields(self)
|
|
31
38
|
end
|
|
32
39
|
|
|
40
|
+
# Get the field metadata for this result set.
|
|
41
|
+
# @returns [Array(Field)] The array of field objects.
|
|
33
42
|
def fields
|
|
34
43
|
unless @fields
|
|
35
44
|
pointer = Native.mysql_fetch_fields(self)
|
|
@@ -42,15 +51,21 @@ module DB
|
|
|
42
51
|
return @fields
|
|
43
52
|
end
|
|
44
53
|
|
|
54
|
+
# Get the field names for this result set.
|
|
55
|
+
# @returns [Array(String)] The array of field names.
|
|
45
56
|
def field_names
|
|
46
57
|
fields.map(&:name)
|
|
47
58
|
end
|
|
48
59
|
|
|
60
|
+
# Get the type converters for each field.
|
|
61
|
+
# @returns [Array] The array of type converter objects.
|
|
49
62
|
def field_types
|
|
50
63
|
fields.map{|field| @types[field.type]}
|
|
51
64
|
end
|
|
52
65
|
|
|
66
|
+
# Get the number of rows in this result set.
|
|
53
67
|
# In the context of unbuffered queries, this is the number of rows that have been fetched so far.
|
|
68
|
+
# @returns [Integer] The row count.
|
|
54
69
|
def row_count
|
|
55
70
|
Native.mysql_num_rows(self)
|
|
56
71
|
end
|
|
@@ -58,6 +73,9 @@ module DB
|
|
|
58
73
|
alias count row_count
|
|
59
74
|
alias keys field_names
|
|
60
75
|
|
|
76
|
+
# Cast row values to appropriate Ruby types.
|
|
77
|
+
# @parameter row [Array] The raw row data.
|
|
78
|
+
# @returns [Array] The row with values cast to proper types.
|
|
61
79
|
def cast!(row)
|
|
62
80
|
@casts ||= self.field_types
|
|
63
81
|
|
|
@@ -70,6 +88,9 @@ module DB
|
|
|
70
88
|
return row
|
|
71
89
|
end
|
|
72
90
|
|
|
91
|
+
# Iterate over each row in the result set.
|
|
92
|
+
# @yields {|row| ...} Each row as an array.
|
|
93
|
+
# @parameter row [Array] The current row data.
|
|
73
94
|
def each
|
|
74
95
|
row = FFI::MemoryPointer.new(:pointer)
|
|
75
96
|
field_count = self.field_count
|
|
@@ -95,6 +116,10 @@ module DB
|
|
|
95
116
|
@connection.check_error!("Reading recordset")
|
|
96
117
|
end
|
|
97
118
|
|
|
119
|
+
# Map over each row in the result set.
|
|
120
|
+
# @yields {|row| ...} Each row as an array.
|
|
121
|
+
# @parameter row [Array] The current row data.
|
|
122
|
+
# @returns [Array] The mapped results.
|
|
98
123
|
def map(&block)
|
|
99
124
|
results = []
|
|
100
125
|
|
|
@@ -105,6 +130,8 @@ module DB
|
|
|
105
130
|
return results
|
|
106
131
|
end
|
|
107
132
|
|
|
133
|
+
# Convert the entire result set to an array.
|
|
134
|
+
# @returns [Array(Array)] All rows as arrays.
|
|
108
135
|
def to_a
|
|
109
136
|
rows = []
|
|
110
137
|
|
|
@@ -1,49 +1,70 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require
|
|
7
|
-
require
|
|
6
|
+
require "json"
|
|
7
|
+
require "bigdecimal"
|
|
8
8
|
|
|
9
9
|
module DB
|
|
10
10
|
module MariaDB
|
|
11
11
|
module Native
|
|
12
|
+
# Provides type converters for translating between MariaDB types and Ruby types.
|
|
12
13
|
module Types
|
|
14
|
+
# A text/string type converter.
|
|
13
15
|
class Text
|
|
16
|
+
# Initialize a text type converter.
|
|
17
|
+
# @parameter name [String] The SQL type name.
|
|
14
18
|
def initialize(name = "TEXT")
|
|
15
19
|
@name = name
|
|
16
20
|
end
|
|
17
21
|
|
|
22
|
+
# @attribute [String] The SQL type name.
|
|
18
23
|
attr :name
|
|
19
24
|
|
|
25
|
+
# Parse a string value from the database.
|
|
26
|
+
# @parameter string [String | Nil] The raw string value.
|
|
27
|
+
# @returns [String | Nil] The string value.
|
|
20
28
|
def parse(string)
|
|
21
29
|
string
|
|
22
30
|
end
|
|
23
31
|
end
|
|
24
32
|
|
|
33
|
+
# An integer type converter.
|
|
25
34
|
class Integer
|
|
35
|
+
# Initialize an integer type converter.
|
|
36
|
+
# @parameter name [String] The SQL type name.
|
|
26
37
|
def initialize(name = "INTEGER")
|
|
27
38
|
@name = name
|
|
28
39
|
end
|
|
29
40
|
|
|
41
|
+
# @attribute [String] The SQL type name.
|
|
30
42
|
attr :name
|
|
31
43
|
|
|
44
|
+
# Parse an integer value from the database.
|
|
45
|
+
# @parameter string [String | Nil] The raw string value.
|
|
46
|
+
# @returns [Integer | Nil] The parsed integer.
|
|
32
47
|
def parse(string)
|
|
33
48
|
Integer(string) if string
|
|
34
49
|
end
|
|
35
50
|
end
|
|
36
51
|
|
|
52
|
+
# A boolean type converter.
|
|
37
53
|
class Boolean
|
|
54
|
+
# Get the SQL type name for boolean.
|
|
55
|
+
# @returns [String] The type name.
|
|
38
56
|
def name
|
|
39
57
|
"BOOLEAN"
|
|
40
58
|
end
|
|
41
59
|
|
|
60
|
+
# Parse a boolean value from the database.
|
|
61
|
+
# @parameter string [String | Nil] The raw string value.
|
|
62
|
+
# @returns [Boolean | Integer | Nil] The parsed boolean value.
|
|
42
63
|
def parse(string)
|
|
43
64
|
case string
|
|
44
|
-
when
|
|
65
|
+
when "0"
|
|
45
66
|
false
|
|
46
|
-
when
|
|
67
|
+
when "1"
|
|
47
68
|
true
|
|
48
69
|
when nil
|
|
49
70
|
nil
|
|
@@ -53,45 +74,71 @@ module DB
|
|
|
53
74
|
end
|
|
54
75
|
end
|
|
55
76
|
|
|
77
|
+
# A decimal type converter.
|
|
56
78
|
class Decimal
|
|
79
|
+
# Get the SQL type name for decimal.
|
|
80
|
+
# @returns [String] The type name.
|
|
57
81
|
def name
|
|
58
82
|
"DECIMAL"
|
|
59
83
|
end
|
|
60
84
|
|
|
85
|
+
# Parse a decimal value from the database.
|
|
86
|
+
# @parameter string [String | Nil] The raw string value.
|
|
87
|
+
# @returns [BigDecimal | Nil] The parsed decimal.
|
|
61
88
|
def parse(string)
|
|
62
89
|
BigDecimal(string) if string
|
|
63
90
|
end
|
|
64
91
|
end
|
|
65
92
|
|
|
93
|
+
# A floating point type converter.
|
|
66
94
|
class Float
|
|
95
|
+
# Initialize a float type converter.
|
|
96
|
+
# @parameter name [String] The SQL type name.
|
|
67
97
|
def initialize(name = "FLOAT")
|
|
68
98
|
@name = name
|
|
69
99
|
end
|
|
70
100
|
|
|
101
|
+
# @attribute [String] The SQL type name.
|
|
71
102
|
attr :name
|
|
72
103
|
|
|
104
|
+
# Parse a float value from the database.
|
|
105
|
+
# @parameter string [String | Nil] The raw string value.
|
|
106
|
+
# @returns [Float | Nil] The parsed float.
|
|
73
107
|
def parse(string)
|
|
74
108
|
Float(string) if string
|
|
75
109
|
end
|
|
76
110
|
end
|
|
77
111
|
|
|
112
|
+
# A symbol/enum type converter.
|
|
78
113
|
class Symbol
|
|
114
|
+
# Get the SQL type name for enum.
|
|
115
|
+
# @returns [String] The type name.
|
|
79
116
|
def name
|
|
80
117
|
"ENUM"
|
|
81
118
|
end
|
|
82
119
|
|
|
120
|
+
# Parse a symbol value from the database.
|
|
121
|
+
# @parameter string [String | Nil] The raw string value.
|
|
122
|
+
# @returns [Symbol | Nil] The parsed symbol.
|
|
83
123
|
def parse(string)
|
|
84
124
|
string&.to_sym
|
|
85
125
|
end
|
|
86
126
|
end
|
|
87
127
|
|
|
128
|
+
# A datetime type converter.
|
|
88
129
|
class DateTime
|
|
130
|
+
# Initialize a datetime type converter.
|
|
131
|
+
# @parameter name [String] The SQL type name.
|
|
89
132
|
def initialize(name = "DATETIME")
|
|
90
133
|
@name = name
|
|
91
134
|
end
|
|
92
135
|
|
|
136
|
+
# @attribute [String] The SQL type name.
|
|
93
137
|
attr :name
|
|
94
138
|
|
|
139
|
+
# Parse a datetime value from the database.
|
|
140
|
+
# @parameter string [String | Nil] The raw string value.
|
|
141
|
+
# @returns [Time | Nil] The parsed datetime as a UTC Time object.
|
|
95
142
|
def parse(string)
|
|
96
143
|
if string
|
|
97
144
|
parts = string.split(/[\-\s:]/)
|
|
@@ -101,11 +148,17 @@ module DB
|
|
|
101
148
|
end
|
|
102
149
|
end
|
|
103
150
|
|
|
151
|
+
# A date type converter.
|
|
104
152
|
class Date
|
|
153
|
+
# Get the SQL type name for date.
|
|
154
|
+
# @returns [String] The type name.
|
|
105
155
|
def name
|
|
106
156
|
"DATE"
|
|
107
157
|
end
|
|
108
158
|
|
|
159
|
+
# Parse a date value from the database.
|
|
160
|
+
# @parameter string [String | Nil] The raw string value.
|
|
161
|
+
# @returns [Time | Nil] The parsed date as a UTC Time object.
|
|
109
162
|
def parse(string)
|
|
110
163
|
if string
|
|
111
164
|
parts = string.split(/[\-\s:]/)
|
|
@@ -115,11 +168,17 @@ module DB
|
|
|
115
168
|
end
|
|
116
169
|
end
|
|
117
170
|
|
|
171
|
+
# A JSON type converter.
|
|
118
172
|
class JSON
|
|
173
|
+
# Get the SQL type name for JSON.
|
|
174
|
+
# @returns [String] The type name.
|
|
119
175
|
def name
|
|
120
176
|
"JSON"
|
|
121
177
|
end
|
|
122
178
|
|
|
179
|
+
# Parse a JSON value from the database.
|
|
180
|
+
# @parameter string [String | Nil] The raw string value.
|
|
181
|
+
# @returns [Hash | Array | Nil] The parsed JSON with symbolized keys.
|
|
123
182
|
def parse(string)
|
|
124
183
|
::JSON.parse(string, symbolize_names: true) if string
|
|
125
184
|
end
|
data/lib/db/mariadb/native.rb
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require
|
|
7
|
-
require
|
|
6
|
+
require "ffi/native"
|
|
7
|
+
require "ffi/native/config_tool"
|
|
8
8
|
|
|
9
9
|
module DB
|
|
10
10
|
module MariaDB
|
|
11
|
+
# Provides FFI bindings to the native MariaDB/MySQL client library.
|
|
11
12
|
module Native
|
|
12
|
-
extend FFI::
|
|
13
|
-
extend FFI::
|
|
14
|
-
extend FFI::
|
|
13
|
+
extend FFI::Native::Library
|
|
14
|
+
extend FFI::Native::Loader
|
|
15
|
+
extend FFI::Native::ConfigTool
|
|
15
16
|
|
|
16
|
-
ffi_load(
|
|
17
|
+
ffi_load("mariadb") ||
|
|
17
18
|
ffi_load_using_config_tool(%w{mariadb_config --libs}) ||
|
|
18
19
|
ffi_load_using_config_tool(%w{mysql_config --libs}) ||
|
|
19
20
|
ffi_load_failure(<<~EOF)
|
data/lib/db/mariadb/version.rb
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
+
# @namespace
|
|
6
7
|
module DB
|
|
8
|
+
# @namespace
|
|
7
9
|
module MariaDB
|
|
8
|
-
VERSION = "0.
|
|
10
|
+
VERSION = "0.13.0"
|
|
9
11
|
end
|
|
10
12
|
end
|
data/lib/db/mariadb.rb
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require_relative
|
|
7
|
-
require_relative
|
|
6
|
+
require_relative "mariadb/native"
|
|
7
|
+
require_relative "mariadb/connection"
|
|
8
8
|
|
|
9
|
-
require_relative
|
|
9
|
+
require_relative "mariadb/adapter"
|
|
10
10
|
|
|
11
|
-
require
|
|
11
|
+
require "db/adapters"
|
|
12
12
|
DB::Adapters.register(:mariadb, DB::MariaDB::Adapter)
|
data/license.md
CHANGED
data/readme.md
CHANGED
|
@@ -10,6 +10,14 @@ Please see the [project documentation](https://socketry.github.io/db-mariadb/) f
|
|
|
10
10
|
|
|
11
11
|
- [Getting Started](https://socketry.github.io/db-mariadb/guides/getting-started/index) - This guide explains how to get started with the `db-mariadb` gem.
|
|
12
12
|
|
|
13
|
+
## Releases
|
|
14
|
+
|
|
15
|
+
Please see the [project releases](https://socketry.github.io/db-mariadb/releases/index) for all releases.
|
|
16
|
+
|
|
17
|
+
### v0.12.0
|
|
18
|
+
|
|
19
|
+
- Add support for `DB::Features`.
|
|
20
|
+
|
|
13
21
|
## Contributing
|
|
14
22
|
|
|
15
23
|
We welcome contributions to this project.
|
data/releases.md
ADDED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: db-mariadb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
8
8
|
- Hal Brodigan
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain:
|
|
12
11
|
- |
|
|
@@ -38,7 +37,7 @@ cert_chain:
|
|
|
38
37
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
|
39
38
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
|
40
39
|
-----END CERTIFICATE-----
|
|
41
|
-
date:
|
|
40
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
42
41
|
dependencies:
|
|
43
42
|
- !ruby/object:Gem::Dependency
|
|
44
43
|
name: async-pool
|
|
@@ -69,25 +68,39 @@ dependencies:
|
|
|
69
68
|
- !ruby/object:Gem::Version
|
|
70
69
|
version: '0'
|
|
71
70
|
- !ruby/object:Gem::Dependency
|
|
72
|
-
name:
|
|
71
|
+
name: db
|
|
73
72
|
requirement: !ruby/object:Gem::Requirement
|
|
74
73
|
requirements:
|
|
75
74
|
- - "~>"
|
|
76
75
|
- !ruby/object:Gem::Version
|
|
77
|
-
version: 0.
|
|
76
|
+
version: '0.14'
|
|
78
77
|
type: :runtime
|
|
79
78
|
prerelease: false
|
|
80
79
|
version_requirements: !ruby/object:Gem::Requirement
|
|
81
80
|
requirements:
|
|
82
81
|
- - "~>"
|
|
83
82
|
- !ruby/object:Gem::Version
|
|
84
|
-
version: 0.
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
version: '0.14'
|
|
84
|
+
- !ruby/object:Gem::Dependency
|
|
85
|
+
name: ffi-native
|
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - "~>"
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: 0.4.0
|
|
91
|
+
type: :runtime
|
|
92
|
+
prerelease: false
|
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - "~>"
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: 0.4.0
|
|
87
98
|
executables: []
|
|
88
99
|
extensions: []
|
|
89
100
|
extra_rdoc_files: []
|
|
90
101
|
files:
|
|
102
|
+
- context/getting-started.md
|
|
103
|
+
- context/index.yaml
|
|
91
104
|
- lib/db/mariadb.rb
|
|
92
105
|
- lib/db/mariadb/adapter.rb
|
|
93
106
|
- lib/db/mariadb/connection.rb
|
|
@@ -100,6 +113,7 @@ files:
|
|
|
100
113
|
- lib/db/mariadb/version.rb
|
|
101
114
|
- license.md
|
|
102
115
|
- readme.md
|
|
116
|
+
- releases.md
|
|
103
117
|
homepage: https://github.com/socketry/db-mariadb
|
|
104
118
|
licenses:
|
|
105
119
|
- MIT
|
|
@@ -107,7 +121,6 @@ metadata:
|
|
|
107
121
|
documentation_uri: https://socketry.github.io/db-mariadb/
|
|
108
122
|
funding_uri: https://github.com/sponsors/ioquatix
|
|
109
123
|
source_code_uri: https://github.com/socketry/db-mariadb.git
|
|
110
|
-
post_install_message:
|
|
111
124
|
rdoc_options: []
|
|
112
125
|
require_paths:
|
|
113
126
|
- lib
|
|
@@ -115,15 +128,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
115
128
|
requirements:
|
|
116
129
|
- - ">="
|
|
117
130
|
- !ruby/object:Gem::Version
|
|
118
|
-
version: '3.
|
|
131
|
+
version: '3.2'
|
|
119
132
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
133
|
requirements:
|
|
121
134
|
- - ">="
|
|
122
135
|
- !ruby/object:Gem::Version
|
|
123
136
|
version: '0'
|
|
124
137
|
requirements: []
|
|
125
|
-
rubygems_version:
|
|
126
|
-
signing_key:
|
|
138
|
+
rubygems_version: 4.0.3
|
|
127
139
|
specification_version: 4
|
|
128
140
|
summary: An event-driven interface for MariaDB and MySQL servers.
|
|
129
141
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|