wowsql-sdk 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2f513a4e3b2200161273f4f070b4a03f7ffc87406110a0f4d6b8236bfb46daf3
4
+ data.tar.gz: 2a5a47b0f6c8702ee2312ce42874d8c81af88a6b2e50573850081bb469959318
5
+ SHA512:
6
+ metadata.gz: 896e5564f6ee97da1868b69149de1c43781fdeef20e893db433b4c96f026613d4687567d58aaececdd5f4f5a2af63914781f819e1d2ef04c33485628f21fe28f
7
+ data.tar.gz: 3bda8034b18ace12708ee009d67b940773e893fcffb11884ce6afb24fa563ddee8bff6075d95ad93fbe84cf88be488e1c3af0b86618edfa30d60ba844ba0e40a
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 WowSQL
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,554 @@
1
+ # 🚀 WOWSQL Ruby SDK
2
+
3
+ Official Ruby client for [WOWSQL](https://wowsql.com) - MySQL Backend-as-a-Service with S3 Storage.
4
+
5
+ [![Gem Version](https://img.shields.io/gem/v/wowsql-sdk.svg)](https://rubygems.org/gems/wowsql-sdk)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## ✨ Features
9
+
10
+ ### Database Features
11
+ - 🗄️ Full CRUD operations (Create, Read, Update, Delete)
12
+ - 🔍 Advanced filtering (eq, neq, gt, gte, lt, lte, like, is_null)
13
+ - 📄 Pagination (limit, offset)
14
+ - 📊 Sorting (order_by)
15
+ - 🎯 Fluent query builder API
16
+ - 📝 Raw SQL queries (read-only)
17
+ - 📋 Table schema introspection
18
+ - 🔒 Built-in error handling
19
+
20
+ ### Storage Features
21
+ - 📦 S3-compatible storage client
22
+ - ⬆️ File upload with automatic quota validation
23
+ - ⬇️ File download (presigned URLs)
24
+ - 📂 File listing with metadata
25
+ - 🗑️ File deletion
26
+ - 📊 Storage quota management
27
+ - 🌍 Multi-region support
28
+
29
+ ## 📦 Installation
30
+
31
+ ### Gemfile
32
+
33
+ ```ruby
34
+ gem 'wowsql-sdk', '~> 1.0'
35
+ ```
36
+
37
+ Then run:
38
+
39
+ ```bash
40
+ bundle install
41
+ ```
42
+
43
+ ### Manual Installation
44
+
45
+ ```bash
46
+ gem install wowsql-sdk
47
+ ```
48
+
49
+ ## 🚀 Quick Start
50
+
51
+ ### Database Operations
52
+
53
+ ```ruby
54
+ require 'wowsql'
55
+
56
+ # Initialize client
57
+ client = WOWSQL::WOWSQLClient.new(
58
+ 'https://your-project.wowsql.com',
59
+ 'your-api-key' # Get from dashboard
60
+ )
61
+
62
+ # Select data
63
+ response = client.table('users')
64
+ .select('id', 'name', 'email')
65
+ .eq('status', 'active')
66
+ .limit(10)
67
+ .get
68
+
69
+ response['data'].each do |user|
70
+ puts "#{user['name']} (#{user['email']})"
71
+ end
72
+
73
+ # Insert data
74
+ new_user = {
75
+ 'name' => 'Jane Doe',
76
+ 'email' => 'jane@example.com',
77
+ 'age' => 25
78
+ }
79
+
80
+ result = client.table('users').create(new_user)
81
+ puts "Created user with ID: #{result['id']}"
82
+
83
+ # Update data
84
+ updates = { 'name' => 'Jane Smith' }
85
+ client.table('users').update(result['id'], updates)
86
+
87
+ # Delete data
88
+ client.table('users').delete(result['id'])
89
+ ```
90
+
91
+ ### Storage Operations
92
+
93
+ ```ruby
94
+ require 'wowsql'
95
+
96
+ # Initialize storage client
97
+ storage = WOWSQL::WOWSQLStorage.new(
98
+ 'your-project-slug',
99
+ 'your-api-key'
100
+ )
101
+
102
+ # Upload file
103
+ storage.upload_from_path('local-file.pdf', 'uploads/document.pdf', 'documents')
104
+
105
+ # Get presigned URL
106
+ url_data = storage.get_file_url('uploads/document.pdf', 3600)
107
+ puts "File URL: #{url_data['file_url']}"
108
+
109
+ # List files
110
+ files = storage.list_files('uploads/')
111
+ files.each do |file|
112
+ puts "#{file['key']}: #{(file['size'] / 1024.0 / 1024.0).round(2)} MB"
113
+ end
114
+
115
+ # Delete file
116
+ storage.delete_file('uploads/document.pdf')
117
+
118
+ # Check storage quota
119
+ quota = storage.get_quota
120
+ puts "Used: #{quota['used_gb']} GB"
121
+ puts "Available: #{quota['available_gb']} GB"
122
+ ```
123
+
124
+ ## 📚 Usage Examples
125
+
126
+ ### Select Queries
127
+
128
+ ```ruby
129
+ # Select all columns
130
+ users = client.table('users').select('*').get
131
+
132
+ # Select specific columns
133
+ users = client.table('users')
134
+ .select('id', 'name', 'email')
135
+ .get
136
+
137
+ # With filters
138
+ active_users = client.table('users')
139
+ .select('id', 'name', 'email')
140
+ .eq('status', 'active')
141
+ .gt('age', 18)
142
+ .get
143
+
144
+ # With ordering
145
+ recent_users = client.table('users')
146
+ .select('*')
147
+ .order_by('created_at', desc: true)
148
+ .limit(10)
149
+ .get
150
+
151
+ # With pagination
152
+ page1 = client.table('users')
153
+ .select('*')
154
+ .limit(20)
155
+ .offset(0)
156
+ .get
157
+
158
+ page2 = client.table('users')
159
+ .select('*')
160
+ .limit(20)
161
+ .offset(20)
162
+ .get
163
+
164
+ # Pattern matching
165
+ gmail_users = client.table('users')
166
+ .select('*')
167
+ .like('email', '%@gmail.com')
168
+ .get
169
+
170
+ # Get single record by ID
171
+ user = client.table('users').get_by_id(123)
172
+ ```
173
+
174
+ ### Insert Data
175
+
176
+ ```ruby
177
+ # Insert single record
178
+ new_user = {
179
+ 'name' => 'John Doe',
180
+ 'email' => 'john@example.com',
181
+ 'age' => 30,
182
+ 'status' => 'active'
183
+ }
184
+
185
+ result = client.table('users').create(new_user)
186
+ puts "New user ID: #{result['id']}"
187
+ ```
188
+
189
+ ### Update Data
190
+
191
+ ```ruby
192
+ # Update by ID
193
+ updates = {
194
+ 'name' => 'Jane Smith',
195
+ 'age' => 26
196
+ }
197
+
198
+ result = client.table('users').update(1, updates)
199
+ puts "Updated #{result['affected_rows']} row(s)"
200
+ ```
201
+
202
+ ### Delete Data
203
+
204
+ ```ruby
205
+ # Delete by ID
206
+ result = client.table('users').delete(1)
207
+ puts "Deleted #{result['affected_rows']} row(s)"
208
+
209
+ # Delete with conditions
210
+ deleted = client.table('users')
211
+ .eq('status', 'deleted')
212
+ .delete
213
+ ```
214
+
215
+ ### Filter Operators
216
+
217
+ ```ruby
218
+ # Equal
219
+ .eq('status', 'active')
220
+
221
+ # Not equal
222
+ .neq('status', 'deleted')
223
+
224
+ # Greater than
225
+ .gt('age', 18)
226
+
227
+ # Greater than or equal
228
+ .gte('age', 18)
229
+
230
+ # Less than
231
+ .lt('age', 65)
232
+
233
+ # Less than or equal
234
+ .lte('age', 65)
235
+
236
+ # Pattern matching (SQL LIKE)
237
+ .like('email', '%@gmail.com')
238
+
239
+ # Is null
240
+ .is_null('deleted_at')
241
+
242
+ # Is not null
243
+ .is_not_null('email')
244
+ ```
245
+
246
+ ### Advanced Queries
247
+
248
+ ```ruby
249
+ # Multiple filters with sorting
250
+ active_users = client.table('users')
251
+ .select('id', 'name', 'email')
252
+ .eq('status', 'active')
253
+ .gt('age', 18)
254
+ .order_by('created_at', desc: true)
255
+ .limit(20)
256
+ .get
257
+
258
+ # Complex filtering
259
+ results = client.table('products')
260
+ .select('*')
261
+ .gt('price', 100)
262
+ .lt('price', 1000)
263
+ .like('name', '%widget%')
264
+ .is_not_null('category')
265
+ .order_by('price', desc: false) # asc
266
+ .limit(50)
267
+ .offset(0)
268
+ .get
269
+ ```
270
+
271
+ ### Storage Operations
272
+
273
+ ```ruby
274
+ storage = WOWSQL::WOWSQLStorage.new(
275
+ 'your-project-slug',
276
+ 'your-api-key'
277
+ )
278
+
279
+ # Upload file from local path
280
+ storage.upload_from_path(
281
+ 'local-file.pdf',
282
+ 'uploads/document.pdf',
283
+ 'documents' # bucket/folder
284
+ )
285
+
286
+ # Check if file exists
287
+ if storage.file_exists?('uploads/document.pdf')
288
+ puts "File exists!"
289
+ end
290
+
291
+ # Get file information
292
+ info = storage.get_file_info('uploads/document.pdf')
293
+ puts "Size: #{info['size']} bytes"
294
+ puts "Modified: #{info['last_modified']}"
295
+
296
+ # List files with prefix
297
+ files = storage.list_files('uploads/2024/')
298
+ files.each do |file|
299
+ puts "#{file['key']}: #{file['size']} bytes"
300
+ end
301
+
302
+ # Download file (get presigned URL)
303
+ url_data = storage.get_file_url('uploads/document.pdf', 3600)
304
+ puts "Download URL: #{url_data['file_url']}"
305
+ # URL is valid for 1 hour (3600 seconds)
306
+
307
+ # Delete single file
308
+ storage.delete_file('uploads/old-file.pdf')
309
+
310
+ # Delete multiple files
311
+ storage.delete_files([
312
+ 'uploads/file1.pdf',
313
+ 'uploads/file2.pdf',
314
+ 'uploads/file3.pdf'
315
+ ])
316
+
317
+ # Check quota
318
+ quota = storage.get_quota
319
+ puts "Used: #{quota['used_gb'].round(2)} GB"
320
+ puts "Available: #{quota['available_gb'].round(2)} GB"
321
+ puts "Usage: #{quota['usage_percentage'].round(1)}%"
322
+
323
+ # Check if enough storage before upload
324
+ file_size = File.size('large-file.zip')
325
+ if quota['available_bytes'] < file_size
326
+ puts "Not enough storage!"
327
+ else
328
+ storage.upload_from_path('large-file.zip', 'uploads/large-file.zip')
329
+ end
330
+ ```
331
+
332
+ ### Error Handling
333
+
334
+ ```ruby
335
+ begin
336
+ users = client.table('users').select('*').get
337
+ puts "Success: #{users['data'].count} users"
338
+ rescue WOWSQL::AuthenticationException => e
339
+ puts "Authentication error: #{e.message}"
340
+ rescue WOWSQL::NotFoundException => e
341
+ puts "Not found: #{e.message}"
342
+ rescue WOWSQL::RateLimitException => e
343
+ puts "Rate limit exceeded: #{e.message}"
344
+ rescue WOWSQL::WOWSQLException => e
345
+ puts "Database error (#{e.status_code}): #{e.message}"
346
+ end
347
+
348
+ begin
349
+ storage.upload_from_path('file.pdf', 'uploads/file.pdf')
350
+ rescue WOWSQL::StorageLimitExceededException => e
351
+ puts "Storage full: #{e.message}"
352
+ puts "Please upgrade your plan or delete old files"
353
+ rescue WOWSQL::StorageException => e
354
+ puts "Storage error: #{e.message}"
355
+ end
356
+ ```
357
+
358
+ ### Utility Methods
359
+
360
+ ```ruby
361
+ # List all tables
362
+ tables = client.list_tables
363
+ puts "Tables: #{tables.inspect}"
364
+
365
+ # Get table schema
366
+ schema = client.get_table_schema('users')
367
+ puts "Columns: #{schema['columns'].count}"
368
+ schema['columns'].each do |column|
369
+ puts " - #{column['name']} (#{column['type']})"
370
+ end
371
+
372
+ # Check API health
373
+ health = client.health
374
+ puts "Status: #{health['status']}"
375
+ ```
376
+
377
+ ## 🔧 Configuration
378
+
379
+ ### Custom Timeout
380
+
381
+ ```ruby
382
+ # Database client
383
+ client = WOWSQL::WOWSQLClient.new(
384
+ 'https://your-project.wowsql.com',
385
+ 'your-api-key',
386
+ 60 # 60 seconds timeout
387
+ )
388
+
389
+ # Storage client
390
+ storage = WOWSQL::WOWSQLStorage.new(
391
+ 'your-project-slug',
392
+ 'your-api-key',
393
+ 120 # 2 minutes for large files
394
+ )
395
+ ```
396
+
397
+ ### Using Environment Variables
398
+
399
+ ```ruby
400
+ # Best practice: Use environment variables for API keys
401
+ client = WOWSQL::WOWSQLClient.new(
402
+ ENV['WOWSQL_PROJECT_URL'],
403
+ ENV['WOWSQL_API_KEY']
404
+ )
405
+
406
+ storage = WOWSQL::WOWSQLStorage.new(
407
+ ENV['WOWSQL_PROJECT_URL'],
408
+ ENV['WOWSQL_API_KEY']
409
+ )
410
+ ```
411
+
412
+ ## 🔑 API Keys
413
+
414
+ WOWSQL uses **different API keys for different operations**. Understanding which key to use is crucial for proper authentication.
415
+
416
+ ### Key Types Overview
417
+
418
+ | Operation Type | Recommended Key | Alternative Key | Used By |
419
+ |---------------|----------------|-----------------|---------|
420
+ | **Database Operations** (CRUD) | Service Role Key (`wowbase_service_...`) | Anonymous Key (`wowbase_anon_...`) | `WOWSQLClient` |
421
+ | **Storage Operations** | Service Role Key (`wowbase_service_...`) | Anonymous Key (`wowbase_anon_...`) | `WOWSQLStorage` |
422
+
423
+ ### Where to Find Your Keys
424
+
425
+ All keys are found in: **WOWSQL Dashboard → Authentication → PROJECT KEYS**
426
+
427
+ 1. **Service Role Key** (`wowbase_service_...`)
428
+ - Location: "Service Role Key (keep secret)"
429
+ - Used for: Database CRUD operations and storage (recommended for server-side)
430
+ - **Important**: Click the eye icon to reveal this key
431
+
432
+ 2. **Anonymous Key** (`wowbase_anon_...`)
433
+ - Location: "Anonymous Key"
434
+ - Used for: Public/client-side database operations with limited permissions
435
+ - Optional: Use when exposing database access to frontend/client
436
+
437
+ ### Database Operations
438
+
439
+ Use **Service Role Key** or **Anonymous Key** for database operations:
440
+
441
+ ```ruby
442
+ # Using Service Role Key (recommended for server-side, full access)
443
+ client = WOWSQL::WOWSQLClient.new(
444
+ 'https://your-project.wowsql.com',
445
+ 'wowbase_service_your-service-key-here' # Service Role Key
446
+ )
447
+
448
+ # Using Anonymous Key (for public/client-side access with limited permissions)
449
+ client = WOWSQL::WOWSQLClient.new(
450
+ 'https://your-project.wowsql.com',
451
+ 'wowbase_anon_your-anon-key-here' # Anonymous Key
452
+ )
453
+
454
+ # Query data
455
+ users = client.table('users').get
456
+ ```
457
+
458
+ ### Security Best Practices
459
+
460
+ 1. **Never expose Service Role Key** in client-side code or public repositories
461
+ 2. **Use Anonymous Key** for public database access with limited permissions
462
+ 3. **Store keys in environment variables**, never hardcode them
463
+ 4. **Rotate keys regularly** if compromised
464
+
465
+ ## 🎨 Framework Integration
466
+
467
+ ### Rails
468
+
469
+ ```ruby
470
+ # config/initializers/wowsql.rb
471
+ WOWSQL_CLIENT = WOWSQL::WOWSQLClient.new(
472
+ Rails.application.credentials.wowsql[:project_url],
473
+ Rails.application.credentials.wowsql[:api_key]
474
+ )
475
+
476
+ # app/models/user.rb
477
+ class User < ApplicationRecord
478
+ def self.sync_from_wowsql
479
+ response = WOWSQL_CLIENT.table('users')
480
+ .select('*')
481
+ .get
482
+
483
+ response['data'].each do |user_data|
484
+ User.find_or_create_by(external_id: user_data['id']) do |user|
485
+ user.name = user_data['name']
486
+ user.email = user_data['email']
487
+ end
488
+ end
489
+ end
490
+ end
491
+
492
+ # Usage in Controller
493
+ class UsersController < ApplicationController
494
+ def index
495
+ @users = WOWSQL_CLIENT.table('users')
496
+ .select('id', 'name', 'email')
497
+ .get['data']
498
+ end
499
+ end
500
+ ```
501
+
502
+ ### Sinatra
503
+
504
+ ```ruby
505
+ require 'sinatra'
506
+ require 'wowsql'
507
+
508
+ configure do
509
+ set :wowsql_client, WOWSQL::WOWSQLClient.new(
510
+ ENV['WOWSQL_PROJECT_URL'],
511
+ ENV['WOWSQL_API_KEY']
512
+ )
513
+ end
514
+
515
+ get '/users' do
516
+ users = settings.wowsql_client.table('users')
517
+ .select('id', 'name', 'email')
518
+ .get['data']
519
+
520
+ content_type :json
521
+ users.to_json
522
+ end
523
+ ```
524
+
525
+ ## 📋 Requirements
526
+
527
+ - Ruby 2.6.0 or higher
528
+ - Faraday 2.0+
529
+ - JSON 2.0+
530
+
531
+ ## 🔗 Links
532
+
533
+ - 📚 [Documentation](https://wowsql.com/docs)
534
+ - 🌐 [Website](https://wowsql.com)
535
+ - 💬 [Discord](https://discord.gg/WOWSQL)
536
+ - 🐛 [Issues](https://github.com/wowsql/wowsql/issues)
537
+
538
+ ## 📄 License
539
+
540
+ MIT License - see [LICENSE](LICENSE) file for details.
541
+
542
+ ## 🤝 Contributing
543
+
544
+ Contributions are welcome! Please open an issue or submit a pull request.
545
+
546
+ ## 📞 Support
547
+
548
+ - Email: support@wowsql.com
549
+ - Discord: https://discord.gg/WOWSQL
550
+ - Documentation: https://wowsql.com/docs
551
+
552
+ ---
553
+
554
+ Made with ❤️ by the WOWSQL Team
@@ -0,0 +1,84 @@
1
+ require 'faraday'
2
+ require 'json'
3
+ require_relative 'exceptions'
4
+ require_relative 'table'
5
+
6
+ module WOWSQL
7
+ # WOWSQL client for interacting with your database via REST API.
8
+ #
9
+ # This client is used for DATABASE OPERATIONS (CRUD on tables).
10
+ # Use Service Role Key or Anonymous Key for authentication.
11
+ class WOWSQLClient
12
+ def initialize(project_url, api_key, timeout = 30)
13
+ @api_key = api_key
14
+ @timeout = timeout
15
+
16
+ # Build API URL
17
+ if project_url.start_with?('http://') || project_url.start_with?('https://')
18
+ base_url = project_url.chomp('/')
19
+ if base_url.include?('/api')
20
+ @api_url = base_url.sub('/api', '') + '/api/v2'
21
+ else
22
+ @api_url = base_url + '/api/v2'
23
+ end
24
+ else
25
+ @api_url = "https://#{project_url}.wowsql.com/api/v2"
26
+ end
27
+
28
+ @conn = Faraday.new(url: @api_url) do |f|
29
+ f.request :json
30
+ f.response :json
31
+ f.adapter Faraday.default_adapter
32
+ f.options.timeout = timeout
33
+ end
34
+
35
+ @conn.headers['Authorization'] = "Bearer #{api_key}"
36
+ @conn.headers['Content-Type'] = 'application/json'
37
+ end
38
+
39
+ # Get a table interface for fluent API.
40
+ #
41
+ # @param table_name [String] Name of the table
42
+ # @return [Table] Table instance for the specified table
43
+ def table(table_name)
44
+ Table.new(self, table_name)
45
+ end
46
+
47
+ # List all tables in the database.
48
+ #
49
+ # @return [Array<String>] List of table names
50
+ def list_tables
51
+ response = request('GET', '/tables', nil, nil)
52
+ response['tables'] || []
53
+ end
54
+
55
+ # Get table schema information.
56
+ #
57
+ # @param table_name [String] Name of the table
58
+ # @return [Hash] Table schema with columns and primary key
59
+ def get_table_schema(table_name)
60
+ request('GET', "/tables/#{table_name}/schema", nil, nil)
61
+ end
62
+
63
+ # Make HTTP request to API.
64
+ def request(method, path, params = nil, json = nil)
65
+ begin
66
+ response = @conn.public_send(method.downcase, path) do |req|
67
+ req.params = params if params
68
+ req.body = json if json
69
+ end
70
+
71
+ if response.status >= 400
72
+ error_data = response.body.is_a?(Hash) ? response.body : {}
73
+ error_msg = error_data['detail'] || error_data['message'] || "Request failed with status #{response.status}"
74
+ raise WOWSQLException.new(error_msg, response.status, error_data)
75
+ end
76
+
77
+ response.body
78
+ rescue Faraday::Error => e
79
+ raise WOWSQLException.new("Request failed: #{e.message}")
80
+ end
81
+ end
82
+ end
83
+ end
84
+
@@ -0,0 +1,31 @@
1
+ module WOWSQL
2
+ # Base exception for WOWSQL SDK errors.
3
+ class WOWSQLException < StandardError
4
+ attr_reader :status_code, :response
5
+
6
+ def initialize(message, status_code = nil, response = nil)
7
+ super(message)
8
+ @status_code = status_code
9
+ @response = response
10
+ end
11
+ end
12
+
13
+ # Storage-specific exception.
14
+ class StorageException < WOWSQLException
15
+ end
16
+
17
+ # Exception raised when storage limit would be exceeded.
18
+ class StorageLimitExceededException < StorageException
19
+ def initialize(message, response = nil)
20
+ super(message, 413, response)
21
+ end
22
+ end
23
+
24
+ # Exception raised when operation requires service role key but anonymous key was used.
25
+ class PermissionException < WOWSQLException
26
+ def initialize(message)
27
+ super(message, 403)
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,97 @@
1
+ module WOWSQL
2
+ # Fluent query builder for constructing database queries.
3
+ class QueryBuilder
4
+ def initialize(client, table_name)
5
+ @client = client
6
+ @table_name = table_name
7
+ @params = {}
8
+ end
9
+
10
+ def select(*columns)
11
+ if columns.length == 1 && columns[0] == '*'
12
+ @params['select'] = '*'
13
+ else
14
+ @params['select'] = columns.join(',')
15
+ end
16
+ self
17
+ end
18
+
19
+ def eq(column, value)
20
+ add_filter(column, 'eq', value)
21
+ self
22
+ end
23
+
24
+ def neq(column, value)
25
+ add_filter(column, 'neq', value)
26
+ self
27
+ end
28
+
29
+ def gt(column, value)
30
+ add_filter(column, 'gt', value)
31
+ self
32
+ end
33
+
34
+ def gte(column, value)
35
+ add_filter(column, 'gte', value)
36
+ self
37
+ end
38
+
39
+ def lt(column, value)
40
+ add_filter(column, 'lt', value)
41
+ self
42
+ end
43
+
44
+ def lte(column, value)
45
+ add_filter(column, 'lte', value)
46
+ self
47
+ end
48
+
49
+ def like(column, pattern)
50
+ add_filter(column, 'like', pattern)
51
+ self
52
+ end
53
+
54
+ def is_null(column)
55
+ add_filter(column, 'is', nil)
56
+ self
57
+ end
58
+
59
+ def order_by(column, desc: false)
60
+ @params['order'] = column
61
+ @params['order_direction'] = desc ? 'desc' : 'asc'
62
+ self
63
+ end
64
+
65
+ def limit(limit)
66
+ @params['limit'] = limit.to_s
67
+ self
68
+ end
69
+
70
+ def offset(offset)
71
+ @params['offset'] = offset.to_s
72
+ self
73
+ end
74
+
75
+ def get
76
+ @client.request('GET', "/#{@table_name}", @params, nil)
77
+ end
78
+
79
+ def first
80
+ result = limit(1).get
81
+ result['data']&.first
82
+ end
83
+
84
+ private
85
+
86
+ def add_filter(column, op, value)
87
+ filter_value = "#{column}.#{op}.#{value || 'null'}"
88
+
89
+ if @params['filter']
90
+ @params['filter'] += ",#{filter_value}"
91
+ else
92
+ @params['filter'] = filter_value
93
+ end
94
+ end
95
+ end
96
+ end
97
+
@@ -0,0 +1,60 @@
1
+ require_relative 'query_builder'
2
+
3
+ module WOWSQL
4
+ # Table interface for database operations.
5
+ class Table
6
+ def initialize(client, table_name)
7
+ @client = client
8
+ @table_name = table_name
9
+ end
10
+
11
+ # Start a query with column selection.
12
+ #
13
+ # @param columns [Array<String>] Column(s) to select
14
+ # @return [QueryBuilder] QueryBuilder for chaining
15
+ def select(*columns)
16
+ QueryBuilder.new(@client, @table_name).select(*columns)
17
+ end
18
+
19
+ # Get all records with optional filters.
20
+ #
21
+ # @return [Hash] Query response
22
+ def get
23
+ QueryBuilder.new(@client, @table_name).get
24
+ end
25
+
26
+ # Get a single record by ID.
27
+ #
28
+ # @param record_id [Object] Record ID
29
+ # @return [Hash] Record data
30
+ def get_by_id(record_id)
31
+ @client.request('GET', "/#{@table_name}/#{record_id}", nil, nil)
32
+ end
33
+
34
+ # Create a new record.
35
+ #
36
+ # @param data [Hash] Record data
37
+ # @return [Hash] Create response with new record ID
38
+ def create(data)
39
+ @client.request('POST', "/#{@table_name}", nil, data)
40
+ end
41
+
42
+ # Update a record by ID.
43
+ #
44
+ # @param record_id [Object] Record ID
45
+ # @param data [Hash] Data to update
46
+ # @return [Hash] Update response
47
+ def update(record_id, data)
48
+ @client.request('PATCH', "/#{@table_name}/#{record_id}", nil, data)
49
+ end
50
+
51
+ # Delete a record by ID.
52
+ #
53
+ # @param record_id [Object] Record ID
54
+ # @return [Hash] Delete response
55
+ def delete(record_id)
56
+ @client.request('DELETE', "/#{@table_name}/#{record_id}", nil, nil)
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,4 @@
1
+ module WOWSQL
2
+ VERSION = "1.0.0"
3
+ end
4
+
data/lib/wowsql.rb ADDED
@@ -0,0 +1,10 @@
1
+ require_relative 'wowsql/version'
2
+ require_relative 'wowsql/exceptions'
3
+ require_relative 'wowsql/client'
4
+ require_relative 'wowsql/table'
5
+ require_relative 'wowsql/query_builder'
6
+
7
+ module WOWSQL
8
+ # Main module for WOWSQL SDK
9
+ end
10
+
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wowsql-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - WOWSQL Team
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: json
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rspec
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rake
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '13.0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '13.0'
68
+ description: Official Ruby client library for WOWSQL - MySQL Backend-as-a-Service
69
+ with S3 Storage
70
+ email:
71
+ - support@wowsql.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - LICENSE
77
+ - README.md
78
+ - lib/wowsql.rb
79
+ - lib/wowsql/client.rb
80
+ - lib/wowsql/exceptions.rb
81
+ - lib/wowsql/query_builder.rb
82
+ - lib/wowsql/table.rb
83
+ - lib/wowsql/version.rb
84
+ homepage: https://github.com/wowsql/wowsql-sdk-ruby
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 2.6.0
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubygems_version: 3.6.9
103
+ specification_version: 4
104
+ summary: Official Ruby client library for WOWSQL - MySQL Backend-as-a-Service with
105
+ S3 Storage
106
+ test_files: []