Class JpqlExecutionService

java.lang.Object
io.jmix.aitools.dataload.execution.JpqlExecutionService

@Component("aitls_JpqlExecutionService") public class JpqlExecutionService extends Object
Validates, repairs and executes a generated JPQL query, returning the fetched rows.
  • Field Details

  • Constructor Details

    • JpqlExecutionService

      public JpqlExecutionService()
  • Method Details

    • execute

      public JpqlExecutionResult execute(JpqlExecutionRequest request)
      Validates, repairs if needed and executes the query described by the request.

      This method runs the full pipeline: it validates and (if needed) repairs the query, enforces data-access constraints for every entity the query reads (see JpqlAccessSupport), converts the parameters to their Java types and runs the query through UnconstrainedDataManager.loadValues(io.jmix.core.ValueLoadContext). One extra row is fetched to detect whether more results are available. A query that cannot be narrowed as the current user's permissions require is not executed; the result carries the reason as its execution error.

      Parameters:
      request - query to execute together with its parameters and paging hints
      Returns:
      result with the fetched rows on success, or with validation/execution failure details
      Throws:
      AccessDeniedException - if the current user may not read an entity the query reads
    • applyAccessConstraints

      protected String applyAccessConstraints(GeneratedJpqlResult generatedResult)
      Applies the current user's access constraints to the generated query, returning the text to execute: the query itself, or the query with the row-level conditions of the entities it reads woven in.
      Parameters:
      generatedResult - validated generated query with its parameters
      Returns:
      the text to execute
      Throws:
      AccessDeniedException - if the current user may not read an entity the query reads
      JpqlAccessConstraintException - if the query cannot be narrowed as the user's permissions require, or the constraints cannot be applied to it
    • withJpql

      protected GeneratedJpqlResult withJpql(GeneratedJpqlResult generatedResult, String jpql)
      Returns the generated result with the given text to execute. The result returned to the caller keeps the validated text, so the model never sees the row-level conditions applied for execution.
      Parameters:
      generatedResult - validated generated result
      jpql - text to execute
      Returns:
      the generated result itself when the text is unchanged, otherwise a copy carrying the text
    • toExecutionParameters

      protected List<JpqlExecutionParameter> toExecutionParameters(GeneratedJpqlResult generatedJpqlResult)
    • resolveDeniedSelectedIndexes

      protected List<Integer> resolveDeniedSelectedIndexes(String jpqlQuery)
      Resolves the positions of the selected columns the current user is not allowed to read.
      Parameters:
      jpqlQuery - query whose data access is being checked
      Returns:
      positions (in select-clause order) of the denied columns, or an empty list if all selected columns are readable
      Throws:
      AccessDeniedException - if the current user cannot read the queried entity
    • resolveExcludedSelectedIndexes

      protected List<Integer> resolveExcludedSelectedIndexes(String jpqlQuery)
      Resolves the positions of the selected columns that must be dropped from the result: those the current user is not allowed to read, plus those mapping to an attribute hidden from the AI (annotated Secret or ExcludeFromAi). The hidden-attribute guard is defense in depth — such an attribute is already unknown to introspection and rejected by JPQL validation — so its value is never returned even if a query reaches execution through another path.
      Parameters:
      jpqlQuery - query whose selected columns are being resolved
      Returns:
      positions (in select-clause order) of the columns to drop, without duplicates
      Throws:
      AccessDeniedException - if the current user cannot read the queried entity
    • resolveHiddenSelectedIndexes

      protected List<Integer> resolveHiddenSelectedIndexes(String jpqlQuery)
      Resolves the positions of the selected columns that map to an attribute hidden from the AI (annotated Secret or ExcludeFromAi).
      Parameters:
      jpqlQuery - query whose selected columns are being inspected
      Returns:
      positions (in select-clause order) of the hidden columns, or an empty list when the query cannot be parsed
    • isHiddenSelectedPath

      protected boolean isHiddenSelectedPath(QueryParser.QueryPath queryPath)
    • retainPermittedProperties

      protected List<String> retainPermittedProperties(List<String> resultProperties, List<Integer> excludedSelectedIndexes)
      Returns the result properties that stay in the result, dropping the ones at the excluded select positions (denied by security or mapping to an attribute hidden from the AI).
      Parameters:
      resultProperties - result property names in select-clause order
      excludedSelectedIndexes - positions of the columns to drop
      Returns:
      the retained property names, in their original order
    • retainProperties

      protected List<Map<String,@Nullable Object>> retainProperties(List<Map<String,@Nullable Object>> rows, List<String> resultProperties, List<String> retainedProperties)
      Rebuilds each row keeping only the retained properties, in their original order. Null values are kept distinct from empty strings.
      Parameters:
      rows - fetched rows keyed by all result properties
      resultProperties - all result property names the rows are keyed by
      retainedProperties - property names to keep in the output rows
      Returns:
      rows containing only the retained properties, or the original rows if nothing is dropped
    • executeQuery

      protected JpqlExecutionService.ExecutionRows executeQuery(JpqlExecutionRequest request, GeneratedJpqlResult generatedJpqlResult, Map<String,Object> executionParameters, Integer maxResults, @Nullable Integer firstResult)
    • toValueRow

      protected Map<String,@Nullable Object> toValueRow(KeyValueEntity keyValueEntity, List<String> resultProperties)
    • getEffectiveMaxResult

      protected Integer getEffectiveMaxResult(@Nullable Integer maxResults)
    • createExecutionRows

      protected JpqlExecutionService.ExecutionRows createExecutionRows(List<Map<String,@Nullable Object>> rows, boolean hasMore)