model_driven_api 3.2.4 → 3.2.5
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/app/controllers/api/v2/info_controller.rb +92 -0
- data/app/controllers/api/v2/raw_controller.rb +17 -0
- data/config/routes.rb +4 -0
- data/lib/model_driven_api/version.rb +1 -1
- data/lib/model_driven_api.rb +2 -0
- data/lib/safe_sql_executor.rb +20 -0
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e73b3aaf951e74746e4f15fd020a5e9811b13f8222bee893e3b657323dbea0f7
|
4
|
+
data.tar.gz: 38f200e4c7550d9f15ff356e3323fe2a4bdaa5328f6c4c94e5d05401de1cf60a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84c35cf76c50627514dc34702c136f3506fed645ccfb2228d26c21338de8b310e598d18fb302c11675056d0956310641fe0b1d0c60edfb5869ef88e718643833
|
7
|
+
data.tar.gz: 003ee1a957b5f8a2dc9c40c68acf8d57ec4d64ae5e29f26452ea7f763db37e93bb2cd6dd410ca4d31535e8b1613252a335b8efa75cd6462a0bbd2131df8a25c0
|
@@ -198,6 +198,98 @@ class Api::V2::InfoController < Api::V2::ApplicationController
|
|
198
198
|
}
|
199
199
|
}
|
200
200
|
},
|
201
|
+
"/raw/sql": {
|
202
|
+
"post": {
|
203
|
+
"summary": "Raw SQL query execution of SELECT queries",
|
204
|
+
"description": "Executes a SQL query on the underlying PostgreSQL database.
|
205
|
+
|
206
|
+
Designed for SELECT queries that use the json_agg function to aggregate results into JSON arrays.
|
207
|
+
|
208
|
+
Other query types are not recommended and may be restricted for security and performance reasons.
|
209
|
+
|
210
|
+
Only SELECT statements are allowed. DDL and DML statements (INSERT, UPDATE, DELETE) are forbidden.
|
211
|
+
|
212
|
+
Queries can be as simple as
|
213
|
+
|
214
|
+
SELECT json_agg(u) AS result
|
215
|
+
FROM users u
|
216
|
+
WHERE u.active = true;
|
217
|
+
|
218
|
+
or more complex, using joins, subqueries, CTEs, and other SQL features. like:
|
219
|
+
|
220
|
+
WITH order_details AS (
|
221
|
+
SELECT
|
222
|
+
o.id AS order_id,
|
223
|
+
o.date AS order_date,
|
224
|
+
json_agg(
|
225
|
+
json_build_object(
|
226
|
+
'item_id', i.id,
|
227
|
+
'item_name', i.name,
|
228
|
+
'quantity', oi.quantity,
|
229
|
+
'price', oi.price
|
230
|
+
)
|
231
|
+
) AS items
|
232
|
+
FROM orders o
|
233
|
+
JOIN order_items oi ON o.id = oi.order_id
|
234
|
+
JOIN items i ON i.id = oi.item_id
|
235
|
+
GROUP BY o.id
|
236
|
+
)
|
237
|
+
SELECT json_agg(
|
238
|
+
json_build_object(
|
239
|
+
'order_id', od.order_id,
|
240
|
+
'order_date', od.order_date,
|
241
|
+
'customer', json_build_object(
|
242
|
+
'id', c.id,
|
243
|
+
'name', c.name
|
244
|
+
),
|
245
|
+
'items', od.items
|
246
|
+
)
|
247
|
+
) AS result
|
248
|
+
FROM order_details od
|
249
|
+
JOIN customers c ON c.id = od.order_id;
|
250
|
+
|
251
|
+
",
|
252
|
+
"tags": ["Raw"],
|
253
|
+
"security": [
|
254
|
+
"bearerAuth": []
|
255
|
+
],
|
256
|
+
"responses": {
|
257
|
+
"200": {
|
258
|
+
"description": "SQL Query Result",
|
259
|
+
"content": {
|
260
|
+
"application/json": {
|
261
|
+
"schema": {
|
262
|
+
"type": "array",
|
263
|
+
"items": {
|
264
|
+
"type": "object",
|
265
|
+
"properties": {
|
266
|
+
"json_agg": {
|
267
|
+
"type": "string"
|
268
|
+
}
|
269
|
+
}
|
270
|
+
}
|
271
|
+
}
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}
|
275
|
+
},
|
276
|
+
"requestBody": {
|
277
|
+
"content": {
|
278
|
+
"application/json": {
|
279
|
+
"schema": {
|
280
|
+
"type": "object",
|
281
|
+
"properties": {
|
282
|
+
"query": {
|
283
|
+
"type": "string",
|
284
|
+
"example": "SELECT json_agg(u) FROM users u WHERE u.active = true;"
|
285
|
+
}
|
286
|
+
}
|
287
|
+
}
|
288
|
+
}
|
289
|
+
}
|
290
|
+
}
|
291
|
+
}
|
292
|
+
},
|
201
293
|
"/info/version": {
|
202
294
|
"get": {
|
203
295
|
"summary": "Version",
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# require 'model_driven_api/version'
|
2
|
+
class Api::V2::RawController < Api::V2::ApplicationController
|
3
|
+
# Info uses a different auth method: username and password
|
4
|
+
# skip_before_action :authenticate_request, only: [:version, :swagger, :openapi], raise: false
|
5
|
+
skip_before_action :extract_model
|
6
|
+
|
7
|
+
# api :GET, '/api/v2/raw/sql'
|
8
|
+
def sql
|
9
|
+
# if params is nil, render 400
|
10
|
+
render json: { error: "Query is required" }, status: 400 and return if params[:query].nil?
|
11
|
+
|
12
|
+
query = params[:query]
|
13
|
+
|
14
|
+
render json: SafeSqlExecutor.execute_select(query).first["json_agg"], status: 200
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/config/routes.rb
CHANGED
data/lib/model_driven_api.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
module SafeSqlExecutor
|
2
|
+
def self.execute_select(query)
|
3
|
+
# Validate the query
|
4
|
+
validate_select_query(query)
|
5
|
+
|
6
|
+
# Execute the query
|
7
|
+
ActiveRecord::Base.connection.execute(query)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def self.validate_select_query(query)
|
13
|
+
sanitized_query = query.strip.gsub(/\s+/, " ").upcase
|
14
|
+
|
15
|
+
# Allow SELECT or WITH...SELECT queries
|
16
|
+
unless sanitized_query.match?(/^(WITH .+)?SELECT /)
|
17
|
+
raise ArgumentError, "Only SELECT queries (including with CTEs) are allowed"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: model_driven_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gabriele Tassoni
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-01-08 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: thecore_backend_commons
|
@@ -124,6 +123,7 @@ files:
|
|
124
123
|
- app/controllers/api/v2/application_controller.rb
|
125
124
|
- app/controllers/api/v2/authentication_controller.rb
|
126
125
|
- app/controllers/api/v2/info_controller.rb
|
126
|
+
- app/controllers/api/v2/raw_controller.rb
|
127
127
|
- app/controllers/api/v2/users_controller.rb
|
128
128
|
- app/models/endpoints/test_api.rb
|
129
129
|
- app/models/test_api.rb
|
@@ -146,13 +146,13 @@ files:
|
|
146
146
|
- lib/model_driven_api/engine.rb
|
147
147
|
- lib/model_driven_api/version.rb
|
148
148
|
- lib/non_crud_endpoints.rb
|
149
|
+
- lib/safe_sql_executor.rb
|
149
150
|
- lib/tasks/model_driven_api_tasks.rake
|
150
151
|
homepage: https://github.com/gabrieletassoni/model_driven_api
|
151
152
|
licenses:
|
152
153
|
- MIT
|
153
154
|
metadata:
|
154
155
|
allowed_push_host: https://rubygems.org
|
155
|
-
post_install_message:
|
156
156
|
rdoc_options: []
|
157
157
|
require_paths:
|
158
158
|
- lib
|
@@ -167,8 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
167
167
|
- !ruby/object:Gem::Version
|
168
168
|
version: '0'
|
169
169
|
requirements: []
|
170
|
-
rubygems_version: 3.
|
171
|
-
signing_key:
|
170
|
+
rubygems_version: 3.6.2
|
172
171
|
specification_version: 4
|
173
172
|
summary: Convention based RoR engine which uses DB schema introspection to create
|
174
173
|
REST APIs.
|