wowsql-sdk 3.0.2 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +557 -325
- data/lib/wowsql/auth.rb +2 -2
- data/lib/wowsql/client.rb +60 -60
- data/lib/wowsql/query_builder.rb +197 -226
- data/lib/wowsql/schema.rb +2 -2
- data/lib/wowsql/storage.rb +2 -2
- data/lib/wowsql/table.rb +123 -110
- metadata +1 -1
data/lib/wowsql/table.rb
CHANGED
|
@@ -1,169 +1,182 @@
|
|
|
1
1
|
require_relative 'query_builder'
|
|
2
2
|
|
|
3
3
|
module WOWSQL
|
|
4
|
-
# Table interface for
|
|
4
|
+
# Table interface for direct PostgREST operations.
|
|
5
|
+
#
|
|
6
|
+
# All mutations use PostgREST native query parameters (?id=eq.val) and
|
|
7
|
+
# Prefer headers (return=representation, resolution=merge-duplicates).
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# user = client.table("users").get_by_id("uuid-here")
|
|
11
|
+
# result = client.table("users").create({ email: "a@b.com", name: "Alice" })
|
|
5
12
|
class Table
|
|
6
13
|
def initialize(client, table_name)
|
|
7
|
-
@client
|
|
14
|
+
@client = client
|
|
8
15
|
@table_name = table_name
|
|
9
16
|
end
|
|
10
17
|
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
# @param columns [Array<String>] Column(s) to select
|
|
14
|
-
# @return [QueryBuilder] QueryBuilder for chaining
|
|
18
|
+
# ── Query builder shortcuts ───────────────────────────────────
|
|
19
|
+
|
|
15
20
|
def select(*columns)
|
|
16
21
|
QueryBuilder.new(@client, @table_name).select(*columns)
|
|
17
22
|
end
|
|
18
23
|
|
|
19
|
-
# Start a query with a filter.
|
|
20
|
-
#
|
|
21
|
-
# @param column [String, Hash] Column name or filter hash
|
|
22
|
-
# @param operator [String, nil] Operator
|
|
23
|
-
# @param value [Object] Filter value
|
|
24
|
-
# @param logical_op [String] "AND" or "OR"
|
|
25
|
-
# @return [QueryBuilder] QueryBuilder for chaining
|
|
26
24
|
def filter(column, operator = nil, value = nil, logical_op: 'AND')
|
|
27
25
|
QueryBuilder.new(@client, @table_name).filter(column, operator, value, logical_op: logical_op)
|
|
28
26
|
end
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
def eq(column, value)
|
|
29
|
+
QueryBuilder.new(@client, @table_name).eq(column, value)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def neq(column, value)
|
|
33
|
+
QueryBuilder.new(@client, @table_name).neq(column, value)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def gt(column, value)
|
|
37
|
+
QueryBuilder.new(@client, @table_name).gt(column, value)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def gte(column, value)
|
|
41
|
+
QueryBuilder.new(@client, @table_name).gte(column, value)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def lt(column, value)
|
|
45
|
+
QueryBuilder.new(@client, @table_name).lt(column, value)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def lte(column, value)
|
|
49
|
+
QueryBuilder.new(@client, @table_name).lte(column, value)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def order_by(column, direction = 'asc')
|
|
53
|
+
QueryBuilder.new(@client, @table_name).order_by(column, direction)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def limit(n)
|
|
57
|
+
QueryBuilder.new(@client, @table_name).limit(n)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def offset(n)
|
|
61
|
+
QueryBuilder.new(@client, @table_name).offset(n)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# ── Read ─────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
# Retrieve all rows (with optional filter options forwarded to QueryBuilder#get).
|
|
31
67
|
#
|
|
32
|
-
# @param options [Hash, nil]
|
|
33
|
-
# @return [Hash]
|
|
68
|
+
# @param options [Hash, nil] Reserved for compatibility; use chained methods instead
|
|
69
|
+
# @return [Hash] { data: Array, count: Integer, total: Integer, limit: Integer, offset: Integer }
|
|
34
70
|
def get(options = nil)
|
|
35
71
|
QueryBuilder.new(@client, @table_name).get(options)
|
|
36
72
|
end
|
|
37
73
|
|
|
38
|
-
#
|
|
74
|
+
# Retrieve a single row by primary key.
|
|
39
75
|
#
|
|
40
|
-
# @param record_id [
|
|
41
|
-
# @return [Hash]
|
|
76
|
+
# @param record_id [String] Row UUID
|
|
77
|
+
# @return [Hash] Row data
|
|
42
78
|
def get_by_id(record_id)
|
|
43
|
-
@client.request(
|
|
79
|
+
result = @client.request(
|
|
80
|
+
'GET', "/#{@table_name}",
|
|
81
|
+
{ 'id' => "eq.#{record_id}" },
|
|
82
|
+
nil,
|
|
83
|
+
'Prefer' => 'return=representation'
|
|
84
|
+
)
|
|
85
|
+
data = normalise_data(result)
|
|
86
|
+
data.first
|
|
44
87
|
end
|
|
45
88
|
|
|
46
|
-
#
|
|
89
|
+
# ── Write ────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
# Insert a single row and return the created record.
|
|
47
92
|
#
|
|
48
|
-
# @param data [Hash]
|
|
49
|
-
# @return [Hash]
|
|
93
|
+
# @param data [Hash] Column→value map
|
|
94
|
+
# @return [Hash] Created row
|
|
50
95
|
def create(data)
|
|
51
|
-
@client.request(
|
|
96
|
+
result = @client.request(
|
|
97
|
+
'POST', "/#{@table_name}", nil, data,
|
|
98
|
+
'Prefer' => 'return=representation'
|
|
99
|
+
)
|
|
100
|
+
normalise_data(result).first || {}
|
|
52
101
|
end
|
|
53
102
|
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
# @param data [Hash] Record data
|
|
57
|
-
# @return [Hash] Create response with new record ID
|
|
58
|
-
def insert(data)
|
|
59
|
-
create(data)
|
|
60
|
-
end
|
|
103
|
+
alias insert create
|
|
61
104
|
|
|
62
|
-
# Insert multiple
|
|
105
|
+
# Insert multiple rows.
|
|
63
106
|
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
# @param records [Array<Hash>] List of record hashes
|
|
68
|
-
# @return [Array<Hash>] List of create responses
|
|
107
|
+
# @param records [Array<Hash>] List of row hashes
|
|
108
|
+
# @return [Array<Hash>] Created rows
|
|
69
109
|
def bulk_insert(records)
|
|
70
110
|
return [] if records.nil? || records.empty?
|
|
71
111
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
end
|
|
112
|
+
result = @client.request(
|
|
113
|
+
'POST', "/#{@table_name}", nil, records,
|
|
114
|
+
'Prefer' => 'return=representation'
|
|
115
|
+
)
|
|
116
|
+
normalise_data(result)
|
|
78
117
|
end
|
|
79
118
|
|
|
80
119
|
# Insert or update based on conflict column.
|
|
81
120
|
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
# @param data [Hash] Record data (must include the conflict column)
|
|
87
|
-
# @param on_conflict [String] Column to check for conflicts (default: "id")
|
|
88
|
-
# @return [Hash] Create or update response
|
|
121
|
+
# @param data [Hash] Row data (must include the conflict column value)
|
|
122
|
+
# @param on_conflict [String] Column to detect conflicts on (default: "id")
|
|
123
|
+
# @return [Hash] Upserted row
|
|
89
124
|
def upsert(data, on_conflict: 'id')
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if update_data.empty?
|
|
97
|
-
{ 'message' => 'No changes', 'affected_rows' => 0 }
|
|
98
|
-
else
|
|
99
|
-
update(conflict_value, update_data)
|
|
100
|
-
end
|
|
101
|
-
else
|
|
102
|
-
create(data)
|
|
103
|
-
end
|
|
125
|
+
result = @client.request(
|
|
126
|
+
'POST', "/#{@table_name}", nil, data,
|
|
127
|
+
'Prefer' => 'return=representation,resolution=merge-duplicates',
|
|
128
|
+
'on-conflict-column' => on_conflict
|
|
129
|
+
)
|
|
130
|
+
normalise_data(result).first || {}
|
|
104
131
|
end
|
|
105
132
|
|
|
106
|
-
# Update a
|
|
133
|
+
# Update a row by ID.
|
|
107
134
|
#
|
|
108
|
-
# @param record_id [
|
|
109
|
-
# @param data [Hash]
|
|
110
|
-
# @return [Hash]
|
|
135
|
+
# @param record_id [String] Row UUID
|
|
136
|
+
# @param data [Hash] Columns to update
|
|
137
|
+
# @return [Hash] Updated row
|
|
111
138
|
def update(record_id, data)
|
|
112
|
-
@client.request(
|
|
139
|
+
result = @client.request(
|
|
140
|
+
'PATCH', "/#{@table_name}",
|
|
141
|
+
{ 'id' => "eq.#{record_id}" },
|
|
142
|
+
data,
|
|
143
|
+
'Prefer' => 'return=representation'
|
|
144
|
+
)
|
|
145
|
+
normalise_data(result).first || {}
|
|
113
146
|
end
|
|
114
147
|
|
|
115
|
-
# Delete a
|
|
148
|
+
# Delete a row by ID.
|
|
116
149
|
#
|
|
117
|
-
# @param record_id [
|
|
118
|
-
# @return [Hash]
|
|
150
|
+
# @param record_id [String] Row UUID
|
|
151
|
+
# @return [Hash] Deleted row
|
|
119
152
|
def delete(record_id)
|
|
120
|
-
@client.request(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def neq(column, value)
|
|
130
|
-
QueryBuilder.new(@client, @table_name).neq(column, value)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def gt(column, value)
|
|
134
|
-
QueryBuilder.new(@client, @table_name).gt(column, value)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def gte(column, value)
|
|
138
|
-
QueryBuilder.new(@client, @table_name).gte(column, value)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def lt(column, value)
|
|
142
|
-
QueryBuilder.new(@client, @table_name).lt(column, value)
|
|
153
|
+
result = @client.request(
|
|
154
|
+
'DELETE', "/#{@table_name}",
|
|
155
|
+
{ 'id' => "eq.#{record_id}" },
|
|
156
|
+
nil,
|
|
157
|
+
'Prefer' => 'return=representation'
|
|
158
|
+
)
|
|
159
|
+
normalise_data(result).first || {}
|
|
143
160
|
end
|
|
144
161
|
|
|
145
|
-
|
|
146
|
-
QueryBuilder.new(@client, @table_name).lte(column, value)
|
|
147
|
-
end
|
|
162
|
+
# ── Aggregates / pagination ───────────────────────────────────
|
|
148
163
|
|
|
149
|
-
def order_by(column, direction = 'asc')
|
|
150
|
-
QueryBuilder.new(@client, @table_name).order_by(column, direction)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
# Get total record count for this table.
|
|
154
|
-
#
|
|
155
|
-
# @return [Integer]
|
|
156
164
|
def count
|
|
157
165
|
QueryBuilder.new(@client, @table_name).count
|
|
158
166
|
end
|
|
159
167
|
|
|
160
|
-
# Paginate all records in this table.
|
|
161
|
-
#
|
|
162
|
-
# @param page [Integer] Page number (1-indexed)
|
|
163
|
-
# @param per_page [Integer] Records per page
|
|
164
|
-
# @return [Hash]
|
|
165
168
|
def paginate(page: 1, per_page: 20)
|
|
166
169
|
QueryBuilder.new(@client, @table_name).paginate(page: page, per_page: per_page)
|
|
167
170
|
end
|
|
171
|
+
|
|
172
|
+
private
|
|
173
|
+
|
|
174
|
+
def normalise_data(result)
|
|
175
|
+
case result
|
|
176
|
+
when Array then result
|
|
177
|
+
when Hash then result['data'] || result['rows'] || (result.key?('id') ? [result] : [])
|
|
178
|
+
else []
|
|
179
|
+
end
|
|
180
|
+
end
|
|
168
181
|
end
|
|
169
182
|
end
|