{
  "topic": "analytics",
  "path": [
    "analytics"
  ],
  "title": "analytics — Trino SQL analytics interface",
  "synopsis": "Cyoda Cloud exposes entity data as Trino SQL tables through a Trino connector. The connector uses the Schema Management REST API to discover table definitions and the WebSocket (STOMP) messaging API to stream entity rows at query time.",
  "body": "# analytics\n\n**Cloud-only.** The analytics surface documented here is served by Cyoda Cloud (`cloud.cyoda.com`). It is not part of the cyoda-go binary. Running a local cyoda-go server does not expose any of the endpoints below.\n\n## NAME\n\nanalytics — Trino SQL analytics interface for querying Cyoda entity data via SQL.\n\n## SYNOPSIS\n\n```\n# SQL Schema Management REST API (Cyoda Cloud)\nGET    /api/sql/schema/{schemaId}\nDELETE /api/sql/schema/{schemaId}\nGET    /api/sql/schema/?schemaName={name}\nPOST   /api/sql/schema/\nDELETE /api/sql/schema/?schemaName={name}\nPUT    /api/sql/schema/putDefault/{schemaName}\nGET    /api/sql/schema/listAll\nGET    /api/sql/schema/genTables/{entityModelId}\nPOST   /api/sql/schema/updateTables/{entityModelId}\n\n# WebSocket (STOMP) Messaging API (Cyoda Cloud)\ntreeNode.getSchemas\ntreeNode.getSchema\ntreeNode.getData\ntreeNode.getRawData\nview.getViews\nview.addView\nview.renameView\nview.dropView\nreports.runReport\nreports.getReportConfigs\nreports.getReportDefinition\nreports.getReportHistories\nreports.getReportStatistics\nreports.getReportGroups\nreports.getReportRows\nreports.deleteReports\n```\n\n## DESCRIPTION\n\nCyoda Cloud exposes entity data as Trino SQL tables through a Trino connector. The connector uses the Schema Management REST API to discover table definitions and the WebSocket (STOMP) messaging API to stream entity rows at query time.\n\n## SQL SCHEMA MANAGEMENT REST API\n\nAll endpoints are served under `/api/sql/schema` in Cyoda Cloud.\n\nAuthentication is required on all endpoints. Errors follow RFC 7807 Problem Details format: `{ \"type\", \"title\", \"status\", \"detail\", \"instance\", \"properties\" }`.\n\n**GET /api/sql/schema/{schemaId}**\n\nRetrieve a complete schema configuration by its time-based UUID. Returns all fields including hidden ones. Returns `400` if the UUID is not a time-based (version 1) UUID; returns `404` if not found.\n\n- `schemaId` (path): UUID (version 1 / time-based)\n\nResponse: `200 OK`, `application/json`, `SchemaConfigDto`.\n\n**DELETE /api/sql/schema/{schemaId}**\n\nDelete a schema by UUID. Requires both read and delete permissions. Returns confirmation string on success.\n\nResponse: `200 OK`, `application/json`, string — e.g., `\"SQL Schema with id 8824c480-c166-11ee-822a-ae468cd3ed16 deleted\"`.\n\n**GET /api/sql/schema/?schemaName={name}**\n\nRetrieve a schema by its unique name. Returns `404` if not found.\n\n- `schemaName` (query, required): case-sensitive string, 1–1024 characters\n\nResponse: `200 OK`, `application/json`, `SchemaConfigDto`.\n\n**POST /api/sql/schema/**\n\nSave a schema (create or update). Uses upsert semantics: if a schema with the same `schemaName` exists, its tables are replaced with the incoming definition. If no schema with that name exists, a new one is created.\n\nThe `id` field in the request body is ignored; matching is done exclusively by `schemaName`. Returns the time-based UUID of the saved schema.\n\nValidation: `schemaName` must be 1–1024 characters.\n\nRequest body: `SchemaConfigDto`.\n\nResponse: `200 OK`, `application/json`, UUID string — e.g., `\"8824c480-c166-11ee-822a-ae468cd3ed16\"`.\n\n**DELETE /api/sql/schema/?schemaName={name}**\n\nDelete a schema by name. Returns `404` if not found.\n\nResponse: `200 OK`, `application/json`, string — e.g., `\"SQL Schema with name NOBEL_PRIZES deleted\"`.\n\n**PUT /api/sql/schema/putDefault/{schemaName}**\n\nCreate a new schema by scanning all Entity Models the user has read access to. Generates the complete set of tables (object, array, JSON) for every model. Validates for duplicate table names and duplicate field names within a table. On validation failure, returns `422 Unprocessable Entity`.\n\n- `schemaName` (path): string, 1–1024 characters\n\nResponse: `200 OK`, `application/json`, `SchemaConfigDto`.\n\n**GET /api/sql/schema/listAll**\n\nList all schemas the user has read access to. Schemas the user cannot read are silently omitted. Returns all fields including hidden ones.\n\nResponse: `200 OK`, `application/json`, array of `SchemaConfigDto`.\n\n**GET /api/sql/schema/genTables/{entityModelId}**\n\nPreview: generate SQL table configurations from a specific Entity Model without saving. Read-only.\n\n- `entityModelId` (path): UUID of the Entity Model\n\nResponse: `200 OK`, `application/json`, array of `TableConfigDto`.\n\n**POST /api/sql/schema/updateTables/{entityModelId}**\n\nMerge existing table configurations with the current state of an Entity Model. Read-only; does not save. Tables are matched by `uniformedPath`. Fields from the current model are added; existing table custom settings are preserved.\n\n- `entityModelId` (path): UUID of the Entity Model\n\nRequest body: array of `TableConfigDto`.\n\nResponse: `200 OK`, `application/json`, array of `TableConfigDto`.\n\n## SCHEMA DTO STRUCTURES\n\n**SchemaConfigDto:**\n\n```json\n{\n  \"id\": \"8824c480-c166-11ee-822a-ae468cd3ed16\",\n  \"schemaName\": \"NOBEL_PRIZES\",\n  \"tables\": [ ...TableConfigDto... ]\n}\n```\n\n- `id` — UUID (time-based, version 1); server-assigned; null when creating via POST; required for GET/DELETE by ID\n- `schemaName` — string, unique, 1–1024 characters\n- `tables` — array of `TableConfigDto`; sorted by `uniformedPath` in responses\n\n**TableConfigDto:**\n\n```json\n{\n  \"tableName\": \"nobel_prize\",\n  \"metadataClassId\": \"a1b2c3d4-e5f6-11ee-b789-0242ac120002\",\n  \"uniformedPath\": \"$\",\n  \"fields\": [ ...FieldConfigDto... ],\n  \"hidden\": false,\n  \"modelUpdateDate\": 1702900000\n}\n```\n\n- `tableName` — SQL table display name; auto-generated from model name, version, and path; customizable\n- `metadataClassId` — UUID of the Cyoda Entity Model; all tables from the same model share this value\n- `uniformedPath` — structural key identifying which node in the model this table represents. Values: `\"$\"` (root level), `\"$.fieldName\"` (nested object outside arrays), `\"$.fieldName[*]\"` (object table under array element), `\"$.fieldName[*]^\"` (detached array table — individual array elements), `\"json\"` (special JSON table, full reconstructed entity as string)\n- `fields` — array of `FieldConfigDto`\n- `hidden` — boolean; hidden tables excluded from WebSocket schema discovery (`filterHidden=true`) but always included in REST responses\n- `modelUpdateDate` — int64 (epoch seconds), nullable; last Entity Model update timestamp\n\n**Table naming rules:**\n\n- Base: `{modelName}` when version = 1; `{modelName}_{version}` when version > 1\n- Path segments appended with underscores (e.g., `nobel_prize_laureates` for path `$.laureates`)\n- Multi-level array nesting: `_{n}d` suffix (e.g., `_2d` for depth 2)\n- Detached arrays: `_array` suffix\n- JSON table: `_json` suffix\n\n**FieldConfigDto:**\n\n```json\n{\n  \"fieldName\": \"category\",\n  \"fieldKey\": \"category\",\n  \"fieldCategory\": \"DATA\",\n  \"dataType\": \"STRING\",\n  \"isArray\": false,\n  \"hidden\": false,\n  \"flatten\": null,\n  \"arrayFields\": null\n}\n```\n\n- `fieldName` — SQL column name; display name; defaults to `fieldKey` for DATA fields; snake_case aliases for ROOT fields\n- `fieldKey` — internal resolution key; interpretation depends on `fieldCategory`\n- `fieldCategory` — one of: `DATA` (entity payload fields keyed by value map short key), `ROOT` (entity metadata: `creationDate`, `lastUpdateTime`, `state`), `INDEX` (array index fields keyed by nesting level position), `SPECIAL` (synthetic columns: `ENTITY_ID`, `POINT_TIME`, `JSON`)\n- `dataType` — one of: `STRING`, `INTEGER`, `LONG`, `DOUBLE`, `BOOLEAN`, `DATE`, `ZONED_DATE_TIME`, `UUID_TYPE`, `TIME_UUID_TYPE`, `BYTE_ARRAY`\n- `isArray` — boolean; when true, `arrayFields` contains element-level sub-fields\n- `hidden` — boolean\n- `flatten` — boolean or null; for INDEX array fields: `true` flattens indices into separate columns (`index_0`, `index_1`, etc.), `false` keeps as array\n- `arrayFields` — array of `FieldConfigDto` or null; sub-fields when `isArray=true`\n\n**Reserved field names (cannot be used for DATA fields):** `index`, `entity_id`, `point_time`, `creation_date`, `last_update_date`, `state`.\n\n**Always-present field categories per table:**\n\n- `SPECIAL`: `entity_id` (`UUID_TYPE`), `point_time` (allows point-in-time queries)\n- `ROOT`: `creation_date` (`DATE`), `last_update_date` (`DATE`), `state` (`STRING`)\n- `SPECIAL` JSON table only: `entity` (`JSON` key, full reconstructed JSON string)\n- `INDEX`: present only on tables derived from array nodes\n\n## WEBSOCKET (STOMP) MESSAGING API\n\nThe WebSocket API is served by Cyoda Cloud over STOMP. The concrete WebSocket endpoint URL is environment-specific and not part of this contract.\n\n**TreeNode Data Access (treeNode.*):**\n\n- `treeNode.getSchemas` — retrieve all schemas the user can read (hidden items filtered out); payload: userId string\n- `treeNode.getSchema` — retrieve a schema by name (hidden items filtered); payload: schemaName string; runs in anonymous context\n- `treeNode.getData` — primary data channel; the Trino connector calls this to fulfil SQL SELECT queries; payload: `DataRequestDto`; runs in authenticated context; returns stream of `EntityContentDto`\n- `treeNode.getRawData` — returns raw tree node structure of all entities (diagnostic; no filtering by model, condition, or fields); payload: userId string; returns stream of `RawEntityContentDto`\n\n**DataRequestDto fields:**\n\n- `metaClassId` — UUID — which Entity Model to query\n- `path` — string — structural path / `uniformedPath` value of the target table\n- `domainCondition` — map of `ColumnCategory` → field key → condition; organized by category (`SPECIAL`, `ROOT`, `INDEX`, `DATA`)\n- `expressionCondition` — `GroupConditionDto` — alternative condition format using AND/OR groups\n- `selectedFields` — optional list of value map keys to include; null returns all fields\n- `userId` — string — user ID for authenticated context and permission-filtered entity access\n\nCondition pushdown by category:\n\n- `SPECIAL` / `ENTITY_ID` equality — direct entity ID lookup, bypasses full scan\n- `SPECIAL` / `POINT_TIME` equality — sets snapshot time for the query (ISO-8601 instant)\n- `ROOT` — applied as range conditions on entity-level fields (`creationDate`, `lastUpdateTime`, `state`)\n- `INDEX` — applied as in-memory predicates on array index values\n- `DATA` — applied as value map conditions, pushed to the storage layer\n\nData is fetched in pages (default page size: 1000). Point-in-time is derived from the `POINT_TIME` condition or defaults to the current consistency time.\n\n**Views (view.*):**\n\n- `view.getViews` — get all views the user can read; payload: userId string; returns stream of `TrinoViewDto`\n- `view.addView` — add a view; payload: `TrinoViewDto`; returns null on success, error string on conflict (when `replace=false` and view already exists)\n- `view.renameView` — rename a view; payload: `TrinoViewDto` with `newName`; returns null on success, error string on failure\n- `view.dropView` — delete a view; payload: `TrinoViewDto`; returns null on success, error string if not found\n\nView identity: composite key of `(schemaName, tableName)`, both automatically lowercased.\n\n**Reports (reports.*):**\n\n- `reports.getReportConfigs` — list saved report configurations (GridConfigs); payload: userId; returns stream of `{id, creationDate}`\n- `reports.runReport` — execute a report; payload: `{configId, userId}`; returns reportId string\n- `reports.getReportDefinition` — get a saved GridConfig definition; anonymous context\n- `reports.getReportHistories` — completed non-failed executions as `Map<String, Any>`; anonymous context\n- `reports.getReportStatistics` — all executions as `DistributedReportInfoDto`; anonymous context\n- `reports.getReportGroups` — grouping headers for an execution; payload: `{reportId, groupingVersion, userId}`; anonymous context\n- `reports.getReportRows` — paginated data rows; payload: `{reportId, groupJsonBase64, startRow, endRow, userId}`; anonymous context\n- `reports.deleteReports` — delete report executions; authenticated context\n\n## CATALOG AND SCHEMA LAYOUT\n\nIn Trino, cyoda entity data is exposed as tables under the Trino catalog and schema configured by the Trino connector deployment. Table names match `tableName` fields in `TableConfigDto`. Each SQL table corresponds to one `uniformedPath` node in an Entity Model.\n\nA single Entity Model produces multiple tables:\n\n- One object table per object-level node (e.g., root `$`, `$.address`)\n- One detached array table per array node (path ending with `^`)\n- One JSON table per model (path = `json`)\n\nQuerying a table returns one row per entity (object and JSON tables) or one row per array element (detached array tables). The `entity_id` column is the entity UUID. The `point_time` column accepts a point-in-time value for historical queries.\n\n## ERRORS\n\n- `errors.BAD_REQUEST` — `400` — schema name too long (> 1024 chars), UUID is not time-based (version 1)\n- `404 Not Found` (RFC 7807) — schema not found by ID or name\n- `422 Unprocessable Entity` — default schema generation failed due to duplicate table or field names\n\n## EXAMPLES\n\n**List all schemas:**\n\n```\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"https://cloud.cyoda.com/api/sql/schema/listAll\"\n```\n\n**Get schema by name:**\n\n```\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"https://cloud.cyoda.com/api/sql/schema/?schemaName=NOBEL_PRIZES\"\n```\n\n**Create default schema from all entity models:**\n\n```\ncurl -s -X PUT \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"https://cloud.cyoda.com/api/sql/schema/putDefault/Nobel_PRIZES\"\n```\n\n**Preview tables for a model (by model UUID):**\n\n```\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"https://cloud.cyoda.com/api/sql/schema/genTables/a1b2c3d4-e5f6-11ee-b789-0242ac120002\"\n```\n\n**Save a schema:**\n\n```\ncurl -s -X POST \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"schemaName\": \"NOBEL_PRIZES\",\n    \"tables\": [\n      {\n        \"tableName\": \"nobel_prize\",\n        \"metadataClassId\": \"a1b2c3d4-e5f6-11ee-b789-0242ac120002\",\n        \"uniformedPath\": \"$\",\n        \"fields\": [],\n        \"hidden\": false\n      }\n    ]\n  }' \\\n  \"https://cloud.cyoda.com/api/sql/schema/\"\n```\n\n**Delete a schema by name:**\n\n```\ncurl -s -X DELETE \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"https://cloud.cyoda.com/api/sql/schema/?schemaName=NOBEL_PRIZES\"\n```\n\n**Trino CLI connection (example; concrete JDBC URL is deployment-specific):**\n\n```\ntrino --server https://trino.cloud.cyoda.com \\\n      --user \"$TRINO_USER\" \\\n      --password \\\n      --catalog cyoda \\\n      --schema NOBEL_PRIZES \\\n      --execute \"SELECT entity_id, category, year FROM nobel_prize LIMIT 10\"\n```\n\n## SEE ALSO\n\n- search\n- models\n- grpc\n- errors.BAD_REQUEST\n",
  "sections": [
    {
      "name": "NAME",
      "body": "analytics — Trino SQL analytics interface for querying Cyoda entity data via SQL."
    },
    {
      "name": "SYNOPSIS",
      "body": "```\n# SQL Schema Management REST API (Cyoda Cloud)\nGET    /api/sql/schema/{schemaId}\nDELETE /api/sql/schema/{schemaId}\nGET    /api/sql/schema/?schemaName={name}\nPOST   /api/sql/schema/\nDELETE /api/sql/schema/?schemaName={name}\nPUT    /api/sql/schema/putDefault/{schemaName}\nGET    /api/sql/schema/listAll\nGET    /api/sql/schema/genTables/{entityModelId}\nPOST   /api/sql/schema/updateTables/{entityModelId}\n\n# WebSocket (STOMP) Messaging API (Cyoda Cloud)\ntreeNode.getSchemas\ntreeNode.getSchema\ntreeNode.getData\ntreeNode.getRawData\nview.getViews\nview.addView\nview.renameView\nview.dropView\nreports.runReport\nreports.getReportConfigs\nreports.getReportDefinition\nreports.getReportHistories\nreports.getReportStatistics\nreports.getReportGroups\nreports.getReportRows\nreports.deleteReports\n```"
    },
    {
      "name": "DESCRIPTION",
      "body": "Cyoda Cloud exposes entity data as Trino SQL tables through a Trino connector. The connector uses the Schema Management REST API to discover table definitions and the WebSocket (STOMP) messaging API to stream entity rows at query time."
    },
    {
      "name": "SQL SCHEMA MANAGEMENT REST API",
      "body": "All endpoints are served under `/api/sql/schema` in Cyoda Cloud.\n\nAuthentication is required on all endpoints. Errors follow RFC 7807 Problem Details format: `{ \"type\", \"title\", \"status\", \"detail\", \"instance\", \"properties\" }`.\n\n**GET /api/sql/schema/{schemaId}**\n\nRetrieve a complete schema configuration by its time-based UUID. Returns all fields including hidden ones. Returns `400` if the UUID is not a time-based (version 1) UUID; returns `404` if not found.\n\n- `schemaId` (path): UUID (version 1 / time-based)\n\nResponse: `200 OK`, `application/json`, `SchemaConfigDto`.\n\n**DELETE /api/sql/schema/{schemaId}**\n\nDelete a schema by UUID. Requires both read and delete permissions. Returns confirmation string on success.\n\nResponse: `200 OK`, `application/json`, string — e.g., `\"SQL Schema with id 8824c480-c166-11ee-822a-ae468cd3ed16 deleted\"`.\n\n**GET /api/sql/schema/?schemaName={name}**\n\nRetrieve a schema by its unique name. Returns `404` if not found.\n\n- `schemaName` (query, required): case-sensitive string, 1–1024 characters\n\nResponse: `200 OK`, `application/json`, `SchemaConfigDto`.\n\n**POST /api/sql/schema/**\n\nSave a schema (create or update). Uses upsert semantics: if a schema with the same `schemaName` exists, its tables are replaced with the incoming definition. If no schema with that name exists, a new one is created.\n\nThe `id` field in the request body is ignored; matching is done exclusively by `schemaName`. Returns the time-based UUID of the saved schema.\n\nValidation: `schemaName` must be 1–1024 characters.\n\nRequest body: `SchemaConfigDto`.\n\nResponse: `200 OK`, `application/json`, UUID string — e.g., `\"8824c480-c166-11ee-822a-ae468cd3ed16\"`.\n\n**DELETE /api/sql/schema/?schemaName={name}**\n\nDelete a schema by name. Returns `404` if not found.\n\nResponse: `200 OK`, `application/json`, string — e.g., `\"SQL Schema with name NOBEL_PRIZES deleted\"`.\n\n**PUT /api/sql/schema/putDefault/{schemaName}**\n\nCreate a new schema by scanning all Entity Models the user has read access to. Generates the complete set of tables (object, array, JSON) for every model. Validates for duplicate table names and duplicate field names within a table. On validation failure, returns `422 Unprocessable Entity`.\n\n- `schemaName` (path): string, 1–1024 characters\n\nResponse: `200 OK`, `application/json`, `SchemaConfigDto`.\n\n**GET /api/sql/schema/listAll**\n\nList all schemas the user has read access to. Schemas the user cannot read are silently omitted. Returns all fields including hidden ones.\n\nResponse: `200 OK`, `application/json`, array of `SchemaConfigDto`.\n\n**GET /api/sql/schema/genTables/{entityModelId}**\n\nPreview: generate SQL table configurations from a specific Entity Model without saving. Read-only.\n\n- `entityModelId` (path): UUID of the Entity Model\n\nResponse: `200 OK`, `application/json`, array of `TableConfigDto`.\n\n**POST /api/sql/schema/updateTables/{entityModelId}**\n\nMerge existing table configurations with the current state of an Entity Model. Read-only; does not save. Tables are matched by `uniformedPath`. Fields from the current model are added; existing table custom settings are preserved.\n\n- `entityModelId` (path): UUID of the Entity Model\n\nRequest body: array of `TableConfigDto`.\n\nResponse: `200 OK`, `application/json`, array of `TableConfigDto`."
    },
    {
      "name": "SCHEMA DTO STRUCTURES",
      "body": "**SchemaConfigDto:**\n\n```json\n{\n  \"id\": \"8824c480-c166-11ee-822a-ae468cd3ed16\",\n  \"schemaName\": \"NOBEL_PRIZES\",\n  \"tables\": [ ...TableConfigDto... ]\n}\n```\n\n- `id` — UUID (time-based, version 1); server-assigned; null when creating via POST; required for GET/DELETE by ID\n- `schemaName` — string, unique, 1–1024 characters\n- `tables` — array of `TableConfigDto`; sorted by `uniformedPath` in responses\n\n**TableConfigDto:**\n\n```json\n{\n  \"tableName\": \"nobel_prize\",\n  \"metadataClassId\": \"a1b2c3d4-e5f6-11ee-b789-0242ac120002\",\n  \"uniformedPath\": \"$\",\n  \"fields\": [ ...FieldConfigDto... ],\n  \"hidden\": false,\n  \"modelUpdateDate\": 1702900000\n}\n```\n\n- `tableName` — SQL table display name; auto-generated from model name, version, and path; customizable\n- `metadataClassId` — UUID of the Cyoda Entity Model; all tables from the same model share this value\n- `uniformedPath` — structural key identifying which node in the model this table represents. Values: `\"$\"` (root level), `\"$.fieldName\"` (nested object outside arrays), `\"$.fieldName[*]\"` (object table under array element), `\"$.fieldName[*]^\"` (detached array table — individual array elements), `\"json\"` (special JSON table, full reconstructed entity as string)\n- `fields` — array of `FieldConfigDto`\n- `hidden` — boolean; hidden tables excluded from WebSocket schema discovery (`filterHidden=true`) but always included in REST responses\n- `modelUpdateDate` — int64 (epoch seconds), nullable; last Entity Model update timestamp\n\n**Table naming rules:**\n\n- Base: `{modelName}` when version = 1; `{modelName}_{version}` when version > 1\n- Path segments appended with underscores (e.g., `nobel_prize_laureates` for path `$.laureates`)\n- Multi-level array nesting: `_{n}d` suffix (e.g., `_2d` for depth 2)\n- Detached arrays: `_array` suffix\n- JSON table: `_json` suffix\n\n**FieldConfigDto:**\n\n```json\n{\n  \"fieldName\": \"category\",\n  \"fieldKey\": \"category\",\n  \"fieldCategory\": \"DATA\",\n  \"dataType\": \"STRING\",\n  \"isArray\": false,\n  \"hidden\": false,\n  \"flatten\": null,\n  \"arrayFields\": null\n}\n```\n\n- `fieldName` — SQL column name; display name; defaults to `fieldKey` for DATA fields; snake_case aliases for ROOT fields\n- `fieldKey` — internal resolution key; interpretation depends on `fieldCategory`\n- `fieldCategory` — one of: `DATA` (entity payload fields keyed by value map short key), `ROOT` (entity metadata: `creationDate`, `lastUpdateTime`, `state`), `INDEX` (array index fields keyed by nesting level position), `SPECIAL` (synthetic columns: `ENTITY_ID`, `POINT_TIME`, `JSON`)\n- `dataType` — one of: `STRING`, `INTEGER`, `LONG`, `DOUBLE`, `BOOLEAN`, `DATE`, `ZONED_DATE_TIME`, `UUID_TYPE`, `TIME_UUID_TYPE`, `BYTE_ARRAY`\n- `isArray` — boolean; when true, `arrayFields` contains element-level sub-fields\n- `hidden` — boolean\n- `flatten` — boolean or null; for INDEX array fields: `true` flattens indices into separate columns (`index_0`, `index_1`, etc.), `false` keeps as array\n- `arrayFields` — array of `FieldConfigDto` or null; sub-fields when `isArray=true`\n\n**Reserved field names (cannot be used for DATA fields):** `index`, `entity_id`, `point_time`, `creation_date`, `last_update_date`, `state`.\n\n**Always-present field categories per table:**\n\n- `SPECIAL`: `entity_id` (`UUID_TYPE`), `point_time` (allows point-in-time queries)\n- `ROOT`: `creation_date` (`DATE`), `last_update_date` (`DATE`), `state` (`STRING`)\n- `SPECIAL` JSON table only: `entity` (`JSON` key, full reconstructed JSON string)\n- `INDEX`: present only on tables derived from array nodes"
    },
    {
      "name": "WEBSOCKET (STOMP) MESSAGING API",
      "body": "The WebSocket API is served by Cyoda Cloud over STOMP. The concrete WebSocket endpoint URL is environment-specific and not part of this contract.\n\n**TreeNode Data Access (treeNode.*):**\n\n- `treeNode.getSchemas` — retrieve all schemas the user can read (hidden items filtered out); payload: userId string\n- `treeNode.getSchema` — retrieve a schema by name (hidden items filtered); payload: schemaName string; runs in anonymous context\n- `treeNode.getData` — primary data channel; the Trino connector calls this to fulfil SQL SELECT queries; payload: `DataRequestDto`; runs in authenticated context; returns stream of `EntityContentDto`\n- `treeNode.getRawData` — returns raw tree node structure of all entities (diagnostic; no filtering by model, condition, or fields); payload: userId string; returns stream of `RawEntityContentDto`\n\n**DataRequestDto fields:**\n\n- `metaClassId` — UUID — which Entity Model to query\n- `path` — string — structural path / `uniformedPath` value of the target table\n- `domainCondition` — map of `ColumnCategory` → field key → condition; organized by category (`SPECIAL`, `ROOT`, `INDEX`, `DATA`)\n- `expressionCondition` — `GroupConditionDto` — alternative condition format using AND/OR groups\n- `selectedFields` — optional list of value map keys to include; null returns all fields\n- `userId` — string — user ID for authenticated context and permission-filtered entity access\n\nCondition pushdown by category:\n\n- `SPECIAL` / `ENTITY_ID` equality — direct entity ID lookup, bypasses full scan\n- `SPECIAL` / `POINT_TIME` equality — sets snapshot time for the query (ISO-8601 instant)\n- `ROOT` — applied as range conditions on entity-level fields (`creationDate`, `lastUpdateTime`, `state`)\n- `INDEX` — applied as in-memory predicates on array index values\n- `DATA` — applied as value map conditions, pushed to the storage layer\n\nData is fetched in pages (default page size: 1000). Point-in-time is derived from the `POINT_TIME` condition or defaults to the current consistency time.\n\n**Views (view.*):**\n\n- `view.getViews` — get all views the user can read; payload: userId string; returns stream of `TrinoViewDto`\n- `view.addView` — add a view; payload: `TrinoViewDto`; returns null on success, error string on conflict (when `replace=false` and view already exists)\n- `view.renameView` — rename a view; payload: `TrinoViewDto` with `newName`; returns null on success, error string on failure\n- `view.dropView` — delete a view; payload: `TrinoViewDto`; returns null on success, error string if not found\n\nView identity: composite key of `(schemaName, tableName)`, both automatically lowercased.\n\n**Reports (reports.*):**\n\n- `reports.getReportConfigs` — list saved report configurations (GridConfigs); payload: userId; returns stream of `{id, creationDate}`\n- `reports.runReport` — execute a report; payload: `{configId, userId}`; returns reportId string\n- `reports.getReportDefinition` — get a saved GridConfig definition; anonymous context\n- `reports.getReportHistories` — completed non-failed executions as `Map<String, Any>`; anonymous context\n- `reports.getReportStatistics` — all executions as `DistributedReportInfoDto`; anonymous context\n- `reports.getReportGroups` — grouping headers for an execution; payload: `{reportId, groupingVersion, userId}`; anonymous context\n- `reports.getReportRows` — paginated data rows; payload: `{reportId, groupJsonBase64, startRow, endRow, userId}`; anonymous context\n- `reports.deleteReports` — delete report executions; authenticated context"
    },
    {
      "name": "CATALOG AND SCHEMA LAYOUT",
      "body": "In Trino, cyoda entity data is exposed as tables under the Trino catalog and schema configured by the Trino connector deployment. Table names match `tableName` fields in `TableConfigDto`. Each SQL table corresponds to one `uniformedPath` node in an Entity Model.\n\nA single Entity Model produces multiple tables:\n\n- One object table per object-level node (e.g., root `$`, `$.address`)\n- One detached array table per array node (path ending with `^`)\n- One JSON table per model (path = `json`)\n\nQuerying a table returns one row per entity (object and JSON tables) or one row per array element (detached array tables). The `entity_id` column is the entity UUID. The `point_time` column accepts a point-in-time value for historical queries."
    },
    {
      "name": "ERRORS",
      "body": "- `errors.BAD_REQUEST` — `400` — schema name too long (> 1024 chars), UUID is not time-based (version 1)\n- `404 Not Found` (RFC 7807) — schema not found by ID or name\n- `422 Unprocessable Entity` — default schema generation failed due to duplicate table or field names"
    },
    {
      "name": "EXAMPLES",
      "body": "**List all schemas:**\n\n```\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"https://cloud.cyoda.com/api/sql/schema/listAll\"\n```\n\n**Get schema by name:**\n\n```\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"https://cloud.cyoda.com/api/sql/schema/?schemaName=NOBEL_PRIZES\"\n```\n\n**Create default schema from all entity models:**\n\n```\ncurl -s -X PUT \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"https://cloud.cyoda.com/api/sql/schema/putDefault/Nobel_PRIZES\"\n```\n\n**Preview tables for a model (by model UUID):**\n\n```\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"https://cloud.cyoda.com/api/sql/schema/genTables/a1b2c3d4-e5f6-11ee-b789-0242ac120002\"\n```\n\n**Save a schema:**\n\n```\ncurl -s -X POST \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"schemaName\": \"NOBEL_PRIZES\",\n    \"tables\": [\n      {\n        \"tableName\": \"nobel_prize\",\n        \"metadataClassId\": \"a1b2c3d4-e5f6-11ee-b789-0242ac120002\",\n        \"uniformedPath\": \"$\",\n        \"fields\": [],\n        \"hidden\": false\n      }\n    ]\n  }' \\\n  \"https://cloud.cyoda.com/api/sql/schema/\"\n```\n\n**Delete a schema by name:**\n\n```\ncurl -s -X DELETE \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  \"https://cloud.cyoda.com/api/sql/schema/?schemaName=NOBEL_PRIZES\"\n```\n\n**Trino CLI connection (example; concrete JDBC URL is deployment-specific):**\n\n```\ntrino --server https://trino.cloud.cyoda.com \\\n      --user \"$TRINO_USER\" \\\n      --password \\\n      --catalog cyoda \\\n      --schema NOBEL_PRIZES \\\n      --execute \"SELECT entity_id, category, year FROM nobel_prize LIMIT 10\"\n```"
    },
    {
      "name": "SEE ALSO",
      "body": "- search\n- models\n- grpc\n- errors.BAD_REQUEST"
    }
  ],
  "see_also": [
    "search",
    "models",
    "grpc",
    "errors.BAD_REQUEST"
  ],
  "stability": "evolving",
  "actions": []
}
