model_driven_api 3.2.5 → 3.2.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e73b3aaf951e74746e4f15fd020a5e9811b13f8222bee893e3b657323dbea0f7
4
- data.tar.gz: 38f200e4c7550d9f15ff356e3323fe2a4bdaa5328f6c4c94e5d05401de1cf60a
3
+ metadata.gz: b97e79e1bc34847a05fd1c9ac004c0f64d15203b2a803d176559bfdcc2b3cf4e
4
+ data.tar.gz: 6c48764ef66785db7b5793bd0bde4526233f39ae10650ec76c98799f0ac5efef
5
5
  SHA512:
6
- metadata.gz: 84c35cf76c50627514dc34702c136f3506fed645ccfb2228d26c21338de8b310e598d18fb302c11675056d0956310641fe0b1d0c60edfb5869ef88e718643833
7
- data.tar.gz: 003ee1a957b5f8a2dc9c40c68acf8d57ec4d64ae5e29f26452ea7f763db37e93bb2cd6dd410ca4d31535e8b1613252a335b8efa75cd6462a0bbd2131df8a25c0
6
+ metadata.gz: 925b9065f28afcfa64652a4262eccf1ad59f829c153f8b9950653331857c9020649633be0590e18c7acfe29aafa06118c839cbbce3e993085c77f98d4d7c4e59
7
+ data.tar.gz: 2ae0d12d73b4c23113d0f98d1829adf4e35ea8a29fa0370d7d7fdd0f8fae5fe3dfcbfab33a7bbd6e0b6a97b9e5a9c431bdcdef403114b2f1846d06a50f701fc9
@@ -201,54 +201,7 @@ class Api::V2::InfoController < Api::V2::ApplicationController
201
201
  "/raw/sql": {
202
202
  "post": {
203
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
- ",
204
+ "description": "Executes a SQL query on the underlying PostgreSQL database, the query must return the JSON in a **result** key (please note in the examples the _SELECT json_agg(u) AS result_ or in the more complex one the _SELECT jsonb_agg(pick_data) AS result_, they always use the **result** return object).\n \nDesigned for SELECT queries that use the json_agg function to aggregate results into JSON arrays, which must return the JSON in a **result** key.\n \nOther query types are not recommended and may be restricted for security and performance reasons.\n \nOnly SELECT statements are allowed. DDL and DML statements (INSERT, UPDATE, DELETE) are forbidden.\n \nQueries can be as simple as:\n \n```sql\nSELECT json_agg(u) AS result\nFROM users u\nWHERE u.active = true;\n```\n \nor more complex, using joins, subqueries, CTEs, and other SQL features. like:\n \n```sql\nWITH pick_data AS (\n SELECT p.id,\n p.project_id,\n p.quantity,\n p.created_at,\n p.updated_at,\n p.notes,\n p.document_id,\n p.external_code,\n p.reference_project_id,\n p.reference_row,\n p.closed,\n p.parent_reference_row,\n p.packages,\n p.weight,\n p.dispatched_quantity,\n p.override_item_reference,\n p.override_item_description,\n p.override_item_measure_unit,\n p.lock_version,\n p.user_id,\n COALESCE(SUM(pr.quantity), 0) AS quantity_detected,\n COALESCE(p.quantity, 0) - COALESCE(SUM(pr.quantity), 0) AS quantity_remaining,\n json_agg(\n jsonb_build_object(\n 'id',\n pr.id,\n 'item_id',\n pr.item_id,\n 'location_id',\n pr.location_id,\n 'quantity',\n pr.quantity\n )\n ) AS project_rows,\n jsonb_build_object(\n 'id',\n l.id,\n 'name',\n l.name,\n 'description',\n l.description\n ) AS location,\n jsonb_build_object(\n 'id',\n i.id,\n 'code',\n i.code,\n 'created_at',\n i.created_at,\n 'updated_at',\n i.updated_at,\n 'description',\n i.description,\n 'has_serials',\n i.has_serials,\n 'external_code',\n i.external_code,\n 'barcode',\n i.barcode,\n 'weight',\n i.weight,\n 'quantity',\n i.quantity,\n 'package_quantity',\n i.package_quantity,\n 'locked_quantity',\n i.locked_quantity,\n 'disabled',\n i.disabled,\n 'measure_unit',\n jsonb_build_object('id', mu.id, 'name', mu.name),\n 'location',\n jsonb_build_object('id', il.id, 'name', il.name),\n 'locations',\n (\n SELECT jsonb_agg(\n jsonb_build_object('id', loc.id, 'name', loc.name)\n )\n FROM locations loc\n JOIN item_locations il ON il.location_id = loc.id\n WHERE il.item_id = i.id\n ),\n 'additional_barcodes',\n (\n SELECT jsonb_agg(\n jsonb_build_object('id', ab.id, 'code', ab.code)\n )\n FROM additional_barcodes ab\n WHERE ab.item_id = i.id\n )\n ) AS item\n FROM picks p\n LEFT JOIN project_rows pr ON pr.pick_id = p.id\n LEFT JOIN locations l ON l.id = p.location_id\n LEFT JOIN items i ON i.id = p.item_id\n LEFT JOIN measure_units mu ON mu.id = i.measure_unit_id\n LEFT JOIN locations il ON il.id = i.location_id\n WHERE p.project_id = 16130\n GROUP BY p.id,\n l.id,\n i.id,\n mu.id,\n il.id\n)\nSELECT jsonb_agg(pick_data) AS result\nFROM pick_data;\n```\n \nLet's break down the provided SQL query and understand why it uses a Common Table Expression (CTE) and how it can improve performance.\n \n### Explanation of the complex Query\n \nThe provided query uses a CTE named `pick_data` to gather and aggregate data from multiple tables (`picks`, `project_rows`, `locations`, `items`, `measure_units`, `item_locations`, and `additional_barcodes`). The final result is a JSON array of aggregated data.\n \n#### Key Components of the Query:\n \n1. **CTE Definition**:\n \n ```sql\n WITH pick_data AS (\n -- Subquery content\n )\n ```\n \n The CTE `pick_data` is defined to encapsulate the logic of the subquery. This makes the query more readable and modular.\n \n2. **Data Selection and Aggregation**:\n Inside the CTE, data is selected and aggregated from various tables. Key operations include:\n \n - **Column Selection**: Selecting specific columns from the `picks` table.\n - **Aggregation**: Using `COALESCE` and `SUM` to calculate `quantity_detected` and `quantity_remaining`.\n - **JSON Aggregation**: Using `json_agg` and `jsonb_build_object` to create JSON objects and arrays for nested data structures.\n \n3. **Final Selection**:\n ```sql\n SELECT jsonb_agg(pick_data) AS result FROM pick_data;\n ```\n The final selection aggregates all rows from the CTE `pick_data` into a single JSON array.\n \n### Why Use a CTE?\n \n1. **Readability and Maintainability**:\n \n - **Modular Code**: By using a CTE, the complex logic is encapsulated in a named subquery, making the main query easier to read and understand.\n - **Reusability**: The CTE can be reused within the same query if needed, avoiding duplication of code.\n \n2. **Performance**:\n - **Optimization**: Modern SQL engines can optimize CTEs effectively. They can be materialized (computed once and stored) or inlined (expanded in the main query) based on the query plan.\n - **Intermediate Results**: CTEs allow breaking down complex queries into simpler steps, which can sometimes help the SQL engine optimize each step more effectively.\n \n### Documentation for Editing Generic Queries\n \nWhen editing or creating new queries, consider the following steps and best practices:\n \n1. **Identify the Purpose**:\n \n - Clearly define what the query needs to achieve. Understand the data relationships and the final output format.\n \n2. **Use CTEs for Complex Logic**:\n \n - Break down complex queries into smaller, manageable parts using CTEs. This improves readability and maintainability.\n \n3. **Optimize Aggregations and Joins**:\n \n - Ensure that aggregations and joins are optimized. Use indexes where appropriate and avoid unnecessary computations.\n \n4. **Leverage JSON Functions**:\n \n - Use JSON functions (`json_agg`, `jsonb_build_object`, etc.) to handle nested data structures effectively.\n \n5. **Test and Validate**:\n - Test the query with different datasets to ensure it performs well and returns the correct results. Validate the output format.\n \n### Example of a Generic Query Using CTE\n \nHere's a generic example to illustrate how to use a CTE in a query:\n \n```sql\n \n\nWITH data_aggregation AS (\n SELECT\n t1.id,\n t1.name,\n SUM(t2.value) AS total_value,\n json_agg(\n jsonb_build_object(\n 'id', t2.id,\n 'value', t2.value\n )\n ) AS details\n FROM table1 t1\n LEFT JOIN table2 t2 ON t2.table1_id = t1.id\n GROUP BY t1.id\n)\nSELECT jsonb_agg(data_aggregation) AS result FROM data_aggregation;\n```\n \n### Conclusion\n \nUsing CTEs in SQL queries helps in organizing complex logic, improving readability, and potentially enhancing performance. When editing or creating new queries, follow best practices such as breaking down complex logic, optimizing joins and aggregations, and leveraging JSON functions for nested data structures.\n",
252
205
  "tags": ["Raw"],
253
206
  "security": [
254
207
  "bearerAuth": []
@@ -271,7 +224,23 @@ or more complex, using joins, subqueries, CTEs, and other SQL features. like:
271
224
  }
272
225
  }
273
226
  }
