Where to test JPQL queries

Back in Cuba platform I used the JMX console and got a persistence object and i was able to load and test JPQL queries from within the admin screen. How can I do the same with JMIX?
thank you.

You can do even better in your project.

Create a simple screen with SourceCodeEditor component:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://jmix.io/schema/ui/window"
        caption="msg://queryTestScreen.caption">
    <layout expand="codeField" spacing="true">
        <sourceCodeEditor id="codeField" width="100%"/>
        <comboBox id="entityComboBox" caption="Entity"/>
        <button id="testBtn" caption="Test"/>
    </layout>
</window>

Add code completion and data loading to it:

@UiController("QueryTestScreen")
@UiDescriptor("query-test-screen.xml")
public class QueryTestScreen extends Screen {

    @Autowired
    private SourceCodeEditor codeField;
    @Autowired
    private JpqlUiSuggestionProvider jpqlUiSuggestionProvider;
    @Autowired
    private DataManager dataManager;
    @Autowired
    private ComboBox<Class<?>> entityComboBox;
    @Autowired
    private MetadataTools metadataTools;

    @Subscribe
    public void onInit(InitEvent event) {
        codeField.setSuggester((source, text, cursorPosition) -> {
            if (codeField.getValue() == null) {
                return Collections.emptyList();
            }
            return jpqlUiSuggestionProvider.getSuggestions(
                    codeField.getValue(),
                    cursorPosition - 1,
                    codeField.getAutoCompleteSupport()
            );
        });

        Map<String, Class<?>> entities = new TreeMap<>();
        for (MetaClass metaClass : metadataTools.getAllJpaEntityMetaClasses()) {
            entities.put(metaClass.getName(), metaClass.getJavaClass());
        }
        entityComboBox.setOptionsMap(entities);
    }

    @Subscribe("testBtn")
    public void onTestBtnClick(Button.ClickEvent event) {
        if (codeField.getValue() != null) {
            List<?> list;
            if (entityComboBox.getValue() != null) {
                list = dataManager.load(entityComboBox.getValue()).query(codeField.getValue()).list();
            } else {
                list = dataManager.loadValues(codeField.getValue()).list();
            }
            System.out.println("Query results: " + list);
        }
    }
}

Moreover, you can add a user selection field and test query execution for different roles, by wrapping dataManager.load() with System Authentication.

2 Likes

Hi, is it possible to have this solution with JMIX 2.0?

Sure. Jmix 2 provides similar features:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<view xmlns="http://jmix.io/schema/flowui/view"
      title="msg://jpqlTestView.title">
    <layout>
        <codeEditor id="codeField" width="100%"/>
        <hbox>
            <comboBox id="entityComboBox" label="Entity"/>
            <button id="testBtn" text="Test" alignSelf="END"/>
        </hbox>
        <textArea id="resultsField" width="100%" minHeight="5em" height="100%"/>
    </layout>
</view>
package com.company.sample.view.jpqltest;


import com.company.sample.view.main.MainView;

import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.data.provider.DataProvider;
import com.vaadin.flow.data.provider.DataProviderListener;
import com.vaadin.flow.data.provider.Query;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.shared.Registration;
import io.jmix.core.DataManager;
import io.jmix.core.MetadataTools;
import io.jmix.core.metamodel.model.MetaClass;
import io.jmix.flowui.component.codeeditor.CodeEditor;
import io.jmix.flowui.component.codeeditor.autocomplete.JpqlUiSuggestionProvider;
import io.jmix.flowui.component.combobox.JmixComboBox;
import io.jmix.flowui.component.textarea.JmixTextArea;
import io.jmix.flowui.kit.component.ComponentUtils;
import io.jmix.flowui.kit.component.button.JmixButton;
import io.jmix.flowui.view.*;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Route(value = "jpql-test-view", layout = MainView.class)
@ViewController(id = "JpqlTestView")
@ViewDescriptor(path = "jpql-test-view.xml")
public class JpqlTestView extends StandardView {

    @Autowired
    private JpqlUiSuggestionProvider jpqlSuggestionProvider;
    @Autowired
    private MetadataTools metadataTools;
    @Autowired
    private DataManager dataManager;

    @ViewComponent
    private CodeEditor codeField;
    @ViewComponent
    private JmixComboBox<Class<?>> entityComboBox;
    @ViewComponent
    private JmixTextArea resultsField;

    @Subscribe
    public void onInit(final InitEvent event) {
        codeField.setSuggester(context ->
                jpqlSuggestionProvider.getSuggestions(
                        context,
                        context.getText(),
                        context.getCursorPosition() - 1
                )
        );

        Map<Class<?>, String> entities = new LinkedHashMap<>();
        for (MetaClass metaClass : metadataTools.getAllJpaEntityMetaClasses()) {
            entities.put(metaClass.getJavaClass(), metaClass.getName());
        }
        ComponentUtils.setItemsMap(entityComboBox, entities);
    }

    @Subscribe(id = "testBtn", subject = "clickListener")
    public void onTestBtnClick(final ClickEvent<JmixButton> event) {
        if (codeField.getValue() != null) {
            List<?> list;
            if (entityComboBox.getValue() != null) {
                list = dataManager.load(entityComboBox.getValue()).query(codeField.getValue()).list();
            } else {
                list = dataManager.loadValues(codeField.getValue()).list();
            }
            resultsField.setValue(list.stream().map(Object::toString).collect(Collectors.joining("\n")));
            System.out.println("Query results: " + list);
        }
    }
}

image

Regards,
Konstantin

1 Like