mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
initial build of table meta-data, query, and count specs, IO, executors
This commit is contained in:
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.executors;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.permissions.TablePermissionSubType;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableCountInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableCountOutputInterface;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableCountExecutor extends AbstractMiddlewareExecutor<TableCountInput, TableCountOutputInterface>
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(TableCountExecutor.class);
|
||||
|
||||
protected static final Integer DEFAULT_QUERY_TIMEOUT_SECONDS = 60;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void execute(TableCountInput input, TableCountOutputInterface output) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
ExecutorSessionUtils.setTableVariantInSession(input.getTableVariant());
|
||||
|
||||
CountInput countInput = new CountInput();
|
||||
countInput.setTableName(input.getTableName());
|
||||
|
||||
PermissionsHelper.checkTablePermissionThrowing(countInput, TablePermissionSubType.READ);
|
||||
|
||||
countInput.setFilter(input.getFilter());
|
||||
countInput.setQueryJoins(input.getJoins());
|
||||
countInput.setIncludeDistinctCount(input.getIncludeDistinct());
|
||||
countInput.withQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND);
|
||||
|
||||
if(countInput.getFilter() != null)
|
||||
{
|
||||
// todo
|
||||
countInput.getFilter().interpretValues(Collections.emptyMap());
|
||||
}
|
||||
|
||||
CountOutput countOutput = new CountAction().execute(countInput);
|
||||
output.setCount(ValueUtils.getValueAsLong(countOutput.getCount()));
|
||||
|
||||
if(BooleanUtils.isTrue(input.getIncludeDistinct()))
|
||||
{
|
||||
output.setDistinctCount(ValueUtils.getValueAsLong(countOutput.getDistinctCount()));
|
||||
}
|
||||
}
|
||||
catch(QException e)
|
||||
{
|
||||
QUserFacingException userFacingException = ExceptionUtils.findClassInRootChain(e, QUserFacingException.class);
|
||||
if(userFacingException != null)
|
||||
{
|
||||
throw userFacingException;
|
||||
}
|
||||
|
||||
throw (e);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QException("Unexpected error occurred while executing count query: " + e.getMessage(), e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.executors;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.metadata.TableMetaDataAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.permissions.TablePermissionSubType;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.TableMetaDataOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableMetaDataInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableMetaDataOutputInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableMetaDataExecutor extends AbstractMiddlewareExecutor<TableMetaDataInput, TableMetaDataOutputInterface>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void execute(TableMetaDataInput input, TableMetaDataOutputInterface output) throws QException
|
||||
{
|
||||
com.kingsrook.qqq.backend.core.model.actions.metadata.TableMetaDataInput tableMetaDataInput = new com.kingsrook.qqq.backend.core.model.actions.metadata.TableMetaDataInput();
|
||||
|
||||
String tableName = input.getTableName();
|
||||
QTableMetaData table = QContext.getQInstance().getTable(tableName);
|
||||
if(table == null)
|
||||
{
|
||||
throw (new QNotFoundException("Table [" + tableName + "] was not found."));
|
||||
}
|
||||
|
||||
tableMetaDataInput.setTableName(tableName);
|
||||
PermissionsHelper.checkTablePermissionThrowing(tableMetaDataInput, TablePermissionSubType.READ);
|
||||
|
||||
TableMetaDataAction tableMetaDataAction = new TableMetaDataAction();
|
||||
TableMetaDataOutput tableMetaDataOutput = tableMetaDataAction.execute(tableMetaDataInput);
|
||||
|
||||
output.setTableMetaData(tableMetaDataOutput.getTable());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.executors;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.permissions.TablePermissionSubType;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||
import com.kingsrook.qqq.backend.javalin.QJavalinMetaData;
|
||||
import com.kingsrook.qqq.backend.javalin.QJavalinUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableQueryInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableQueryOutputInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableQueryExecutor extends AbstractMiddlewareExecutor<TableQueryInput, TableQueryOutputInterface>
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(TableQueryExecutor.class);
|
||||
|
||||
protected static final Integer DEFAULT_QUERY_TIMEOUT_SECONDS = 60;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void execute(TableQueryInput input, TableQueryOutputInterface output) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
ExecutorSessionUtils.setTableVariantInSession(input.getTableVariant());
|
||||
|
||||
QueryInput queryInput = new QueryInput();
|
||||
queryInput.setTableName(input.getTableName());
|
||||
|
||||
PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ);
|
||||
|
||||
queryInput.setFilter(input.getFilter());
|
||||
queryInput.setQueryJoins(input.getJoins());
|
||||
queryInput.setShouldGenerateDisplayValues(true);
|
||||
queryInput.setShouldTranslatePossibleValues(true);
|
||||
queryInput.setTimeoutSeconds(DEFAULT_QUERY_TIMEOUT_SECONDS); // todo param
|
||||
queryInput.withQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND);
|
||||
|
||||
if(queryInput.getFilter() != null)
|
||||
{
|
||||
// todo
|
||||
queryInput.getFilter().interpretValues(Collections.emptyMap());
|
||||
}
|
||||
|
||||
if(queryInput.getFilter() == null || queryInput.getFilter().getLimit() == null)
|
||||
{
|
||||
QJavalinUtils.handleQueryNullLimit(QJavalinMetaData.of(QContext.getQInstance()), queryInput, null);
|
||||
}
|
||||
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
|
||||
// todo not sure QValueFormatter.setBlobValuesToDownloadUrls(QContext.getQInstance().getTable(input.getTableName()), queryOutput.getRecords());
|
||||
|
||||
output.setRecords(queryOutput.getRecords());
|
||||
}
|
||||
catch(QException e)
|
||||
{
|
||||
QUserFacingException userFacingException = ExceptionUtils.findClassInRootChain(e, QUserFacingException.class);
|
||||
if(userFacingException != null)
|
||||
{
|
||||
throw userFacingException;
|
||||
}
|
||||
|
||||
throw (e);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QException("Unexpected error occurred while executing query: " + e.getMessage(), e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableCountInput extends TableQueryOrCountInput
|
||||
{
|
||||
private Boolean includeDistinct = false;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for includeDistinct
|
||||
*******************************************************************************/
|
||||
public Boolean getIncludeDistinct()
|
||||
{
|
||||
return (this.includeDistinct);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for includeDistinct
|
||||
*******************************************************************************/
|
||||
public void setIncludeDistinct(Boolean includeDistinct)
|
||||
{
|
||||
this.includeDistinct = includeDistinct;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for includeDistinct
|
||||
*******************************************************************************/
|
||||
public TableCountInput withIncludeDistinct(Boolean includeDistinct)
|
||||
{
|
||||
this.includeDistinct = includeDistinct;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface TableCountOutputInterface extends AbstractMiddlewareOutputInterface
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
void setCount(Long count);
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
void setDistinctCount(Long count);
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableMetaDataInput extends AbstractMiddlewareInput
|
||||
{
|
||||
private String tableName;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableMetaDataInput withTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface TableMetaDataOutputInterface extends AbstractMiddlewareOutputInterface
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
void setTableMetaData(QFrontendTableMetaData tableMetaData);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableQueryInput extends TableQueryOrCountInput
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.TableVariant;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract class TableQueryOrCountInput extends AbstractMiddlewareInput
|
||||
{
|
||||
private String tableName;
|
||||
private QQueryFilter filter;
|
||||
private List<QueryJoin> joins;
|
||||
|
||||
private TableVariant tableVariant;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableQueryOrCountInput withTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for filter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QQueryFilter getFilter()
|
||||
{
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for filter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFilter(QQueryFilter filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for filter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableQueryOrCountInput withFilter(QQueryFilter filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for joins
|
||||
*******************************************************************************/
|
||||
public List<QueryJoin> getJoins()
|
||||
{
|
||||
return (this.joins);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for joins
|
||||
*******************************************************************************/
|
||||
public void setJoins(List<QueryJoin> joins)
|
||||
{
|
||||
this.joins = joins;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for joins
|
||||
*******************************************************************************/
|
||||
public TableQueryOrCountInput withJoins(List<QueryJoin> joins)
|
||||
{
|
||||
this.joins = joins;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableVariant
|
||||
*******************************************************************************/
|
||||
public TableVariant getTableVariant()
|
||||
{
|
||||
return (this.tableVariant);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableVariant
|
||||
*******************************************************************************/
|
||||
public void setTableVariant(TableVariant tableVariant)
|
||||
{
|
||||
this.tableVariant = tableVariant;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableVariant
|
||||
*******************************************************************************/
|
||||
public TableQueryOrCountInput withTableVariant(TableVariant tableVariant)
|
||||
{
|
||||
this.tableVariant = tableVariant;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface TableQueryOutputInterface extends AbstractMiddlewareOutputInterface
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
void setRecords(List<QRecord> records);
|
||||
}
|
@ -44,6 +44,7 @@ public class MiddlewareVersionV1 extends AbstractMiddlewareVersion
|
||||
|
||||
list.add(new TableMetaDataSpecV1());
|
||||
list.add(new TableQuerySpecV1());
|
||||
list.add(new TableCountSpecV1());
|
||||
|
||||
list.add(new ProcessMetaDataSpecV1());
|
||||
list.add(new ProcessInitSpecV1());
|
||||
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.TableCountExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableCountInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.TableCountResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.QuerySpecUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.In;
|
||||
import com.kingsrook.qqq.openapi.model.Parameter;
|
||||
import com.kingsrook.qqq.openapi.model.RequestBody;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import io.javalin.http.Context;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableCountSpecV1 extends AbstractEndpointSpec<TableCountInput, TableCountResponseV1, TableCountExecutor>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
return new BasicOperation()
|
||||
.withPath("/table/{tableName}/count")
|
||||
.withHttpMethod(HttpMethod.POST)
|
||||
.withTag(TagsV1.TABLES)
|
||||
.withShortSummary("Count records in a table")
|
||||
.withLongDescription("""
|
||||
Execute a query against a table, returning the number of records that match a filter."""
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public List<Parameter> defineRequestParameters()
|
||||
{
|
||||
return List.of(
|
||||
new Parameter()
|
||||
.withName("tableName")
|
||||
.withDescription("Name of the table to count.")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.STRING))
|
||||
.withExample("person")
|
||||
.withIn(In.PATH),
|
||||
new Parameter()
|
||||
.withName("includeDistinct")
|
||||
.withDescription("Whether or not to also return the count distinct records from the main table (e.g., in case of a to-many join; by default, do not).")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.BOOLEAN))
|
||||
.withExample("true")
|
||||
.withIn(In.QUERY)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public RequestBody defineRequestBody()
|
||||
{
|
||||
return (QuerySpecUtils.defineQueryOrCountRequestBody());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public TableCountInput buildInput(Context context) throws Exception
|
||||
{
|
||||
TableCountInput input = new TableCountInput();
|
||||
input.setTableName(getRequestParam(context, "tableName"));
|
||||
|
||||
JSONObject requestBody = getRequestBodyAsJsonObject(context);
|
||||
if(requestBody != null)
|
||||
{
|
||||
input.setFilter(QuerySpecUtils.getFilterFromRequestBody(requestBody));
|
||||
input.setJoins(QuerySpecUtils.getJoinsFromRequestBody(requestBody));
|
||||
input.setTableVariant(QuerySpecUtils.getTableVariantFromRequestBody(requestBody));
|
||||
}
|
||||
|
||||
String includeDistinctParam = getRequestParam(context, "includeDistinct");
|
||||
if("true".equals(includeDistinctParam))
|
||||
{
|
||||
input.setIncludeDistinct(true);
|
||||
}
|
||||
|
||||
return (input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Map<String, Schema> defineComponentSchemas()
|
||||
{
|
||||
return Map.of(TableCountResponseV1.class.getSimpleName(), new TableCountResponseV1().toSchema());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
Map<String, Example> examples = new LinkedHashMap<>();
|
||||
examples.put("TODO", new Example()
|
||||
.withValue(new TableCountResponseV1().withCount(42L)));
|
||||
|
||||
return new BasicResponse("""
|
||||
The number (count) of records matching the query""",
|
||||
TableCountResponseV1.class.getSimpleName(),
|
||||
examples
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.TableMetaDataExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableMetaDataInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.TableMetaDataResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.In;
|
||||
import com.kingsrook.qqq.openapi.model.Parameter;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableMetaDataSpecV1 extends AbstractEndpointSpec<TableMetaDataInput, TableMetaDataResponseV1, TableMetaDataExecutor>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
return new BasicOperation()
|
||||
.withPath("/metaData/table/{tableName}")
|
||||
.withHttpMethod(HttpMethod.GET)
|
||||
.withTag(TagsV1.TABLES)
|
||||
.withShortSummary("Get table metaData")
|
||||
.withLongDescription("""
|
||||
Load the full metadata for a single table, including all fields, which a frontend
|
||||
needs to display to users."""
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public List<Parameter> defineRequestParameters()
|
||||
{
|
||||
return List.of(
|
||||
new Parameter()
|
||||
.withName("tableName")
|
||||
.withDescription("Name of the table to load.")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.STRING))
|
||||
.withExample("person")
|
||||
.withIn(In.PATH)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public TableMetaDataInput buildInput(Context context) throws Exception
|
||||
{
|
||||
TableMetaDataInput input = new TableMetaDataInput();
|
||||
input.setTableName(getRequestParam(context, "tableName"));
|
||||
return (input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Map<String, Schema> defineComponentSchemas()
|
||||
{
|
||||
return Map.of(TableMetaDataResponseV1.class.getSimpleName(), new TableMetaDataResponseV1().toSchema());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
QFrontendTableMetaData frontendTableMetaData = null; // todo
|
||||
|
||||
Map<String, Example> examples = new LinkedHashMap<>();
|
||||
examples.put("TODO", new Example()
|
||||
.withValue(new TableMetaDataResponseV1().withTableMetaData(frontendTableMetaData)));
|
||||
|
||||
return new BasicResponse("""
|
||||
The full table metadata""",
|
||||
TableMetaDataResponseV1.class.getSimpleName(),
|
||||
examples
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void handleOutput(Context context, TableMetaDataResponseV1 output) throws Exception
|
||||
{
|
||||
context.result(JsonUtils.toJson(output.getTableMetaData()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.TableQueryExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableQueryInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.TableQueryResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.QuerySpecUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.In;
|
||||
import com.kingsrook.qqq.openapi.model.Parameter;
|
||||
import com.kingsrook.qqq.openapi.model.RequestBody;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import io.javalin.http.Context;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableQuerySpecV1 extends AbstractEndpointSpec<TableQueryInput, TableQueryResponseV1, TableQueryExecutor>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
return new BasicOperation()
|
||||
.withPath("/table/{tableName}/query")
|
||||
.withHttpMethod(HttpMethod.POST)
|
||||
.withTag(TagsV1.TABLES)
|
||||
.withShortSummary("Query for records from a table")
|
||||
.withLongDescription("""
|
||||
Execute a query against a table, returning records that match a filter."""
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public List<Parameter> defineRequestParameters()
|
||||
{
|
||||
return List.of(
|
||||
new Parameter()
|
||||
.withName("tableName")
|
||||
.withDescription("Name of the table to query.")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.STRING))
|
||||
.withExample("person")
|
||||
.withIn(In.PATH)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public RequestBody defineRequestBody()
|
||||
{
|
||||
return (QuerySpecUtils.defineQueryOrCountRequestBody());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public TableQueryInput buildInput(Context context) throws Exception
|
||||
{
|
||||
TableQueryInput input = new TableQueryInput();
|
||||
input.setTableName(getRequestParam(context, "tableName"));
|
||||
|
||||
JSONObject requestBody = getRequestBodyAsJsonObject(context);
|
||||
if(requestBody != null)
|
||||
{
|
||||
input.setFilter(QuerySpecUtils.getFilterFromRequestBody(requestBody));
|
||||
input.setJoins(QuerySpecUtils.getJoinsFromRequestBody(requestBody));
|
||||
input.setTableVariant(QuerySpecUtils.getTableVariantFromRequestBody(requestBody));
|
||||
}
|
||||
|
||||
return (input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Map<String, Schema> defineComponentSchemas()
|
||||
{
|
||||
return Map.of(TableQueryResponseV1.class.getSimpleName(), new TableQueryResponseV1().toSchema());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
Map<String, Example> examples = new LinkedHashMap<>();
|
||||
examples.put("TODO", new Example()
|
||||
.withValue(new TableQueryResponseV1().withRecords(List.of(new QRecord()
|
||||
.withRecordLabel("Item 17")
|
||||
.withTableName("item")
|
||||
.withValue("id", 17).withValue("quantity", 1000).withValue("storeId", 42)
|
||||
.withDisplayValue("id", "17").withDisplayValue("quantity", "1,000").withDisplayValue("storeId", "QQQ-Mart")
|
||||
))));
|
||||
|
||||
return new BasicResponse("""
|
||||
The records matching query""",
|
||||
TableQueryResponseV1.class.getSimpleName(),
|
||||
examples
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void handleOutput(Context context, TableQueryResponseV1 tableQueryResponseV1) throws Exception
|
||||
{
|
||||
if(CollectionUtils.nullSafeIsEmpty(tableQueryResponseV1.getRecords()))
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// special case here, where we want an empty list to be returned for the case //
|
||||
// with no records found by default our serialization doesn't include empty lists //
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
context.result(JsonUtils.toJson(tableQueryResponseV1, objectMapper -> objectMapper
|
||||
.setSerializationInclusion(JsonInclude.Include.ALWAYS)));
|
||||
}
|
||||
else
|
||||
{
|
||||
super.handleOutput(context, tableQueryResponseV1);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableCountOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableCountResponseV1 implements TableCountOutputInterface, ToSchema
|
||||
{
|
||||
@OpenAPIDescription("Number (count) of records that satisfy the query request")
|
||||
private Long count;
|
||||
|
||||
@OpenAPIDescription("Number (count) of distinct records that satisfy the query request. Only included if requested.")
|
||||
private Long distinctCount;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for count
|
||||
*******************************************************************************/
|
||||
public Long getCount()
|
||||
{
|
||||
return (this.count);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for count
|
||||
*******************************************************************************/
|
||||
public void setCount(Long count)
|
||||
{
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for count
|
||||
*******************************************************************************/
|
||||
public TableCountResponseV1 withCount(Long count)
|
||||
{
|
||||
this.count = count;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for distinctCount
|
||||
*******************************************************************************/
|
||||
public Long getDistinctCount()
|
||||
{
|
||||
return (this.distinctCount);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for distinctCount
|
||||
*******************************************************************************/
|
||||
public void setDistinctCount(Long distinctCount)
|
||||
{
|
||||
this.distinctCount = distinctCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for distinctCount
|
||||
*******************************************************************************/
|
||||
public TableCountResponseV1 withDistinctCount(Long distinctCount)
|
||||
{
|
||||
this.distinctCount = distinctCount;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableMetaDataOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.SchemaBuilder;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.TableMetaData;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableMetaDataResponseV1 implements TableMetaDataOutputInterface, ToSchema
|
||||
{
|
||||
private TableMetaData tableMetaData;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setTableMetaData(QFrontendTableMetaData frontendTableMetaData)
|
||||
{
|
||||
this.tableMetaData = new TableMetaData(frontendTableMetaData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for frontendTableMetaData
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableMetaDataResponseV1 withTableMetaData(QFrontendTableMetaData frontendTableMetaData)
|
||||
{
|
||||
setTableMetaData(frontendTableMetaData);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Schema toSchema()
|
||||
{
|
||||
return new SchemaBuilder().classToSchema(TableMetaData.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableMetaData
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableMetaData getTableMetaData()
|
||||
{
|
||||
return tableMetaData;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.TableQueryOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.OutputRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableQueryResponseV1 implements TableQueryOutputInterface, ToSchema
|
||||
{
|
||||
@OpenAPIDescription("List of records that satisfy the query request")
|
||||
@OpenAPIListItems(value = OutputRecord.class, useRef = true)
|
||||
private List<OutputRecord> records;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void setRecords(List<QRecord> records)
|
||||
{
|
||||
if(records == null)
|
||||
{
|
||||
this.records = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.records = records.stream().map(qr -> new OutputRecord(qr)).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
*******************************************************************************/
|
||||
public TableQueryResponseV1 withRecords(List<QRecord> records)
|
||||
{
|
||||
setRecords(records);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for records
|
||||
*******************************************************************************/
|
||||
public List<OutputRecord> getRecords()
|
||||
{
|
||||
return (this.records);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendExposedJoin;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class ExposedJoin implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QFrontendExposedJoin wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ExposedJoin(QFrontendExposedJoin section)
|
||||
{
|
||||
this.wrapped = section;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ExposedJoin()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("User-facing label to display for this join")
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.wrapped.getLabel());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Whether or not this join is 'to many' in nature")
|
||||
public Boolean getIsMany()
|
||||
{
|
||||
return (this.wrapped.getIsMany());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("The meta-data for the joined table")
|
||||
public TableMetaData getJoinTable()
|
||||
{
|
||||
return (new TableMetaData(this.wrapped.getJoinTable()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("A list of joins that travel from the base table to the exposed join table")
|
||||
@OpenAPIListItems(value = QJoinMetaData.class, useRef = false)
|
||||
public List<QJoinMetaData> getJoinPath()
|
||||
{
|
||||
return (this.wrapped.getJoinPath());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class FilterCriteria implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QFilterCriteria wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public FilterCriteria(QFilterCriteria wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public FilterCriteria()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Field name that this criteria applies to")
|
||||
public String getFieldName()
|
||||
{
|
||||
return (this.wrapped.getFieldName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Logical operator that applies to this criteria")
|
||||
public QCriteriaOperator getOperator()
|
||||
{
|
||||
return (this.wrapped.getOperator());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Values to apply via the operator to the field")
|
||||
@OpenAPIListItems(value = String.class)
|
||||
public List<String> getValues()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getValues()).stream().map(String::valueOf).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class OrderBy implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QFilterOrderBy wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public OrderBy(QFilterOrderBy wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public OrderBy()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Field name that this order-by applies to")
|
||||
public String getFieldName()
|
||||
{
|
||||
return (this.wrapped.getFieldName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Whether this order-by is ascending or descending")
|
||||
public Boolean getIsAscending()
|
||||
{
|
||||
return (this.wrapped.getIsAscending());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class OutputRecord implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QRecord wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public OutputRecord(QRecord wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public OutputRecord()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
@OpenAPIDescription("Name of the table that the record is from.")
|
||||
public String getTableName()
|
||||
{
|
||||
return this.wrapped.getTableName();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
@OpenAPIDescription("Label to identify the record to a user.")
|
||||
public String getRecordLabel()
|
||||
{
|
||||
return this.wrapped.getRecordLabel();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
@OpenAPIDescription("Raw values that make up the record. Keys are Strings, which match the table's field names. Values can be any type, as per the table's fields.")
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return this.wrapped.getValues();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for displayValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
@OpenAPIDescription("Formatted string versions of the values that make up the record. Keys are Strings, which match the table's field names. Values are all Strings.")
|
||||
public Map<String, String> getDisplayValues()
|
||||
{
|
||||
return this.wrapped.getDisplayValues();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class QueryFilter implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QQueryFilter wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryFilter(QQueryFilter wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryFilter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Field level criteria that make up the query filter")
|
||||
@OpenAPIListItems(value = FilterCriteria.class, useRef = true)
|
||||
public List<FilterCriteria> getCriteria()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getCriteria()).stream().map(s -> new FilterCriteria(s)).toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("How the query's results should be ordered (sorted).")
|
||||
@OpenAPIListItems(value = OrderBy.class, useRef = true)
|
||||
public List<OrderBy> getOrderBys()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getOrderBys()).stream().map(s -> new OrderBy(s)).toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Boolean operator to apply between criteria")
|
||||
public QQueryFilter.BooleanOperator getBooleanOperator()
|
||||
{
|
||||
return (this.wrapped.getBooleanOperator());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Records to skip (e.g., to implement pagination)")
|
||||
public Integer getSkip()
|
||||
{
|
||||
return (this.wrapped.getSkip());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Maximum number of results to return.")
|
||||
public Integer getLimit()
|
||||
{
|
||||
return (this.wrapped.getLimit());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class QueryJoin implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryJoin(com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryJoin()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Table being joined into the query by this QueryJoin")
|
||||
public String getJoinTable()
|
||||
{
|
||||
return (this.wrapped.getJoinTable());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Base table (or an alias) that this QueryJoin is joined against")
|
||||
public String getBaseTableOrAlias()
|
||||
{
|
||||
return (this.wrapped.getBaseTableOrAlias());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Name of a join to use in case the baseTable and joinTable have more than one")
|
||||
public String getJoinName()
|
||||
{
|
||||
return (this.wrapped.getJoinMetaData() == null ? null : this.wrapped.getJoinMetaData().getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Alias to apply to this table in the join query")
|
||||
public String getAlias()
|
||||
{
|
||||
return (this.wrapped.getAlias());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Whether or not to select values from the join table")
|
||||
public Boolean getSelect()
|
||||
{
|
||||
return (this.wrapped.getSelect());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Type of join being performed (SQL semantics)")
|
||||
public com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin.Type getType()
|
||||
{
|
||||
return (this.wrapped.getType());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.sharing.ShareableTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QSupplementalTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIIncludeProperties;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIMapValueType;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIIncludeProperties(ancestorClasses = TableMetaDataLight.class)
|
||||
public class TableMetaData extends TableMetaDataLight implements ToSchema
|
||||
{
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableMetaData(QFrontendTableMetaData wrapped)
|
||||
{
|
||||
super(wrapped);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableMetaData()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Fields in this table")
|
||||
@OpenAPIMapValueType(value = FieldMetaData.class, useRef = true)
|
||||
public Map<String, FieldMetaData> getFields()
|
||||
{
|
||||
return (CollectionUtils.nonNullMap(this.wrapped.getFields()).values().stream()
|
||||
.collect(Collectors.toMap(f -> f.getName(), f -> new FieldMetaData(f))));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Name of the primary key field in this table")
|
||||
public String getPrimaryKeyField()
|
||||
{
|
||||
return (wrapped.getPrimaryKeyField());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Whether or not this table's backend uses variants.")
|
||||
public Boolean getUsesVariants()
|
||||
{
|
||||
return (wrapped.getUsesVariants());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Sections to organize fields on screens for this record")
|
||||
@OpenAPIListItems(value = TableSection.class, useRef = true)
|
||||
public List<TableSection> getSections()
|
||||
{
|
||||
if(wrapped.getSections() == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (wrapped.getSections().stream().map(s -> new TableSection(s)).toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Sections to organize fields on screens for this record")
|
||||
@OpenAPIListItems(value = ExposedJoin.class, useRef = true)
|
||||
public List<ExposedJoin> getExposedJoins()
|
||||
{
|
||||
if(wrapped.getExposedJoins() == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (wrapped.getExposedJoins().stream().map(s -> new ExposedJoin(s)).toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Additional meta data about the table, not necessarily known to QQQ.")
|
||||
public Map<String, QSupplementalTableMetaData> getSupplementalMetaData()
|
||||
{
|
||||
return (wrapped.getSupplementalTableMetaData());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("For tables that support the sharing feature, meta-data about the sharing setup.")
|
||||
@OpenAPIListItems(value = ShareableTableMetaData.class, useRef = false)
|
||||
public ShareableTableMetaData getShareableTableMetaData()
|
||||
{
|
||||
return (wrapped.getShareableTableMetaData());
|
||||
}
|
||||
|
||||
}
|
@ -40,7 +40,7 @@ import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIMap
|
||||
public class TableMetaDataLight implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QFrontendTableMetaData wrapped;
|
||||
protected QFrontendTableMetaData wrapped;
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.help.QHelpContent;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class TableSection implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QFieldSection wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableSection(QFieldSection section)
|
||||
{
|
||||
this.wrapped = section;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableSection()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Unique identifier for this section within this table")
|
||||
public String getName()
|
||||
{
|
||||
return (this.wrapped.getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("User-facing label to display for this section")
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.wrapped.getLabel());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Importance of this section (T1, T2, or T3)")
|
||||
public String getTier()
|
||||
{
|
||||
return (this.wrapped.getTier().name());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("List of field names to include in this section.")
|
||||
public List<String> getFieldNames()
|
||||
{
|
||||
return (this.wrapped.getFieldNames());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Name of a widget in this QQQ instance to include in this section (instead of fields).")
|
||||
public String getWidgetName()
|
||||
{
|
||||
return (this.wrapped.getWidgetName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Icon to display for the table")
|
||||
public Icon getIcon()
|
||||
{
|
||||
return (this.wrapped.getIcon() == null ? null : new Icon(this.wrapped.getIcon()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Whether or not to hide this section")
|
||||
public Boolean isHidden()
|
||||
{
|
||||
return (this.wrapped.getIsHidden());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Layout suggestion, for how many columns of a 12-grid this section should use.")
|
||||
public Integer getGridColumns()
|
||||
{
|
||||
return (this.wrapped.getGridColumns());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Help Contents for this section table.") // todo describe more
|
||||
public List<QHelpContent> getHelpContents()
|
||||
{
|
||||
return (this.wrapped.getHelpContents());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class TableVariant implements ToSchema
|
||||
{
|
||||
@OpenAPIDescription("""
|
||||
Specification for the variant type (variantTypeKey from QQQ BackendVariantsConfig)""")
|
||||
private String type;
|
||||
|
||||
@OpenAPIDescription("""
|
||||
Identifier for the variant option (record) being used.""")
|
||||
private String id;
|
||||
|
||||
@OpenAPIDescription("""
|
||||
A user-facing name (or label) for the variant option being used.""")
|
||||
private String name;
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
*******************************************************************************/
|
||||
public String getType()
|
||||
{
|
||||
return (this.type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for type
|
||||
*******************************************************************************/
|
||||
public void setType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for type
|
||||
*******************************************************************************/
|
||||
public TableVariant withType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for id
|
||||
*******************************************************************************/
|
||||
public String getId()
|
||||
{
|
||||
return (this.id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for id
|
||||
*******************************************************************************/
|
||||
public void setId(String id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for id
|
||||
*******************************************************************************/
|
||||
public TableVariant withId(String id)
|
||||
{
|
||||
this.id = id;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for name
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return (this.name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for name
|
||||
*******************************************************************************/
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for name
|
||||
*******************************************************************************/
|
||||
public TableVariant withName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -24,20 +24,19 @@ package com.kingsrook.qqq.middleware.javalin.specs.v1.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.QueryMiddlewareInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.TableVariant;
|
||||
import com.kingsrook.qqq.openapi.model.Content;
|
||||
import com.kingsrook.qqq.openapi.model.RequestBody;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import io.javalin.http.ContentType;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@ -51,99 +50,28 @@ public class QuerySpecUtils
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static Schema defineQueryJoinsSchema()
|
||||
public static RequestBody defineQueryOrCountRequestBody()
|
||||
{
|
||||
Schema queryJoinsSchema = new Schema()
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema()
|
||||
.withProperties(MapBuilder.of(
|
||||
"joinTable", new Schema()
|
||||
.withType(Type.STRING),
|
||||
"select", new Schema()
|
||||
.withType(Type.BOOLEAN),
|
||||
"type", new Schema()
|
||||
.withType(Type.STRING)
|
||||
.withEnumValues(Arrays.stream(QueryJoin.Type.values()).map(o -> o.name()).toList()),
|
||||
"alias", new Schema()
|
||||
.withType(Type.STRING),
|
||||
"baseTableOrAlias", new Schema()
|
||||
.withType(Type.STRING)
|
||||
))
|
||||
);
|
||||
return queryJoinsSchema;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static Schema defineQQueryFilterSchema()
|
||||
{
|
||||
Schema qQueryFilterSchema = new Schema()
|
||||
.withType(Type.OBJECT)
|
||||
.withExample(List.of(
|
||||
JsonUtils.toJson(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.LESS_THAN, 5)))
|
||||
))
|
||||
.withProperties(MapBuilder.of(
|
||||
"criteria", new Schema()
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema()
|
||||
.withProperties(MapBuilder.of(
|
||||
"fieldName", new Schema()
|
||||
.withType(Type.STRING),
|
||||
"operator", new Schema()
|
||||
.withType(Type.STRING)
|
||||
.withEnumValues(Arrays.stream(QCriteriaOperator.values()).map(o -> o.name()).toList()),
|
||||
"values", new Schema()
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema().withOneOf(List.of(
|
||||
new Schema().withType(Type.INTEGER),
|
||||
new Schema().withType(Type.STRING)
|
||||
)))
|
||||
))
|
||||
),
|
||||
"orderBys", new Schema()
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema()
|
||||
.withProperties(MapBuilder.of(
|
||||
"fieldName", new Schema()
|
||||
.withType(Type.STRING),
|
||||
"isAscending", new Schema()
|
||||
.withType(Type.BOOLEAN)))
|
||||
),
|
||||
"booleanOperator", new Schema().withType(Type.STRING).withEnumValues(Arrays.stream(QQueryFilter.BooleanOperator.values()).map(o -> o.name()).toList()),
|
||||
"skip", new Schema().withType(Type.INTEGER),
|
||||
"limit", new Schema().withType(Type.INTEGER)
|
||||
// todo - subfilters??
|
||||
));
|
||||
return qQueryFilterSchema;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static Schema getQueryResponseSchema()
|
||||
{
|
||||
Schema schema = new Schema()
|
||||
.withDescription("Records found by the query. May be empty.")
|
||||
.withType(Type.OBJECT)
|
||||
.withProperties(MapBuilder.of(
|
||||
"records", new Schema()
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema()
|
||||
return new RequestBody()
|
||||
.withContent(Map.of(
|
||||
ContentType.APPLICATION_JSON.getMimeType(), new Content()
|
||||
.withSchema(new Schema()
|
||||
.withType(Type.OBJECT)
|
||||
.withProperties(MapBuilder.of(
|
||||
"recordLabel", new Schema().withType(Type.STRING),
|
||||
"tableName", new Schema().withType(Type.STRING),
|
||||
"values", new Schema().withType(Type.OBJECT).withDescription("Keys for each field in the table"),
|
||||
"displayValues", new Schema().withType(Type.OBJECT)
|
||||
.withProperties(Map.of(
|
||||
"filter", new Schema()
|
||||
.withDescription("QueryFilter to specify matching records to be returned by the query")
|
||||
.withRef("#/components/schemas/QueryFilter"),
|
||||
"joins", new Schema()
|
||||
.withDescription("QueryJoin objects to specify tables to be joined into the query")
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema()
|
||||
.withRef("#/components/schemas/QueryJoin")),
|
||||
"tableVariant", new Schema()
|
||||
.withDescription("For tables that use variant backends, specification of which variant to use.")
|
||||
.withRef("#/components/schemas/TableVariant")
|
||||
))
|
||||
)
|
||||
));
|
||||
return schema;
|
||||
}
|
||||
|
||||
|
||||
@ -151,58 +79,76 @@ public class QuerySpecUtils
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static QueryMiddlewareInput buildInput(Map<String, String> paramMap) throws IOException
|
||||
public static QQueryFilter getFilterFromRequestBody(JSONObject requestBody) throws IOException
|
||||
{
|
||||
|
||||
QQueryFilter filter = null;
|
||||
String filterParam = paramMap.get("filter");
|
||||
if(StringUtils.hasContent(filterParam))
|
||||
if(requestBody.has("filter"))
|
||||
{
|
||||
filter = JsonUtils.toObject(filterParam, QQueryFilter.class);
|
||||
}
|
||||
|
||||
List<QueryJoin> queryJoins = null;
|
||||
String queryJoinsParam = paramMap.get("queryJoins");
|
||||
if(StringUtils.hasContent(queryJoinsParam))
|
||||
{
|
||||
queryJoins = new ArrayList<>();
|
||||
|
||||
JSONArray queryJoinsJSON = new JSONArray(queryJoinsParam);
|
||||
for(int i = 0; i < queryJoinsJSON.length(); i++)
|
||||
Object filterFromJson = requestBody.get("filter");
|
||||
if(filterFromJson instanceof JSONObject filterJsonObject)
|
||||
{
|
||||
QueryJoin queryJoin = new QueryJoin();
|
||||
queryJoins.add(queryJoin);
|
||||
|
||||
JSONObject jsonObject = queryJoinsJSON.getJSONObject(i);
|
||||
queryJoin.setJoinTable(jsonObject.optString("joinTable"));
|
||||
|
||||
if(jsonObject.has("baseTableOrAlias") && !jsonObject.isNull("baseTableOrAlias"))
|
||||
{
|
||||
queryJoin.setBaseTableOrAlias(jsonObject.optString("baseTableOrAlias"));
|
||||
}
|
||||
|
||||
if(jsonObject.has("alias") && !jsonObject.isNull("alias"))
|
||||
{
|
||||
queryJoin.setAlias(jsonObject.optString("alias"));
|
||||
}
|
||||
|
||||
queryJoin.setSelect(jsonObject.optBoolean("select"));
|
||||
|
||||
if(jsonObject.has("type") && !jsonObject.isNull("type"))
|
||||
{
|
||||
queryJoin.setType(QueryJoin.Type.valueOf(jsonObject.getString("type")));
|
||||
}
|
||||
|
||||
if(jsonObject.has("joinName") && !jsonObject.isNull("joinName"))
|
||||
{
|
||||
queryJoin.setJoinMetaData(QContext.getQInstance().getJoin(jsonObject.getString("joinName")));
|
||||
}
|
||||
return (JsonUtils.toObject(filterJsonObject.toString(), QQueryFilter.class));
|
||||
}
|
||||
}
|
||||
|
||||
return new QueryMiddlewareInput()
|
||||
.withTable(paramMap.get("table"))
|
||||
.withFilter(filter)
|
||||
.withQueryJoins(queryJoins);
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static List<QueryJoin> getJoinsFromRequestBody(JSONObject requestBody) throws IOException
|
||||
{
|
||||
if(requestBody.has("joins"))
|
||||
{
|
||||
Object joinsFromJson = requestBody.get("joins");
|
||||
if(joinsFromJson instanceof JSONArray joinsJsonArray)
|
||||
{
|
||||
List<QueryJoin> joins = new ArrayList<>();
|
||||
for(int i = 0; i < joinsJsonArray.length(); i++)
|
||||
{
|
||||
JSONObject joinJsonObject = joinsJsonArray.getJSONObject(i);
|
||||
QJoinMetaData joinMetaData = null;
|
||||
if(joinJsonObject.has("joinName"))
|
||||
{
|
||||
String joinName = joinJsonObject.getString("joinName");
|
||||
joinMetaData = QContext.getQInstance().getJoin(joinName);
|
||||
joinJsonObject.remove("joinName");
|
||||
}
|
||||
|
||||
QueryJoin queryJoin = JsonUtils.toObject(joinJsonObject.toString(), QueryJoin.class);
|
||||
queryJoin.setJoinMetaData(joinMetaData);
|
||||
|
||||
joins.add(queryJoin);
|
||||
}
|
||||
return (joins);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static TableVariant getTableVariantFromRequestBody(JSONObject requestBody)
|
||||
{
|
||||
if(requestBody.has("tableVariant"))
|
||||
{
|
||||
Object variantFromJson = requestBody.get("tableVariant");
|
||||
if(variantFromJson instanceof JSONObject variantJsonObject)
|
||||
{
|
||||
TableVariant tableVariant = new TableVariant();
|
||||
tableVariant.setType(variantJsonObject.optString("type"));
|
||||
tableVariant.setId(variantJsonObject.optString("id"));
|
||||
tableVariant.setName(variantJsonObject.optString("name"));
|
||||
return (tableVariant);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -32,10 +32,7 @@ public enum TagsV1 implements TagsInterface
|
||||
{
|
||||
AUTHENTICATION("Authentication"),
|
||||
GENERAL("General"),
|
||||
QUERY("Query"),
|
||||
INSERT("Insert"),
|
||||
UPDATE("Update"),
|
||||
DELETE("Delete"),
|
||||
TABLES("Tables"),
|
||||
PROCESSES("Processes"),
|
||||
REPORTS("Reports"),
|
||||
WIDGETS("Widgets");
|
||||
|
@ -130,6 +130,42 @@ components:
|
||||
description: "Description of the error"
|
||||
type: "string"
|
||||
type: "object"
|
||||
ExposedJoin:
|
||||
properties:
|
||||
isMany:
|
||||
description: "Whether or not this join is 'to many' in nature"
|
||||
type: "boolean"
|
||||
joinPath:
|
||||
description: "A list of joins that travel from the base table to the exposed\
|
||||
\ join table"
|
||||
items:
|
||||
properties:
|
||||
joinOns:
|
||||
type: "array"
|
||||
leftTable:
|
||||
type: "string"
|
||||
name:
|
||||
type: "string"
|
||||
orderBys:
|
||||
type: "array"
|
||||
rightTable:
|
||||
type: "string"
|
||||
type:
|
||||
enum:
|
||||
- "ONE_TO_ONE"
|
||||
- "ONE_TO_MANY"
|
||||
- "MANY_TO_ONE"
|
||||
- "MANY_TO_MANY"
|
||||
type: "string"
|
||||
type: "object"
|
||||
type: "array"
|
||||
joinTable:
|
||||
$ref: "#/components/schemas/TableMetaData"
|
||||
description: "The meta-data for the joined table"
|
||||
label:
|
||||
description: "User-facing label to display for this join"
|
||||
type: "string"
|
||||
type: "object"
|
||||
FieldAdornment:
|
||||
properties:
|
||||
type:
|
||||
@ -193,6 +229,45 @@ components:
|
||||
description: "Data-type for this field"
|
||||
type: "string"
|
||||
type: "object"
|
||||
FilterCriteria:
|
||||
properties:
|
||||
fieldName:
|
||||
description: "Field name that this criteria applies to"
|
||||
type: "string"
|
||||
operator:
|
||||
description: "Logical operator that applies to this criteria"
|
||||
enum:
|
||||
- "EQUALS"
|
||||
- "NOT_EQUALS"
|
||||
- "NOT_EQUALS_OR_IS_NULL"
|
||||
- "IN"
|
||||
- "NOT_IN"
|
||||
- "IS_NULL_OR_IN"
|
||||
- "LIKE"
|
||||
- "NOT_LIKE"
|
||||
- "STARTS_WITH"
|
||||
- "ENDS_WITH"
|
||||
- "CONTAINS"
|
||||
- "NOT_STARTS_WITH"
|
||||
- "NOT_ENDS_WITH"
|
||||
- "NOT_CONTAINS"
|
||||
- "LESS_THAN"
|
||||
- "LESS_THAN_OR_EQUALS"
|
||||
- "GREATER_THAN"
|
||||
- "GREATER_THAN_OR_EQUALS"
|
||||
- "IS_BLANK"
|
||||
- "IS_NOT_BLANK"
|
||||
- "BETWEEN"
|
||||
- "NOT_BETWEEN"
|
||||
- "TRUE"
|
||||
- "FALSE"
|
||||
type: "string"
|
||||
values:
|
||||
description: "Values to apply via the operator to the field"
|
||||
items:
|
||||
type: "string"
|
||||
type: "array"
|
||||
type: "object"
|
||||
FrontendComponent:
|
||||
properties:
|
||||
type:
|
||||
@ -353,6 +428,34 @@ components:
|
||||
\ has permission to see that they exist)."
|
||||
type: "object"
|
||||
type: "object"
|
||||
OrderBy:
|
||||
properties:
|
||||
fieldName:
|
||||
description: "Field name that this order-by applies to"
|
||||
type: "string"
|
||||
isAscending:
|
||||
description: "Whether this order-by is ascending or descending"
|
||||
type: "boolean"
|
||||
type: "object"
|
||||
OutputRecord:
|
||||
properties:
|
||||
displayValues:
|
||||
description: "Formatted string versions of the values that make up the record.\
|
||||
\ Keys are Strings, which match the table's field names. Values are all\
|
||||
\ Strings."
|
||||
type: "object"
|
||||
recordLabel:
|
||||
description: "Label to identify the record to a user."
|
||||
type: "string"
|
||||
tableName:
|
||||
description: "Name of the table that the record is from."
|
||||
type: "string"
|
||||
values:
|
||||
description: "Raw values that make up the record. Keys are Strings, which\
|
||||
\ match the table's field names. Values can be any type, as per the table's\
|
||||
\ fields."
|
||||
type: "object"
|
||||
type: "object"
|
||||
ProcessMetaData:
|
||||
properties:
|
||||
frontendSteps:
|
||||
@ -720,6 +823,157 @@ components:
|
||||
\ additional fields will be set."
|
||||
type: "string"
|
||||
type: "object"
|
||||
QueryFilter:
|
||||
properties:
|
||||
booleanOperator:
|
||||
description: "Boolean operator to apply between criteria"
|
||||
enum:
|
||||
- "AND"
|
||||
- "OR"
|
||||
type: "string"
|
||||
criteria:
|
||||
description: "Field level criteria that make up the query filter"
|
||||
items:
|
||||
$ref: "#/components/schemas/FilterCriteria"
|
||||
type: "array"
|
||||
limit:
|
||||
description: "Maximum number of results to return."
|
||||
type: "number"
|
||||
orderBys:
|
||||
description: "How the query's results should be ordered (sorted)."
|
||||
items:
|
||||
$ref: "#/components/schemas/OrderBy"
|
||||
type: "array"
|
||||
skip:
|
||||
description: "Records to skip (e.g., to implement pagination)"
|
||||
type: "number"
|
||||
type: "object"
|
||||
QueryJoin:
|
||||
properties:
|
||||
alias:
|
||||
description: "Alias to apply to this table in the join query"
|
||||
type: "string"
|
||||
baseTableOrAlias:
|
||||
description: "Base table (or an alias) that this QueryJoin is joined against"
|
||||
type: "string"
|
||||
joinName:
|
||||
description: "Name of a join to use in case the baseTable and joinTable\
|
||||
\ have more than one"
|
||||
type: "string"
|
||||
joinTable:
|
||||
description: "Table being joined into the query by this QueryJoin"
|
||||
type: "string"
|
||||
select:
|
||||
description: "Whether or not to select values from the join table"
|
||||
type: "boolean"
|
||||
type:
|
||||
description: "Type of join being performed (SQL semantics)"
|
||||
enum:
|
||||
- "INNER"
|
||||
- "LEFT"
|
||||
- "RIGHT"
|
||||
- "FULL"
|
||||
type: "string"
|
||||
type: "object"
|
||||
TableCountResponseV1:
|
||||
properties:
|
||||
count:
|
||||
description: "Number (count) of records that satisfy the query request"
|
||||
type: "number"
|
||||
distinctCount:
|
||||
description: "Number (count) of distinct records that satisfy the query\
|
||||
\ request. Only included if requested."
|
||||
type: "number"
|
||||
type: "object"
|
||||
TableMetaData:
|
||||
properties:
|
||||
capabilities:
|
||||
description: "List of strings describing actions that are supported by the\
|
||||
\ backend application for the table."
|
||||
items:
|
||||
type: "string"
|
||||
type: "array"
|
||||
deletePermission:
|
||||
description: "Boolean to indicate if the user has delete permission for\
|
||||
\ the table."
|
||||
type: "boolean"
|
||||
editPermission:
|
||||
description: "Boolean to indicate if the user has edit permission for the\
|
||||
\ table."
|
||||
type: "boolean"
|
||||
exposedJoins:
|
||||
description: "Sections to organize fields on screens for this record"
|
||||
items:
|
||||
$ref: "#/components/schemas/ExposedJoin"
|
||||
type: "array"
|
||||
fields:
|
||||
additionalProperties:
|
||||
$ref: "#/components/schemas/FieldMetaData"
|
||||
description: "Fields in this table"
|
||||
type: "object"
|
||||
helpContents:
|
||||
description: "Help Contents for this table."
|
||||
type: "object"
|
||||
icon:
|
||||
$ref: "#/components/schemas/Icon"
|
||||
description: "Icon to display for the table"
|
||||
insertPermission:
|
||||
description: "Boolean to indicate if the user has insert permission for\
|
||||
\ the table."
|
||||
type: "boolean"
|
||||
isHidden:
|
||||
description: "Boolean indicator of whether the table should be shown to\
|
||||
\ users or not"
|
||||
type: "boolean"
|
||||
label:
|
||||
description: "User-facing name for this table"
|
||||
type: "string"
|
||||
name:
|
||||
description: "Unique name for this table within the QQQ Instance"
|
||||
type: "string"
|
||||
primaryKeyField:
|
||||
description: "Name of the primary key field in this table"
|
||||
type: "string"
|
||||
readPermission:
|
||||
description: "Boolean to indicate if the user has read permission for the\
|
||||
\ table."
|
||||
type: "boolean"
|
||||
sections:
|
||||
description: "Sections to organize fields on screens for this record"
|
||||
items:
|
||||
$ref: "#/components/schemas/TableSection"
|
||||
type: "array"
|
||||
shareableTableMetaData:
|
||||
description: "For tables that support the sharing feature, meta-data about\
|
||||
\ the sharing setup."
|
||||
properties:
|
||||
assetIdFieldName:
|
||||
type: "string"
|
||||
audiencePossibleValueSourceName:
|
||||
type: "string"
|
||||
audienceTypes:
|
||||
type: "object"
|
||||
audienceTypesPossibleValueSourceName:
|
||||
type: "string"
|
||||
scopeFieldName:
|
||||
type: "string"
|
||||
sharedRecordTableName:
|
||||
type: "string"
|
||||
thisTableOwnerIdFieldName:
|
||||
type: "string"
|
||||
type: "object"
|
||||
supplementalMetaData:
|
||||
description: "Additional meta data about the table, not necessarily known\
|
||||
\ to QQQ."
|
||||
type: "object"
|
||||
usesVariants:
|
||||
description: "Whether or not this table's backend uses variants."
|
||||
type: "boolean"
|
||||
variantTableLabel:
|
||||
description: "If the table uses variants, this is the user-facing label\
|
||||
\ for the table that supplies variants for this table."
|
||||
type: "string"
|
||||
type: "object"
|
||||
TableMetaDataLight:
|
||||
properties:
|
||||
capabilities:
|
||||
@ -765,6 +1019,157 @@ components:
|
||||
\ for the table that supplies variants for this table."
|
||||
type: "string"
|
||||
type: "object"
|
||||
TableMetaDataResponseV1:
|
||||
properties:
|
||||
capabilities:
|
||||
description: "List of strings describing actions that are supported by the\
|
||||
\ backend application for the table."
|
||||
items:
|
||||
type: "string"
|
||||
type: "array"
|
||||
deletePermission:
|
||||
description: "Boolean to indicate if the user has delete permission for\
|
||||
\ the table."
|
||||
type: "boolean"
|
||||
editPermission:
|
||||
description: "Boolean to indicate if the user has edit permission for the\
|
||||
\ table."
|
||||
type: "boolean"
|
||||
exposedJoins:
|
||||
description: "Sections to organize fields on screens for this record"
|
||||
items:
|
||||
$ref: "#/components/schemas/ExposedJoin"
|
||||
type: "array"
|
||||
fields:
|
||||
additionalProperties:
|
||||
$ref: "#/components/schemas/FieldMetaData"
|
||||
description: "Fields in this table"
|
||||
type: "object"
|
||||
helpContents:
|
||||
description: "Help Contents for this table."
|
||||
type: "object"
|
||||
icon:
|
||||
description: "Icon to display for the table"
|
||||
properties:
|
||||
color:
|
||||
description: "A color code to use for displaying the icon"
|
||||
type: "string"
|
||||
name:
|
||||
description: "A material UI icon name."
|
||||
type: "string"
|
||||
path:
|
||||
description: "A path to an image file that can be requested from the\
|
||||
\ server, to serve as the icon image instead of a material UI icon."
|
||||
type: "string"
|
||||
type: "object"
|
||||
insertPermission:
|
||||
description: "Boolean to indicate if the user has insert permission for\
|
||||
\ the table."
|
||||
type: "boolean"
|
||||
isHidden:
|
||||
description: "Boolean indicator of whether the table should be shown to\
|
||||
\ users or not"
|
||||
type: "boolean"
|
||||
label:
|
||||
description: "User-facing name for this table"
|
||||
type: "string"
|
||||
name:
|
||||
description: "Unique name for this table within the QQQ Instance"
|
||||
type: "string"
|
||||
primaryKeyField:
|
||||
description: "Name of the primary key field in this table"
|
||||
type: "string"
|
||||
readPermission:
|
||||
description: "Boolean to indicate if the user has read permission for the\
|
||||
\ table."
|
||||
type: "boolean"
|
||||
sections:
|
||||
description: "Sections to organize fields on screens for this record"
|
||||
items:
|
||||
$ref: "#/components/schemas/TableSection"
|
||||
type: "array"
|
||||
shareableTableMetaData:
|
||||
description: "For tables that support the sharing feature, meta-data about\
|
||||
\ the sharing setup."
|
||||
properties:
|
||||
assetIdFieldName:
|
||||
type: "string"
|
||||
audiencePossibleValueSourceName:
|
||||
type: "string"
|
||||
audienceTypes:
|
||||
type: "object"
|
||||
audienceTypesPossibleValueSourceName:
|
||||
type: "string"
|
||||
scopeFieldName:
|
||||
type: "string"
|
||||
sharedRecordTableName:
|
||||
type: "string"
|
||||
thisTableOwnerIdFieldName:
|
||||
type: "string"
|
||||
type: "object"
|
||||
supplementalMetaData:
|
||||
description: "Additional meta data about the table, not necessarily known\
|
||||
\ to QQQ."
|
||||
type: "object"
|
||||
usesVariants:
|
||||
description: "Whether or not this table's backend uses variants."
|
||||
type: "boolean"
|
||||
variantTableLabel:
|
||||
description: "If the table uses variants, this is the user-facing label\
|
||||
\ for the table that supplies variants for this table."
|
||||
type: "string"
|
||||
type: "object"
|
||||
TableQueryResponseV1:
|
||||
properties:
|
||||
records:
|
||||
description: "List of records that satisfy the query request"
|
||||
items:
|
||||
$ref: "#/components/schemas/OutputRecord"
|
||||
type: "array"
|
||||
type: "object"
|
||||
TableSection:
|
||||
properties:
|
||||
fieldNames:
|
||||
description: "List of field names to include in this section."
|
||||
type: "array"
|
||||
gridColumns:
|
||||
description: "Layout suggestion, for how many columns of a 12-grid this\
|
||||
\ section should use."
|
||||
type: "number"
|
||||
helpContents:
|
||||
description: "Help Contents for this section table."
|
||||
type: "array"
|
||||
icon:
|
||||
$ref: "#/components/schemas/Icon"
|
||||
description: "Icon to display for the table"
|
||||
label:
|
||||
description: "User-facing label to display for this section"
|
||||
type: "string"
|
||||
name:
|
||||
description: "Unique identifier for this section within this table"
|
||||
type: "string"
|
||||
tier:
|
||||
description: "Importance of this section (T1, T2, or T3)"
|
||||
type: "string"
|
||||
widgetName:
|
||||
description: "Name of a widget in this QQQ instance to include in this section\
|
||||
\ (instead of fields)."
|
||||
type: "string"
|
||||
type: "object"
|
||||
TableVariant:
|
||||
properties:
|
||||
id:
|
||||
description: "Identifier for the variant option (record) being used."
|
||||
type: "string"
|
||||
name:
|
||||
description: "A user-facing name (or label) for the variant option being\
|
||||
\ used."
|
||||
type: "string"
|
||||
type:
|
||||
description: "Specification for the variant type (variantTypeKey from QQQ\
|
||||
\ BackendVariantsConfig)"
|
||||
type: "string"
|
||||
type: "object"
|
||||
WidgetBlock:
|
||||
properties:
|
||||
blockId:
|
||||
@ -1532,6 +1937,151 @@ paths:
|
||||
summary: "Get instance metaData"
|
||||
tags:
|
||||
- "General"
|
||||
/qqq/v1/metaData/table/{tableName}:
|
||||
get:
|
||||
description: "Load the full metadata for a single table, including all fields,\
|
||||
\ which a frontend\nneeds to display to users."
|
||||
parameters:
|
||||
- description: "Name of the table to load."
|
||||
example: "person"
|
||||
in: "path"
|
||||
name: "tableName"
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
responses:
|
||||
200:
|
||||
content:
|
||||
application/json:
|
||||
examples:
|
||||
TODO: {}
|
||||
schema:
|
||||
$ref: "#/components/schemas/TableMetaDataResponseV1"
|
||||
description: "The full table metadata"
|
||||
security:
|
||||
- sessionUuidCookie:
|
||||
- "N/A"
|
||||
summary: "Get table metaData"
|
||||
tags:
|
||||
- "Tables"
|
||||
/qqq/v1/table/{tableName}/query:
|
||||
post:
|
||||
description: "Execute a query against a table, returning records that match\
|
||||
\ a filter."
|
||||
parameters:
|
||||
- description: "Name of the table to query."
|
||||
example: "person"
|
||||
in: "path"
|
||||
name: "tableName"
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
tableVariant:
|
||||
$ref: "#/components/schemas/TableVariant"
|
||||
description: "For tables that use variant backends, specification\
|
||||
\ of which variant to use."
|
||||
filter:
|
||||
$ref: "#/components/schemas/QueryFilter"
|
||||
description: "QueryFilter to specify matching records to be returned\
|
||||
\ by the query"
|
||||
joins:
|
||||
description: "QueryJoin objects to specify tables to be joined into\
|
||||
\ the query"
|
||||
items:
|
||||
$ref: "#/components/schemas/QueryJoin"
|
||||
type: "array"
|
||||
type: "object"
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
content:
|
||||
application/json:
|
||||
examples:
|
||||
TODO:
|
||||
value:
|
||||
records:
|
||||
- displayValues:
|
||||
id: "17"
|
||||
quantity: "1,000"
|
||||
storeId: "QQQ-Mart"
|
||||
recordLabel: "Item 17"
|
||||
tableName: "item"
|
||||
values:
|
||||
id: 17
|
||||
quantity: 1000
|
||||
storeId: 42
|
||||
schema:
|
||||
$ref: "#/components/schemas/TableQueryResponseV1"
|
||||
description: "The records matching query"
|
||||
security:
|
||||
- sessionUuidCookie:
|
||||
- "N/A"
|
||||
summary: "Query for records from a table"
|
||||
tags:
|
||||
- "Tables"
|
||||
/qqq/v1/table/{tableName}/count:
|
||||
post:
|
||||
description: "Execute a query against a table, returning the number of records\
|
||||
\ that match a filter."
|
||||
parameters:
|
||||
- description: "Name of the table to count."
|
||||
example: "person"
|
||||
in: "path"
|
||||
name: "tableName"
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
- description: "Whether or not to also return the count distinct records from\
|
||||
\ the main table (e.g., in case of a to-many join; by default, do not)."
|
||||
example: "true"
|
||||
in: "query"
|
||||
name: "includeDistinct"
|
||||
required: true
|
||||
schema:
|
||||
type: "boolean"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
tableVariant:
|
||||
$ref: "#/components/schemas/TableVariant"
|
||||
description: "For tables that use variant backends, specification\
|
||||
\ of which variant to use."
|
||||
filter:
|
||||
$ref: "#/components/schemas/QueryFilter"
|
||||
description: "QueryFilter to specify matching records to be returned\
|
||||
\ by the query"
|
||||
joins:
|
||||
description: "QueryJoin objects to specify tables to be joined into\
|
||||
\ the query"
|
||||
items:
|
||||
$ref: "#/components/schemas/QueryJoin"
|
||||
type: "array"
|
||||
type: "object"
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
content:
|
||||
application/json:
|
||||
examples:
|
||||
TODO:
|
||||
value:
|
||||
count: 42
|
||||
schema:
|
||||
$ref: "#/components/schemas/TableCountResponseV1"
|
||||
description: "The number (count) of records matching the query"
|
||||
security:
|
||||
- sessionUuidCookie:
|
||||
- "N/A"
|
||||
summary: "Count records in a table"
|
||||
tags:
|
||||
- "Tables"
|
||||
/qqq/v1/metaData/process/{processName}:
|
||||
get:
|
||||
description: "Load the full metadata for a single process, including all screens\
|
||||
|
@ -87,11 +87,13 @@ import com.kingsrook.qqq.backend.core.model.metadata.reporting.ReportType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.AssociatedScript;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.variants.BackendVariantsConfig;
|
||||
import com.kingsrook.qqq.backend.core.model.savedviews.SavedViewsMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryModuleBackendVariantSetting;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
|
||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||
@ -114,6 +116,10 @@ public class TestUtils
|
||||
public static final String TABLE_NAME_PERSON = "person";
|
||||
public static final String TABLE_NAME_PET = "pet";
|
||||
|
||||
public static final String MEMORY_BACKEND_WITH_VARIANTS_NAME = "memoryWithVariants";
|
||||
public static final String TABLE_NAME_MEMORY_VARIANT_OPTIONS = "memoryVariantOptions";
|
||||
public static final String TABLE_NAME_MEMORY_VARIANT_DATA = "memoryVariantData";
|
||||
|
||||
public static final String PROCESS_NAME_GREET_PEOPLE_INTERACTIVE = "greetInteractive";
|
||||
public static final String PROCESS_NAME_SIMPLE_SLEEP = "simpleSleep";
|
||||
public static final String PROCESS_NAME_SIMPLE_THROW = "simpleThrow";
|
||||
@ -191,6 +197,8 @@ public class TestUtils
|
||||
qInstance.addPossibleValueSource(definePossibleValueSourcePerson());
|
||||
defineWidgets(qInstance);
|
||||
|
||||
defineMemoryBackendVariantUseCases(qInstance);
|
||||
|
||||
List<JavalinRouteProviderMetaData> routeProviders = new ArrayList<>();
|
||||
routeProviders.add(new JavalinRouteProviderMetaData()
|
||||
.withHostedPath("/statically-served")
|
||||
@ -832,4 +840,39 @@ public class TestUtils
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static void defineMemoryBackendVariantUseCases(QInstance qInstance)
|
||||
{
|
||||
qInstance.addBackend(new QBackendMetaData()
|
||||
.withName(MEMORY_BACKEND_WITH_VARIANTS_NAME)
|
||||
.withBackendType(MemoryBackendModule.class)
|
||||
.withUsesVariants(true)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig()
|
||||
.withVariantTypeKey(TABLE_NAME_MEMORY_VARIANT_OPTIONS)
|
||||
.withOptionsTableName(TABLE_NAME_MEMORY_VARIANT_OPTIONS)
|
||||
.withBackendSettingSourceFieldNameMap(Map.of(MemoryModuleBackendVariantSetting.PRIMARY_KEY, "id"))
|
||||
));
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName(TABLE_NAME_MEMORY_VARIANT_DATA)
|
||||
.withBackendName(MEMORY_BACKEND_WITH_VARIANTS_NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("name", QFieldType.STRING))
|
||||
);
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName(TABLE_NAME_MEMORY_VARIANT_OPTIONS)
|
||||
.withBackendName(BACKEND_NAME_MEMORY) // note, the version without variants!
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("name", QFieldType.STRING))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -109,6 +109,8 @@ public abstract class SpecTestBase
|
||||
service = null;
|
||||
}
|
||||
|
||||
TestMiddlewareVersion testMiddlewareVersion = new TestMiddlewareVersion();
|
||||
|
||||
if(service == null)
|
||||
{
|
||||
service = Javalin.create(config ->
|
||||
@ -117,12 +119,12 @@ public abstract class SpecTestBase
|
||||
|
||||
AbstractEndpointSpec<?, ?, ?> spec = getSpec();
|
||||
spec.setQInstance(qInstance);
|
||||
config.router.apiBuilder(() -> spec.defineRoute(getVersion()));
|
||||
config.router.apiBuilder(() -> spec.defineRoute(testMiddlewareVersion, getVersion()));
|
||||
|
||||
for(AbstractEndpointSpec<?, ?, ?> additionalSpec : getAdditionalSpecs())
|
||||
{
|
||||
additionalSpec.setQInstance(qInstance);
|
||||
config.router.apiBuilder(() -> additionalSpec.defineRoute(getVersion()));
|
||||
config.router.apiBuilder(() -> additionalSpec.defineRoute(testMiddlewareVersion, getVersion()));
|
||||
}
|
||||
}
|
||||
).start(PORT);
|
||||
@ -133,6 +135,35 @@ public abstract class SpecTestBase
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static class TestMiddlewareVersion extends AbstractMiddlewareVersion
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public String getVersion()
|
||||
{
|
||||
return "test";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public List<AbstractEndpointSpec<?, ?, ?>> getEndpointSpecs()
|
||||
{
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSystemUserSession;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.javalin.TestUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.SpecTestBase;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.TableVariant;
|
||||
import io.javalin.http.ContentType;
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.Unirest;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for TableCountSpecV1
|
||||
*******************************************************************************/
|
||||
class TableCountSpecV1Test extends SpecTestBase
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected AbstractEndpointSpec<?, ?, ?> getSpec()
|
||||
{
|
||||
return new TableCountSpecV1();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected String getVersion()
|
||||
{
|
||||
return "v1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/table/person/count")
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("filter", new QQueryFilter(new QFilterCriteria("lastName", QCriteriaOperator.EQUALS, "Kelkhoff")))))
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals(2, jsonObject.getInt("count"));
|
||||
assertFalse(jsonObject.has("distinctCount"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testIncludingDistinct()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/table/person/count?includeDistinct=true")
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("filter", new QQueryFilter(new QFilterCriteria("lastName", QCriteriaOperator.EQUALS, "Kelkhoff")))))
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals(2, jsonObject.getInt("count"));
|
||||
assertEquals(2, jsonObject.getInt("distinctCount"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testNoRecordsFound()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/table/person/count")
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("filter", new QQueryFilter(new QFilterCriteria("lastName", QCriteriaOperator.EQUALS, "Unkelkhoff")))))
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals(0, jsonObject.getInt("count"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** test the for a non-real name
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void testTableNotFound()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/table/notAnActualTable/count").asString();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// expect a non-existing table to 403, the same as one that does exist but that you don't have permission to //
|
||||
// to kinda hide from someone what is or isn't a real table (as a security thing i guess) //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
assertEquals(HttpStatus.FORBIDDEN_403, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals(1, jsonObject.keySet().size(), "Number of top-level keys");
|
||||
String error = jsonObject.getString("error");
|
||||
assertThat(error).contains("Permission denied");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testPostingTableVariant() throws QException
|
||||
{
|
||||
////////////////////////////////////
|
||||
// insert our two variant options //
|
||||
////////////////////////////////////
|
||||
QContext.init(TestUtils.defineInstance(), new QSystemUserSession());
|
||||
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_MEMORY_VARIANT_OPTIONS).withRecords(List.of(
|
||||
new QRecord().withValue("id", 1).withValue("name", "People"),
|
||||
new QRecord().withValue("id", 2).withValue("name", "Planets")
|
||||
)));
|
||||
|
||||
////////////////////////////////////////
|
||||
// insert some data into each variant //
|
||||
////////////////////////////////////////
|
||||
QContext.getQSession().setBackendVariants(Map.of(TestUtils.TABLE_NAME_MEMORY_VARIANT_OPTIONS, 1));
|
||||
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_MEMORY_VARIANT_DATA).withRecords(List.of(
|
||||
new QRecord().withValue("name", "Tom"),
|
||||
new QRecord().withValue("name", "Sally")
|
||||
)));
|
||||
|
||||
QContext.getQSession().setBackendVariants(Map.of(TestUtils.TABLE_NAME_MEMORY_VARIANT_OPTIONS, 2));
|
||||
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_MEMORY_VARIANT_DATA).withRecords(List.of(
|
||||
new QRecord().withValue("name", "Mars"),
|
||||
new QRecord().withValue("name", "Jupiter"),
|
||||
new QRecord().withValue("name", "Saturn")
|
||||
)));
|
||||
|
||||
//////////////////////////////////////////
|
||||
// count with no variant - expect error //
|
||||
//////////////////////////////////////////
|
||||
String url = getBaseUrlAndPath() + "/table/" + TestUtils.TABLE_NAME_MEMORY_VARIANT_DATA + "/count";
|
||||
HttpResponse<String> response = Unirest.post(url)
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of()))
|
||||
.asString();
|
||||
assertEquals(500, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals("Could not find Backend Variant information in session under key 'memoryVariantOptions' for Backend 'memoryWithVariants'", jsonObject.getString("error"));
|
||||
|
||||
//////////////////////////////
|
||||
// count for people variant //
|
||||
//////////////////////////////
|
||||
response = Unirest.post(url)
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("tableVariant", new TableVariant().withType("memoryVariantOptions").withId("1"))))
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals(2, jsonObject.getInt("count"));
|
||||
|
||||
///////////////////////////////
|
||||
// count for planets variant //
|
||||
///////////////////////////////
|
||||
response = Unirest.post(url)
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("tableVariant", new TableVariant().withType("memoryVariantOptions").withId("2"))))
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals(3, jsonObject.getInt("count"));
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// count with unknown variant - expect error //
|
||||
///////////////////////////////////////////////
|
||||
response = Unirest.post(url)
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("tableVariant", new TableVariant().withType("memoryVariantOptions").withId("3"))))
|
||||
.asString();
|
||||
assertEquals(500, response.getStatus());
|
||||
jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals("Could not find Backend Variant in table memoryVariantOptions with id '3'", jsonObject.getString("error"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.SpecTestBase;
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.Unirest;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for TableMetaDataSpecV1
|
||||
*******************************************************************************/
|
||||
class TableMetaDataSpecV1Test extends SpecTestBase
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected AbstractEndpointSpec<?, ?, ?> getSpec()
|
||||
{
|
||||
return new TableMetaDataSpecV1();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected String getVersion()
|
||||
{
|
||||
return "v1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.get(getBaseUrlAndPath() + "/metaData/table/person").asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals("person", jsonObject.getString("name"));
|
||||
assertEquals("Person", jsonObject.getString("label"));
|
||||
|
||||
JSONObject fields = jsonObject.getJSONObject("fields");
|
||||
JSONObject firstNameField = fields.getJSONObject("firstName");
|
||||
assertEquals("firstName", firstNameField.getString("name"));
|
||||
assertEquals("First Name", firstNameField.getString("label"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** test the table-level meta-data endpoint for a non-real name
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void testNotFound()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.get(getBaseUrlAndPath() + "/metaData/table/notAnActualTable").asString();
|
||||
|
||||
assertEquals(HttpStatus.NOT_FOUND_404, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals(1, jsonObject.keySet().size(), "Number of top-level keys");
|
||||
String error = jsonObject.getString("error");
|
||||
assertThat(error).contains("Table").contains("notAnActualTable").contains("not found");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSystemUserSession;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.javalin.TestUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.SpecTestBase;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.TableVariant;
|
||||
import io.javalin.http.ContentType;
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.Unirest;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for TableQuerySpecV1
|
||||
*******************************************************************************/
|
||||
class TableQuerySpecV1Test extends SpecTestBase
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected AbstractEndpointSpec<?, ?, ?> getSpec()
|
||||
{
|
||||
return new TableQuerySpecV1();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected String getVersion()
|
||||
{
|
||||
return "v1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/table/person/query")
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("filter", new QQueryFilter(new QFilterCriteria("lastName", QCriteriaOperator.EQUALS, "Kelkhoff")))))
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
JSONArray records = jsonObject.getJSONArray("records");
|
||||
assertThat(records.length()).isGreaterThanOrEqualTo(1);
|
||||
|
||||
JSONObject record = records.getJSONObject(0);
|
||||
assertThat(record.getString("recordLabel")).contains("Kelkhoff");
|
||||
assertThat(record.getString("tableName")).isEqualTo("person");
|
||||
assertThat(record.getJSONObject("values").getString("lastName")).isEqualTo("Kelkhoff");
|
||||
assertThat(record.getJSONObject("displayValues").getString("lastName")).isEqualTo("Kelkhoff");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testNoRecordsFound()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/table/person/query")
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("filter", new QQueryFilter(new QFilterCriteria("lastName", QCriteriaOperator.EQUALS, "Unkelkhoff")))))
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
JSONArray records = jsonObject.getJSONArray("records");
|
||||
assertThat(records.length()).isZero();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** test the table-level meta-data endpoint for a non-real name
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void testTableNotFound()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/table/notAnActualTable/query").asString();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// expect a non-existing table to 403, the same as one that does exist but that you don't have permission to //
|
||||
// to kinda hide from someone what is or isn't a real table (as a security thing i guess) //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
assertEquals(HttpStatus.FORBIDDEN_403, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals(1, jsonObject.keySet().size(), "Number of top-level keys");
|
||||
String error = jsonObject.getString("error");
|
||||
assertThat(error).contains("Permission denied");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testPostingTableVariant() throws QException
|
||||
{
|
||||
////////////////////////////////////
|
||||
// insert our two variant options //
|
||||
////////////////////////////////////
|
||||
QContext.init(TestUtils.defineInstance(), new QSystemUserSession());
|
||||
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_MEMORY_VARIANT_OPTIONS).withRecords(List.of(
|
||||
new QRecord().withValue("id", 1).withValue("name", "People"),
|
||||
new QRecord().withValue("id", 2).withValue("name", "Planets")
|
||||
)));
|
||||
|
||||
////////////////////////////////////////
|
||||
// insert some data into each variant //
|
||||
////////////////////////////////////////
|
||||
QContext.getQSession().setBackendVariants(Map.of(TestUtils.TABLE_NAME_MEMORY_VARIANT_OPTIONS, 1));
|
||||
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_MEMORY_VARIANT_DATA).withRecords(List.of(
|
||||
new QRecord().withValue("name", "Tom"),
|
||||
new QRecord().withValue("name", "Sally")
|
||||
)));
|
||||
|
||||
QContext.getQSession().setBackendVariants(Map.of(TestUtils.TABLE_NAME_MEMORY_VARIANT_OPTIONS, 2));
|
||||
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_MEMORY_VARIANT_DATA).withRecords(List.of(
|
||||
new QRecord().withValue("name", "Mars"),
|
||||
new QRecord().withValue("name", "Jupiter"),
|
||||
new QRecord().withValue("name", "Saturn")
|
||||
)));
|
||||
|
||||
//////////////////////////////////////////
|
||||
// query with no variant - expect error //
|
||||
//////////////////////////////////////////
|
||||
String url = getBaseUrlAndPath() + "/table/" + TestUtils.TABLE_NAME_MEMORY_VARIANT_DATA + "/query";
|
||||
HttpResponse<String> response = Unirest.post(url)
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of()))
|
||||
.asString();
|
||||
assertEquals(500, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals("Could not find Backend Variant information in session under key 'memoryVariantOptions' for Backend 'memoryWithVariants'", jsonObject.getString("error"));
|
||||
|
||||
//////////////////////////////
|
||||
// query for people variant //
|
||||
//////////////////////////////
|
||||
response = Unirest.post(url)
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("tableVariant", new TableVariant().withType("memoryVariantOptions").withId("1"))))
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
JSONArray records = jsonObject.getJSONArray("records");
|
||||
assertThat(records.length()).isEqualTo(2);
|
||||
JSONObject record = records.getJSONObject(0);
|
||||
assertThat(record.getJSONObject("values").getString("name")).isEqualTo("Tom");
|
||||
|
||||
///////////////////////////////
|
||||
// query for planets variant //
|
||||
///////////////////////////////
|
||||
response = Unirest.post(url)
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("tableVariant", new TableVariant().withType("memoryVariantOptions").withId("2"))))
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
records = jsonObject.getJSONArray("records");
|
||||
assertThat(records.length()).isEqualTo(3);
|
||||
record = records.getJSONObject(0);
|
||||
assertThat(record.getJSONObject("values").getString("name")).isEqualTo("Mars");
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// query with unknown variant - expect error //
|
||||
///////////////////////////////////////////////
|
||||
response = Unirest.post(url)
|
||||
.contentType(ContentType.APPLICATION_JSON.getMimeType())
|
||||
.body(JsonUtils.toJson(Map.of("tableVariant", new TableVariant().withType("memoryVariantOptions").withId("3"))))
|
||||
.asString();
|
||||
assertEquals(500, response.getStatus());
|
||||
jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals("Could not find Backend Variant in table memoryVariantOptions with id '3'", jsonObject.getString("error"));
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user