Capítulo 4: Consultando Datos con Opciones del Sistema
Last updated
Last updated
Una de las características más potentes de OData es su conjunto estandarizado de Opciones de Consulta del Sistema (System Query Options). Estas opciones, añadidas como parámetros a la URI de una solicitud GET, permiten a los clientes refinar y dar forma a los datos devueltos por el servidor, solicitando exactamente lo que necesitan de manera flexible y eficiente.6 Esto reduce la carga en el cliente, minimiza el tráfico de red y permite construir consultas complejas directamente en la URL.
Las opciones de consulta del sistema son parámetros de consulta de URL prefijados con el signo de dólar ($).6 Se añaden a la URI de un recurso (generalmente un conjunto de entidades o una propiedad de navegación de colección) después de un signo de interrogación (?) y se separan entre sí mediante ampersands (&).6
Ejemplo: serviceRoot/Products?$filter=Price lt 10.00&$orderby=Name desc&$top=5
Esta solicitud recupera productos (Products), filtra aquellos cuyo precio (Price) es menor que 10.00, ordena los resultados por nombre (Name) en orden descendente (desc) y devuelve solo los primeros 5 resultados.
Las opciones de consulta más importantes incluyen:
$filter: Selecciona un subconjunto de recursos basado en una expresión booleana.
$select: Limita las propiedades devueltas para cada recurso.
$expand: Incluye representaciones de recursos relacionados en línea.
$orderby: Especifica el orden de los recursos en el resultado.
$top: Devuelve solo los primeros 'n' recursos.
$skip: Omite los primeros 'n' recursos.
$count: Devuelve el número total de recursos en el conjunto (con o sin los datos).
$search (V4): Realiza una búsqueda de texto libre en los recursos.
$apply (V4): Aplica transformaciones como agrupación y agregación.
Es importante notar que, si bien algunas opciones como $select o $expand pueden ser manejadas en gran medida por el framework de SAP Gateway, otras como $filter, $orderby, $top, $skip, $count (o $inlinecount en V2), y $skiptoken generalmente requieren implementación específica en la lógica del backend (clase DPC en SAP Gateway) para funcionar correctamente.16
La opción $filter permite a los clientes solicitar un subconjunto de los recursos de una colección, incluyendo solo aquellos para los cuales una expresión booleana especificada evalúa a true.6 Es análogo a la cláusula WHERE en SQL.
Sintaxis: $filter=<expresión_booleana>
Expresión Booleana: Se construye utilizando:
Nombres de Propiedad: Los nombres de las propiedades de la entidad (ej. Price, Name, Category/Name).
Literales: Valores como cadenas ('Notebooks'), números (10.00), booleanos (true), fechas (2023-10-27), etc..38
Operadores Lógicos: eq (igual), ne (no igual), gt (mayor que), lt (menor que), ge (mayor o igual que), le (menor o igual que), and, or, not.6
Operadores Aritméticos: add, sub, mul, div, mod.
Funciones Canónicas: Funciones predefinidas como startswith(PropertyName, 'valor'), endswith(PropertyName, 'valor'), contains(PropertyName, 'valor'), substringof('valor', PropertyName) (V2), length(PropertyName), year(DateProperty), month(DateProperty), day(DateProperty), toupper(StringProperty), tolower(StringProperty), etc..6
Paréntesis: Para agrupar expresiones y controlar la precedencia.
Expresiones Lambda (V4): Operadores como any y all para filtrar sobre propiedades de colección (ej. Emails/any(e: e eq 'test@example.com')).
Ejemplos:
$filter=Price lt 10.00 (Precio menor que 10.00).6
$filter=Category eq 'Notebooks' (Categoría es 'Notebooks').16
$filter=startswith(Name, 'M') (Nombre comienza con 'M').6
$filter=Price ge 10.00 and Price le 20.00 (Precio entre 10.00 y 20.00 inclusive).
$filter=contains(Location/Address, 'San Francisco') (La propiedad compleja Location, subpropiedad Address, contiene 'San Francisco').26
$filter=Emails/any(s:endswith(s, 'contoso.com')) (Cualquier email en la colección Emails termina con 'contoso.com').26
Implementación en SAP Gateway: Requiere lógica en el método GET_ENTITYSET de la DPC para interpretar la expresión $filter (accesible a través de io_tech_request_context->get_filter()) y aplicarla a la consulta de base de datos.16
La opción $select permite a los clientes especificar un subconjunto de propiedades a incluir en la respuesta para cada recurso.16 Esto es útil para reducir el tamaño del payload y mejorar el rendimiento cuando no se necesitan todas las propiedades de una entidad.
Sintaxis: $select=Propiedad1,Propiedad2,PropiedadCompleja/SubPropiedad
Descripción: Se proporciona una lista separada por comas de las propiedades que se desean incluir. Se pueden seleccionar propiedades de tipos complejos anidados. También se puede usar * para indicar todas las propiedades estructurales, y combinarlo con nombres de propiedades de navegación para controlar la expansión.
Ejemplo:
$select=Name,Price (Devuelve solo las propiedades Name y Price).
$select=Rating,ReleaseDate
$select=Customer/Name,OrderDate (Selecciona la propiedad Name de la entidad relacionada Customer y la propiedad OrderDate de la entidad principal).
Implementación en SAP Gateway: Generalmente manejado por el framework.16 El framework filtra las propiedades solicitadas antes de serializar la respuesta. Sin embargo, para una optimización máxima, la implementación del backend podría usar la información de $select para leer solo las columnas necesarias de la base de datos.
La opción $expand permite a los clientes solicitar recursos relacionados y que sus representaciones se incluyan en línea dentro de la respuesta del recurso principal.1 Esto evita la necesidad de realizar solicitudes separadas para obtener datos relacionados, reduciendo la latencia y el número de viajes de red.
Sintaxis: $expand=NavigationProperty1,NavigationProperty2($select=PropA;$filter=...),NavigationProperty3
Descripción: Se proporciona una lista separada por comas de las propiedades de navegación que se desean expandir.
Opciones de Expansión (V4): OData V4 mejora $expand permitiendo aplicar otras opciones de consulta ($filter, $select, $orderby, $top, $skip, $count, $search, $levels, incluso otro $expand anidado) a los datos expandidos, encerradas entre paréntesis y separadas por punto y coma.1
$levels=n: Permite expansiones recursivas hasta un nivel n o $levels=max para expansión completa (usar con precaución).
Ejemplos:
$expand=Products (Incluye la colección de Productos relacionados con cada Categoría).16
$expand=Category (Incluye la entidad Category relacionada con cada Producto).
$expand=Customer,OrderLines($select=ProductID,Quantity) (Incluye el Cliente y las Líneas de Pedido, pero solo las propiedades ProductID y Quantity de las líneas).
$expand=Products($orderby=Price desc;$top=5) (V4: Incluye los 5 productos más caros relacionados con cada categoría).1
$expand=DirectReports($levels=3) (V4: Expande los subordinados directos, sus subordinados, y los subordinados de estos).
Implementación en SAP Gateway: El framework de Gateway generalmente maneja la expansión básica.16 Lee los datos principales y luego realiza lecturas separadas (o joins si está optimizado) para obtener los datos relacionados según las propiedades de navegación especificadas. La implementación se realiza a través de los métodos GET_EXPANDED_ENTITY y GET_EXPANDED_ENTITYSET en la DPC, aunque el framework a menudo proporciona una implementación genérica.17 Un uso excesivo o ineficiente de $expand puede impactar negativamente el rendimiento, por lo que a veces se prefiere usar $batch para obtener datos relacionados.14
La opción $orderby especifica el orden en que se deben devolver los ítems de una colección.16
Sintaxis: $orderby=Propiedad1 [asc|desc], Propiedad2 [asc|desc],...
Descripción: Se proporciona una lista separada por comas de propiedades por las cuales ordenar. Opcionalmente, se puede especificar asc (ascendente, por defecto) o desc (descendente) para cada propiedad. El orden se aplica secuencialmente.
Ejemplos:
$orderby=Name asc (Ordena por Name ascendente).
$orderby=Category desc, Price asc (Ordena primero por Category descendente, y luego por Price ascendente para ítems con la misma categoría).16
Implementación en SAP Gateway: Requiere implementación en la DPC.16 La lógica en GET_ENTITYSET debe obtener los criterios de ordenación de io_tech_request_context->get_orderby() y aplicarlos a la consulta de base de datos (cláusula ORDER BY).
Las opciones $top y $skip se utilizan juntas para implementar la paginación del lado del cliente, permitiendo solicitar subconjuntos específicos (páginas) de una colección grande.17
$top=n: Restringe la respuesta a los primeros n ítems de la colección (después de aplicar $filter y $orderby).16
$skip=m: Omite los primeros m ítems de la colección (después de aplicar $filter y $orderby) y devuelve los siguientes.16
Sintaxis Combinada: $skip=m&$top=n (Omite m ítems, devuelve los siguientes n).
Ejemplos:
$top=10 (Devuelve los primeros 10 ítems).
$skip=20&$top=10 (Devuelve los ítems del 21 al 30).
Implementación en SAP Gateway: Requieren implementación en la DPC.16 La lógica en GET_ENTITYSET debe obtener los valores de io_tech_request_context->get_top() y io_tech_request_context->get_skip() y aplicarlos a la consulta de base de datos (por ejemplo, usando UP TO n ROWS y OFFSET m en ABAP SQL, o seleccionando todo y luego procesando el slice en memoria, aunque esto último es menos eficiente para grandes volúmenes).17
La opción $count (introducida en V4, reemplazando a $inlinecount=allpages de V2/V3 en funcionalidad) se utiliza para obtener el número total de ítems en una colección.12
Sintaxis (V4):
/SalesOrders/$count: Devuelve solo el recuento como un valor escalar.
$count=true: Se añade a una solicitud GET de una colección (ej. /SalesOrders?$count=true). La respuesta incluye el recuento junto con los datos solicitados (posiblemente paginados por $top/$skip). El recuento se encuentra en la propiedad @odata.count.
Sintaxis (V2 - Inline Count):
$inlinecount=allpages: Se añade a una solicitud GET. La respuesta incluye una propiedad (ej. __count en JSON) con el número total de ítems que coinciden con el filtro, ignorando $top y $skip.16
$inlinecount=none: (Por defecto) No se incluye el recuento.
Ejemplos:
V4: serviceRoot/Products?$count=true&$filter=Price gt 100 (Devuelve los productos con precio > 100 y el recuento total de dichos productos).
V2: serviceRoot/Products?$inlinecount=allpages&$filter=Price gt 100 (Similar al anterior, pero el recuento está en __count).
Importante: El recuento devuelto por $count=true o $inlinecount=allpages debe reflejar el número total de entidades que satisfacen cualquier $filter o $search aplicado, pero NO debe ser afectado por $top, $skip, u $orderby.19
Implementación en SAP Gateway: Requiere implementación en la DPC.16 La lógica en GET_ENTITYSET debe calcular el recuento total (generalmente con una consulta SELECT COUNT(*) separada con la misma cláusula WHERE derivada del $filter) y establecer el valor en es_response_context-inlinecount (para V2/$inlinecount) o manejarlo según las convenciones V4 ($count=true).
Introducida en OData V4, la opción $search proporciona una capacidad de búsqueda de texto libre en una colección.1 A diferencia de $filter que busca coincidencias exactas o parciales en propiedades específicas, $search aplica una expresión de búsqueda a un conjunto predeterminado (o a todas) las propiedades textuales de una entidad.
Sintaxis: $search=<expresión_de_búsqueda>
Expresión de Búsqueda: Puede ser una simple palabra, una frase (entre comillas), o términos combinados con operadores lógicos como AND, OR, NOT. La sintaxis exacta y las capacidades (ej. búsqueda por proximidad, comodines) dependen de la implementación del servicio.
Ejemplo:
$search=Mountain (Busca entidades que contengan la palabra "Mountain").
$search="Mountain Bike" (Busca la frase exacta).
$search=electronics AND NOT television (Busca entidades relacionadas con electrónica pero no televisión).
Implementación en SAP Gateway: Requiere implementación específica en la DPC. La lógica en GET_ENTITYSET debe obtener el término de búsqueda de io_tech_request_context->get_search_string() y aplicarlo a la consulta subyacente, posiblemente utilizando capacidades de búsqueda de texto completo de la base de datos (como HANA Fuzzy Search) o lógica personalizada.
La opción $apply, también introducida en OData V4 y definida en la extensión de Agregación de Datos OData, permite realizar transformaciones complejas en el lado del servidor, como agrupar (groupby) y agregar (aggregate) datos.21 Es extremadamente potente para escenarios analíticos.
Sintaxis: $apply=<secuencia_de_transformaciones>
Transformaciones Comunes:
aggregate(<expresión> with <método> as <alias>,...): Calcula valores agregados.
Métodos estándar: sum, min, max, average, countdistinct.50
Expresión $count as <alias>: Cuenta el número de ítems agregados.50
groupby((Propiedad1, Propiedad2,...), aggregate(...)): Agrupa los resultados por las propiedades especificadas y luego aplica agregaciones a cada grupo.49
filter(...): Filtra el conjunto de resultados (similar a $filter).
orderby(...): Ordena el conjunto de resultados (similar a $orderby).
top(...) / skip(...): Aplica paginación (similar a $top/$skip).
compute(<expresión> as <alias>): Calcula nuevas propiedades.
expand(...): Expande navegaciones.
Otras: concat, search, nest, topcount, bottomcount, etc..50
Secuencia: Las transformaciones se aplican en el orden en que aparecen, separadas por /.
Ejemplos:
$apply=aggregate(Amount with sum as TotalSales) (Calcula la suma total de Amount).51
$apply=groupby((Category/CategoryName), aggregate(Price with average as AveragePrice)) (Agrupa por nombre de categoría y calcula el precio promedio para cada una).54
$apply=filter(SalesAmount gt 1000)/groupby((Region), aggregate(SalesAmount with sum as RegionalSales)) (Filtra ventas > 1000, luego agrupa por región y suma las ventas).
$apply=groupby((ProductId), aggregate($count as NumberOfSales)) (Agrupa por producto y cuenta cuántas ventas hubo para cada uno).54
Implementación en SAP Gateway: Requiere una implementación significativa en la DPC. El framework estándar de Gateway (especialmente para V2) no soporta $apply de forma nativa. La implementación implicaría parsear la secuencia $apply, traducir las transformaciones a consultas complejas (posiblemente utilizando capacidades analíticas de HANA a través de CDS Views o AMDPs) y devolver los resultados agregados en la estructura esperada. Dada la complejidad, a menudo se prefiere exponer vistas CDS analíticas pre-agregadas como servicios OData en lugar de implementar $apply genéricamente en SEGW.
El dominio de estas opciones de consulta del sistema es clave para consumir servicios OData de manera eficiente y flexible, permitiendo a las aplicaciones cliente obtener precisamente los datos que necesitan con una sobrecarga mínima.