Main Content

Create Custom Queries

With the CI/CD Automation for Simulink Check support package, you can define a development and verification process for your team by using a process model. You can use queries to find artifacts relevant to your tasks and processes. The support package contains several built-in queries that you can reconfigure and use to find artifacts in your project, but if you need to perform other actions or always want to use a reconfigured version of a built-in query, you can create and add custom queries to your process model.

To find artifacts in your project, you can use the built-in queries that ship with the support package or you can create your own custom queries. Use the built-in queries where possible. If your use case requires custom queries, use the following steps to create a custom query. Note that to reconfigure the functionality of a built-in task, your custom queries can inherit from a built-in query.

After you create a custom query, you can use that query as an input query for a task to modify or filter the task inputs.

Choose Superclass for Custom Query

There are two ways to define custom queries:

  • Inherit from a built-in query — Use this approach when there is a built-in query that is similar to the custom query that you want to create. When you inherit from a built-in query, like padv.builtin.query.FindArtifacts, your custom query inherits the functionality of that query, but then you can override the properties and methods of the class to fit your needs.

  • Inherit from padv.Query — Use this approach if your custom query needs to find artifacts in a way that is not similar to a built-in query. padv.Query is the base class of the built-in queries, so you must completely define the functionality of the query.

Define and Use Custom Query in Process

  1. Create a new MATLAB® class in your project.

    Tip

    Namespaces can help you organize the class definition files for your custom queries. In the root of your project, create a folder +processLibrary with a subfolder +query and save your class in that folder.

    To share your custom queries across multiple process models in different projects, consider creating a referenced project that contains your folders and class definition files. Your main projects can then use the referenced project as a shared process library.

  2. Use one of these approaches to define your custom query:

    • If you are inheriting from a built-in query, you can replace the contents of your class file with this example code:

      classdef MyCustomQuery<padv.builtin.query.FindArtifacts
          % query definition goes in this class
          % by default, this query finds all artifacts in the project
          methods
              function obj = MyCustomQuery(NameValueArgs)
                  arguments
                      NameValueArgs.Name = "MyCustomQuery";
                  end
              end
          end
      end
      This example query inherits from the built-in query padv.builtin.query.FindArtifacts, but you can change that line of code to inherit from another built-in query. Use the properties of the query to specify which sets of artifacts you want the query to return. If you want to override the run method for a built-in query, check which input arguments the run method for the built-in query accepts and use the same method signature inside your custom query. For more information, see Built-In Queries.

    • If you are inheriting from padv.Query, you can replace the contents of your class file with this example code:

      classdef MyCustomQuery < padv.Query
      
          methods
              function obj = MyCustomQuery(NameValueArgs)
                  obj@padv.Query("MyCustomQuery");
              end
      
              function artifacts = run(obj,~)
                  artifacts = padv.Artifact.empty;
                      % Core functionality of the query goes here
                  % artifacts = padv.Artifact(artifactType,...
                      % padv.util.ArtifactAddress(fullfile(fileparts));
                  
              end
          end
      end
      A query must have:

      • a unique name, specified using the Name property

      • a run function that returns either a padv.Artifact object or an array of padv.Artifact objects. For more information, see padv.Artifact and Example Custom Queries.

      Note

      The digital thread only tracks changes to specific types of artifacts. For information on supported artifact types, see Valid Artifact Types. If there is an artifact in your project that the padv.builtin.query.FindArtifacts query does not find, the digital thread cannot detect changes to that artifact. If you create custom queries that return padv.Artifact objects with unsupported artifact types, the digital thread will not detect changes to those artifacts. This behavior can impact whether changes to these artifacts cause a task to be marked as outdated. To see a list of the files the digital thread is tracking in your project, see Find Artifacts that Digital Thread Tracks.

  3. You can test your custom query in the MATLAB Command Window executing the run function. Note that your project needs to be open for the query to find artifacts. For example, for a query MyCustomQuery saved in the namespace processLibrary.query:

    run(processLibrary.query.MyCustomQuery)

  4. You can use your custom query in your process model. For example, you can control which artifacts a task iterates over by using your custom query as the iteration query for a task:

    function processmodel(pm)
        % Defines the project's processmodel
    
        arguments
            pm padv.ProcessModel
        end
    
        t = addTask(pm,"MyCustomTask",...
            IterationQuery = processLibrary.query.MyCustomQuery);
    
    end
    This example assumes that you saved your class file in the +query folder inside the +processLibrary folder.

  5. You can confirm which artifacts your task iterates over by opening Process Advisor. In the MATLAB Command Window, enter:

    processAdvisorWindow
    The artifacts that the task iterates over appear under the task name in the Tasks column.

    Task iterations under "MyCustomTask" in Tasks column

Example Custom Queries

Run Task on Data Dictionaries in Project

Suppose you want to find each of the data dictionaries in your project. There are no built-in queries that perform this functionality by default, but there is a built-in query padv.builtin.query.FindArtifacts that can find artifacts that meet certain search criteria. Effectively you can create your own version of the built-in query, but specialized to only find data dictionaries. You can create a class-based, custom query that inherits from padv.builtin.query.FindArtifacts and specifies the ArtifactType argument as a Simulink® data dictionary.

classdef FindSLDDs<padv.builtin.query.FindArtifacts
    %FindSLDDs This query is like FindArtifacts,
    % but only returns data dictionaries.
    methods
        function obj = FindSLDDs(NameValueArgs)
            arguments
                NameValueArgs.ArtifactType string = "sl_data_dictionary_file";
                NameValueArgs.Name = "FindSLDDs";
            end
            obj.ArtifactType = NameValueArgs.ArtifactType;
        end
    end
end

The example class FindSLDDs inherits its properties and run function from the built-in query padv.builtin.query.FindArtifacts, but specifies a unique Name and ArtifactType. The ArtifactType is specified as sl_data_dictionary_file because that is the artifact type associated with Simulink data dictionary files. For a list of valid artifact types, see padv.builtin.query.FindArtifacts.

You can have a task run once for each data dictionary in your project by using the custom query as the iteration query for the task.

function processmodel(pm)
    % Defines the project's processmodel

    arguments
        pm padv.ProcessModel
    end

    t = addTask(pm,"MyCustomTask",...
        IterationQuery = processLibrary.query.FindSLDDs);

end

Tasks column showing data dictionaries under "MyCustomTask"

Sort Artifacts in Specific Order

By default, queries sort artifacts alphabetically by the artifact address. If you want your query to sort artifacts in a different order, you can override the internal sortArtifacts method in a subclass that defines a custom sort behavior. For example:

classdef FindFileSorted < padv.builtin.query.FindArtifacts    
    methods
        function obj = FindFileSorted(options)
            arguments
                options.ArtifactType string
                options.IncludeLabel string
                options.ExcludeLabel string
                options.IncludePath string
                options.ExcludePath string
                options.InProject boolean
                options.FilterSubFileArtifacts boolean
            end
            fwdoptions = namedargs2cell(options);
            obj@padv.builtin.query.FindArtifacts(fwdoptions{:});
        end
    end
    methods(Access = protected)
        % Overload the default sort artifacts logic, in this case
        % Sorting artifacts based upon their string length rather than
        % Alphabetically
        function sortedArtifacts = sortArtifacts(~, artifacts)
            if isempty(artifacts)
                sortedArtifacts = artifacts;
                return;
            end
            namesToSort = arrayfun(@(art) art.ArtifactAddress.getFileAddress,artifacts);
            [~,idx] = sort(strlength(namesToSort));
            sortedArtifacts = artifacts(idx);
        end
    end
end

Note

If you override sortArtifacts, make sure that your implementation only changes the order of the artifacts, not the data type or structure. Do not use sortArtifacts to add or remove artifacts from the query results.

Run Validation Scripts on Spreadsheets

Suppose that your project contains several Excel® spreadsheets and that for each spreadsheet, you have a validation script with the same name as the spreadsheet. You can find the validation scripts by using a custom query and then you can run the validation script on each spreadsheet by using a custom task. For example, the following example custom query searches through the artifacts in the project to find if there are any scripts that have the same name as the iteration artifact.

classdef FindValidationFiles < padv.Query
    
    methods
        function obj = FindValidationFiles(NameValueArgs)
            arguments
                NameValueArgs.Name string = string.empty;
                NameValueArgs.Title string = "Find validation files";
            end

            obj@padv.Query(NameValueArgs.Name, Title=NameValueArgs.Title);

            % Named Query
            obj.CanBeUsedAsInputQuery = true;
            obj.CanBeUsedAsIterationQuery = true;
        end
        
        function paArtifact = run(~,iterationArtifact)
            paArtifact = padv.Artifact.empty;

            % Get Name of iteration artifact
            [~,name] = fileparts(iterationArtifact.ArtifactAddress.getFileAddress());
            % Find validation script with same name as iteration artifact
            validationFileName = strcat(name, ".m");
            filePath = which(validationFileName);
            if ~isempty(filePath)
                paArtifact = padv.Artifact("xls_validation_file",filePath);
            end
        end

    end
end

In the process model, you can add the custom query as an input query for your custom task so that if you make a change to the validation script, the task iteration for that spreadsheet automatically becomes outdated. For example, this example process model uses the built-in query FindArtifacts to find the spreadsheets, specifies that a custom task named RunValidationScript must iterate over each spreadsheet returned by the FindArtifacts query, and then adds the custom query as an input query for the task.

function processmodel(pm)
    % Defines the project's processmodel

    arguments
        pm padv.ProcessModel
    end

    findSpreadsheets = padv.builtin.query.FindArtifacts(IncludePathRegex = "Spreadsheet.*\.xlsx");
    validationTask = pm.addTask(RunValidationScript(IterationQuery=findSpreadsheets));
    validationTask.addInputQueries(FindValidationFiles);

end

The validation task automatically becomes outdated if you make changes to the validation scripts because you specified the custom query FindValidationFiles as an input query for the task.

Process Advisor UI showing that the RunValidationScript task is outdated because the validation script for SpreadsheetA was changed

See Also

| | | |

Related Topics