227
+ },
228
+ "400": {
229
+ "description": "SQL query must return a key called result otherwise cannot be parsed",
230
+ "content": {
231
+ "application/json": {
232
+ "schema": {
233
+ "type": "object",
234
+ "properties": {
235
+ "error": {
236
+ "type": "string"
237
+ }
238
+ }
239
+ }
240
+ }
241
+ }
274
242
  }
243
+
275
244
  },
276
245
  "requestBody": {
277
246
  "content": {
@@ -11,7 +11,12 @@ class Api::V2::RawController < Api::V2::ApplicationController
11
11
 
12
12
  query = params[:query]
13
13
 
14
- render json: SafeSqlExecutor.execute_select(query).first["json_agg"], status: 200
14
+ first_element = SafeSqlExecutor.execute_select(query).first rescue nil
15
+
16
+ # Error if first_element does not contain a key called results
17
+ render json: { error: "Query must return a key called result" }, status: 400 and return if first_element.nil? || !first_element.key?("result")
18
+
19
+ render json: first_element["result"], status: 200
15
20
  end
16
21
 
17
22
  end
@@ -1,3 +1,3 @@
1
1
  module ModelDrivenApi
2
- VERSION = "3.2.5".freeze
2
+ VERSION = "3.2.6".freeze
3
3
  end
metadata CHANGED
@@ -1,13 +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.5
4
+ version: 3.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriele Tassoni
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-08 00:00:00.000000000 Z
10
+ date: 2025-01-14 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: thecore_backend_commons