wowsql-sdk 3.0.2 → 3.9.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
- data/CHANGELOG.md +20 -0
- data/LICENSE +81 -17
- data/README.md +587 -322
- data/lib/wowsql/auth.rb +2 -2
- data/lib/wowsql/client.rb +62 -58
- data/lib/wowsql/query_builder.rb +197 -226
- data/lib/wowsql/realtime.rb +201 -0
- data/lib/wowsql/schema.rb +2 -2
- data/lib/wowsql/storage.rb +2 -2
- data/lib/wowsql/table.rb +123 -110
- data/lib/wowsql/version.rb +1 -1
- data/lib/wowsql.rb +1 -0
- metadata +17 -1
data/lib/wowsql/auth.rb
CHANGED
|
@@ -91,12 +91,12 @@ module WOWSQL
|
|
|
91
91
|
|
|
92
92
|
# @param project_url [String] Project subdomain or full URL
|
|
93
93
|
# @param api_key [String] API key for authentication
|
|
94
|
-
# @param base_domain [String] Base domain (default: "
|
|
94
|
+
# @param base_domain [String] Base domain (default: "wowsqlconnect.com")
|
|
95
95
|
# @param secure [Boolean] Use HTTPS (default: true)
|
|
96
96
|
# @param timeout [Integer] Request timeout in seconds (default: 30)
|
|
97
97
|
# @param verify_ssl [Boolean] Verify SSL certificates (default: true)
|
|
98
98
|
# @param token_storage [TokenStorage, nil] Optional token storage
|
|
99
|
-
def initialize(project_url, api_key, base_domain: '
|
|
99
|
+
def initialize(project_url, api_key, base_domain: 'wowsqlconnect.com', secure: true,
|
|
100
100
|
timeout: 30, verify_ssl: true, token_storage: nil)
|
|
101
101
|
@api_key = api_key
|
|
102
102
|
@timeout = timeout
|
data/lib/wowsql/client.rb
CHANGED
|
@@ -4,104 +4,97 @@ require_relative 'exceptions'
|
|
|
4
4
|
require_relative 'table'
|
|
5
5
|
|
|
6
6
|
module WOWSQL
|
|
7
|
-
#
|
|
7
|
+
# WowSQL client for PostgREST-native database operations.
|
|
8
8
|
#
|
|
9
|
-
#
|
|
10
|
-
# Use Service Role Key or Anonymous Key for authentication.
|
|
11
|
-
#
|
|
12
|
-
# Key Types:
|
|
13
|
-
# - Service Role Key: Full access to all database operations (server-side)
|
|
14
|
-
# - Anonymous Key: Public access with limited permissions (client-side)
|
|
9
|
+
# All requests are sent directly to the PostgREST endpoint (/rest/v1).
|
|
15
10
|
#
|
|
16
11
|
# @example
|
|
17
|
-
# client = WOWSQL::WOWSQLClient.new(
|
|
18
|
-
#
|
|
19
|
-
# "wowbase_service_..."
|
|
20
|
-
# )
|
|
21
|
-
# users = client.table("users").get
|
|
12
|
+
# client = WOWSQL::WOWSQLClient.new("myproject", "wowsql_anon_...")
|
|
13
|
+
# result = client.table("users").get
|
|
22
14
|
class WOWSQLClient
|
|
23
|
-
attr_reader :api_url, :api_key, :timeout, :verify_ssl
|
|
15
|
+
attr_reader :api_url, :api_key, :timeout, :verify_ssl, :last_content_range
|
|
24
16
|
|
|
25
|
-
# @param project_url [String]
|
|
26
|
-
# @param api_key
|
|
27
|
-
# @param base_domain [String]
|
|
28
|
-
# @param secure
|
|
29
|
-
# @param timeout
|
|
30
|
-
# @param verify_ssl
|
|
31
|
-
def initialize(project_url, api_key,
|
|
32
|
-
|
|
33
|
-
|
|
17
|
+
# @param project_url [String] Project slug, domain, or full URL
|
|
18
|
+
# @param api_key [String] Anonymous or service role key
|
|
19
|
+
# @param base_domain [String] Base domain appended when project_url is a slug (default: wowsqlconnect.com)
|
|
20
|
+
# @param secure [Boolean] Use HTTPS (default: true)
|
|
21
|
+
# @param timeout [Integer] Request timeout in seconds (default: 30)
|
|
22
|
+
# @param verify_ssl [Boolean] Verify SSL certificates (default: true)
|
|
23
|
+
def initialize(project_url, api_key,
|
|
24
|
+
base_domain: 'wowsqlconnect.com',
|
|
25
|
+
secure: true,
|
|
26
|
+
timeout: 30,
|
|
27
|
+
verify_ssl: true)
|
|
28
|
+
@api_key = api_key
|
|
29
|
+
@timeout = timeout
|
|
34
30
|
@verify_ssl = verify_ssl
|
|
31
|
+
@last_content_range = nil
|
|
35
32
|
|
|
36
|
-
if project_url.start_with?('http://'
|
|
37
|
-
|
|
38
|
-
if
|
|
39
|
-
|
|
40
|
-
@api_url = "#{base_url}/api/v2"
|
|
41
|
-
else
|
|
42
|
-
@api_url = "#{base_url}/api/v2"
|
|
43
|
-
end
|
|
33
|
+
if project_url.start_with?('http://', 'https://')
|
|
34
|
+
base = project_url.chomp('/')
|
|
35
|
+
base = base.split('/api').first if base.include?('/api')
|
|
36
|
+
@base_url = base
|
|
44
37
|
else
|
|
45
38
|
protocol = secure ? 'https' : 'http'
|
|
46
39
|
if project_url.include?(".#{base_domain}") || project_url.end_with?(base_domain)
|
|
47
|
-
@
|
|
40
|
+
@base_url = "#{protocol}://#{project_url}"
|
|
48
41
|
else
|
|
49
|
-
@
|
|
42
|
+
@base_url = "#{protocol}://#{project_url}.#{base_domain}"
|
|
50
43
|
end
|
|
51
44
|
end
|
|
52
45
|
|
|
46
|
+
@api_url = "#{@base_url}/rest/v1"
|
|
47
|
+
|
|
53
48
|
ssl_options = verify_ssl ? {} : { verify: false }
|
|
54
49
|
|
|
55
50
|
@conn = Faraday.new(url: @api_url, ssl: ssl_options) do |f|
|
|
56
|
-
f.request
|
|
51
|
+
f.request :json
|
|
57
52
|
f.response :json
|
|
58
|
-
f.adapter
|
|
53
|
+
f.adapter Faraday.default_adapter
|
|
59
54
|
f.options.timeout = timeout
|
|
60
55
|
end
|
|
61
56
|
|
|
62
|
-
@conn.headers['
|
|
57
|
+
@conn.headers['apikey'] = api_key
|
|
63
58
|
@conn.headers['Content-Type'] = 'application/json'
|
|
64
59
|
end
|
|
65
60
|
|
|
66
|
-
#
|
|
61
|
+
# Return a Table interface for the given table name.
|
|
67
62
|
#
|
|
68
|
-
# @param table_name [String]
|
|
69
|
-
# @return [Table]
|
|
63
|
+
# @param table_name [String]
|
|
64
|
+
# @return [Table]
|
|
70
65
|
def table(table_name)
|
|
71
66
|
Table.new(self, table_name)
|
|
72
67
|
end
|
|
73
68
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
# @return [Array<String>] List of table names
|
|
77
|
-
def list_tables
|
|
78
|
-
response = request('GET', '/tables', nil, nil)
|
|
79
|
-
response['tables'] || []
|
|
69
|
+
def realtime
|
|
70
|
+
@realtime ||= WowSQLRealtime.new(@base_url, @api_key)
|
|
80
71
|
end
|
|
81
72
|
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
# @param table_name [String] Name of the table
|
|
85
|
-
# @return [Hash] Table schema with columns and primary key
|
|
86
|
-
def get_table_schema(table_name)
|
|
87
|
-
request('GET', "/tables/#{table_name}/schema", nil, nil)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Close the HTTP connection.
|
|
73
|
+
# Close the HTTP connection (no-op, provided for API parity).
|
|
91
74
|
def close
|
|
92
75
|
@conn.close if @conn.respond_to?(:close)
|
|
93
76
|
end
|
|
94
77
|
|
|
95
|
-
# Make HTTP request to
|
|
96
|
-
|
|
78
|
+
# Make an HTTP request to the PostgREST endpoint.
|
|
79
|
+
#
|
|
80
|
+
# @param method [String] HTTP method
|
|
81
|
+
# @param path [String] Path (relative to /rest/v1)
|
|
82
|
+
# @param params [Hash, nil] Query parameters
|
|
83
|
+
# @param json [Hash, nil] Request body
|
|
84
|
+
# @param headers [Hash, nil] Additional headers (e.g. Prefer, on-conflict)
|
|
85
|
+
# @return [Array, Hash, nil]
|
|
86
|
+
def request(method, path, params = nil, json = nil, headers = nil)
|
|
97
87
|
response = @conn.public_send(method.downcase, path) do |req|
|
|
98
|
-
req.params
|
|
99
|
-
req.body
|
|
88
|
+
req.params = params if params
|
|
89
|
+
req.body = json if json
|
|
90
|
+
req.headers = req.headers.merge(headers) if headers
|
|
100
91
|
end
|
|
101
92
|
|
|
93
|
+
@last_content_range = response.headers['content-range']
|
|
94
|
+
|
|
102
95
|
if response.status >= 400
|
|
103
96
|
error_data = response.body.is_a?(Hash) ? response.body : {}
|
|
104
|
-
error_msg
|
|
97
|
+
error_msg = error_data['message'] || error_data['detail'] || "Request failed with status #{response.status}"
|
|
105
98
|
raise WOWSQLError.new(error_msg, response.status, error_data)
|
|
106
99
|
end
|
|
107
100
|
|
|
@@ -109,5 +102,16 @@ module WOWSQL
|
|
|
109
102
|
rescue Faraday::Error => e
|
|
110
103
|
raise WOWSQLError.new("Request failed: #{e.message}")
|
|
111
104
|
end
|
|
105
|
+
|
|
106
|
+
# Parse total count from a Content-Range header value.
|
|
107
|
+
#
|
|
108
|
+
# @param header [String, nil] e.g. "0-19/100"
|
|
109
|
+
# @param fallback [Integer]
|
|
110
|
+
# @return [Integer]
|
|
111
|
+
def self.parse_total_from_content_range(header, fallback)
|
|
112
|
+
return fallback unless header&.include?('/')
|
|
113
|
+
val = header.split('/').last.to_i
|
|
114
|
+
val > 0 ? val : fallback
|
|
115
|
+
end
|
|
112
116
|
end
|
|
113
117
|
end
|