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 TableMetaDataSpecV1());
|
||||||
list.add(new TableQuerySpecV1());
|
list.add(new TableQuerySpecV1());
|
||||||
|
list.add(new TableCountSpecV1());
|
||||||
|
|
||||||
list.add(new ProcessMetaDataSpecV1());
|
list.add(new ProcessMetaDataSpecV1());
|
||||||
list.add(new ProcessInitSpecV1());
|
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
|
public class TableMetaDataLight implements ToSchema
|
||||||
{
|
{
|
||||||
@OpenAPIExclude()
|
@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.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
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.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
|
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.JsonUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.TableVariant;
|
||||||
import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
|
import com.kingsrook.qqq.openapi.model.Content;
|
||||||
import com.kingsrook.qqq.middleware.javalin.executors.io.QueryMiddlewareInput;
|
import com.kingsrook.qqq.openapi.model.RequestBody;
|
||||||
import com.kingsrook.qqq.openapi.model.Schema;
|
import com.kingsrook.qqq.openapi.model.Schema;
|
||||||
import com.kingsrook.qqq.openapi.model.Type;
|
import com.kingsrook.qqq.openapi.model.Type;
|
||||||
|
import io.javalin.http.ContentType;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
@ -51,99 +50,28 @@ public class QuerySpecUtils
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
**
|
**
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
public static Schema defineQueryJoinsSchema()
|
public static RequestBody defineQueryOrCountRequestBody()
|
||||||
{
|
{
|
||||||
Schema queryJoinsSchema = new Schema()
|
return new RequestBody()
|
||||||
.withType(Type.ARRAY)
|
.withContent(Map.of(
|
||||||
.withItems(new Schema()
|
ContentType.APPLICATION_JSON.getMimeType(), new Content()
|
||||||
.withProperties(MapBuilder.of(
|
.withSchema(new Schema()
|
||||||
"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)
|
.withType(Type.OBJECT)
|
||||||
.withExample(List.of(
|
.withProperties(Map.of(
|
||||||
JsonUtils.toJson(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.LESS_THAN, 5)))
|
"filter", new Schema()
|
||||||
))
|
.withDescription("QueryFilter to specify matching records to be returned by the query")
|
||||||
.withProperties(MapBuilder.of(
|
.withRef("#/components/schemas/QueryFilter"),
|
||||||
"criteria", new Schema()
|
"joins", new Schema()
|
||||||
|
.withDescription("QueryJoin objects to specify tables to be joined into the query")
|
||||||
.withType(Type.ARRAY)
|
.withType(Type.ARRAY)
|
||||||
.withItems(new Schema()
|
.withItems(new Schema()
|
||||||
.withProperties(MapBuilder.of(
|
.withRef("#/components/schemas/QueryJoin")),
|
||||||
"fieldName", new Schema()
|
"tableVariant", new Schema()
|
||||||
.withType(Type.STRING),
|
.withDescription("For tables that use variant backends, specification of which variant to use.")
|
||||||
"operator", new Schema()
|
.withRef("#/components/schemas/TableVariant")
|
||||||
.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()
|
|
||||||
.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)
|
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
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
|
||||||
{
|
{
|
||||||
|
if(requestBody.has("filter"))
|
||||||
QQueryFilter filter = null;
|
|
||||||
String filterParam = paramMap.get("filter");
|
|
||||||
if(StringUtils.hasContent(filterParam))
|
|
||||||
{
|
{
|
||||||
filter = JsonUtils.toObject(filterParam, QQueryFilter.class);
|
Object filterFromJson = requestBody.get("filter");
|
||||||
}
|
if(filterFromJson instanceof JSONObject filterJsonObject)
|
||||||
|
|
||||||
List<QueryJoin> queryJoins = null;
|
|
||||||
String queryJoinsParam = paramMap.get("queryJoins");
|
|
||||||
if(StringUtils.hasContent(queryJoinsParam))
|
|
||||||
{
|
{
|
||||||
queryJoins = new ArrayList<>();
|
return (JsonUtils.toObject(filterJsonObject.toString(), QQueryFilter.class));
|
||||||
|
|
||||||
JSONArray queryJoinsJSON = new JSONArray(queryJoinsParam);
|
|
||||||
for(int i = 0; i < queryJoinsJSON.length(); i++)
|
|
||||||
{
|
|
||||||
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 (null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new QueryMiddlewareInput()
|
|
||||||
.withTable(paramMap.get("table"))
|
|
||||||
.withFilter(filter)
|
/***************************************************************************
|
||||||
.withQueryJoins(queryJoins);
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
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"),
|
AUTHENTICATION("Authentication"),
|
||||||
GENERAL("General"),
|
GENERAL("General"),
|
||||||
QUERY("Query"),
|
TABLES("Tables"),
|
||||||
INSERT("Insert"),
|
|
||||||
UPDATE("Update"),
|
|
||||||
DELETE("Delete"),
|
|
||||||
PROCESSES("Processes"),
|
PROCESSES("Processes"),
|
||||||
REPORTS("Reports"),
|
REPORTS("Reports"),
|
||||||
WIDGETS("Widgets");
|
WIDGETS("Widgets");
|
||||||
|
@ -130,6 +130,42 @@ components:
|
|||||||
description: "Description of the error"
|
description: "Description of the error"
|
||||||
type: "string"
|
type: "string"
|
||||||
type: "object"
|
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:
|
FieldAdornment:
|
||||||
properties:
|
properties:
|
||||||
type:
|
type:
|
||||||
@ -193,6 +229,45 @@ components:
|
|||||||
description: "Data-type for this field"
|
description: "Data-type for this field"
|
||||||
type: "string"
|
type: "string"
|
||||||
type: "object"
|
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:
|
FrontendComponent:
|
||||||
properties:
|
properties:
|
||||||
type:
|
type:
|
||||||
@ -353,6 +428,34 @@ components:
|
|||||||
\ has permission to see that they exist)."
|
\ has permission to see that they exist)."
|
||||||
type: "object"
|
type: "object"
|
||||||
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:
|
ProcessMetaData:
|
||||||
properties:
|
properties:
|
||||||
frontendSteps:
|
frontendSteps:
|
||||||
@ -720,6 +823,157 @@ components:
|
|||||||
\ additional fields will be set."
|
\ additional fields will be set."
|
||||||
type: "string"
|
type: "string"
|
||||||
type: "object"
|
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:
|
TableMetaDataLight:
|
||||||
properties:
|
properties:
|
||||||
capabilities:
|
capabilities:
|
||||||
@ -765,6 +1019,157 @@ components:
|
|||||||
\ for the table that supplies variants for this table."
|
\ for the table that supplies variants for this table."
|
||||||
type: "string"
|
type: "string"
|
||||||
type: "object"
|
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:
|
WidgetBlock:
|
||||||
properties:
|
properties:
|
||||||
blockId:
|
blockId:
|
||||||
@ -1532,6 +1937,151 @@ paths:
|
|||||||
summary: "Get instance metaData"
|
summary: "Get instance metaData"
|
||||||
tags:
|
tags:
|
||||||
- "General"
|
- "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}:
|
/qqq/v1/metaData/process/{processName}:
|
||||||
get:
|
get:
|
||||||
description: "Load the full metadata for a single process, including all screens\
|
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.AssociatedScript;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
|
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.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.savedviews.SavedViewsMetaDataProvider;
|
||||||
import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider;
|
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.session.QSession;
|
||||||
import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage;
|
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.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.core.processes.implementations.mock.MockBackendStep;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
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_PERSON = "person";
|
||||||
public static final String TABLE_NAME_PET = "pet";
|
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_GREET_PEOPLE_INTERACTIVE = "greetInteractive";
|
||||||
public static final String PROCESS_NAME_SIMPLE_SLEEP = "simpleSleep";
|
public static final String PROCESS_NAME_SIMPLE_SLEEP = "simpleSleep";
|
||||||
public static final String PROCESS_NAME_SIMPLE_THROW = "simpleThrow";
|
public static final String PROCESS_NAME_SIMPLE_THROW = "simpleThrow";
|
||||||
@ -191,6 +197,8 @@ public class TestUtils
|
|||||||
qInstance.addPossibleValueSource(definePossibleValueSourcePerson());
|
qInstance.addPossibleValueSource(definePossibleValueSourcePerson());
|
||||||
defineWidgets(qInstance);
|
defineWidgets(qInstance);
|
||||||
|
|
||||||
|
defineMemoryBackendVariantUseCases(qInstance);
|
||||||
|
|
||||||
List<JavalinRouteProviderMetaData> routeProviders = new ArrayList<>();
|
List<JavalinRouteProviderMetaData> routeProviders = new ArrayList<>();
|
||||||
routeProviders.add(new JavalinRouteProviderMetaData()
|
routeProviders.add(new JavalinRouteProviderMetaData()
|
||||||
.withHostedPath("/statically-served")
|
.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;
|
service = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestMiddlewareVersion testMiddlewareVersion = new TestMiddlewareVersion();
|
||||||
|
|
||||||
if(service == null)
|
if(service == null)
|
||||||
{
|
{
|
||||||
service = Javalin.create(config ->
|
service = Javalin.create(config ->
|
||||||
@ -117,12 +119,12 @@ public abstract class SpecTestBase
|
|||||||
|
|
||||||
AbstractEndpointSpec<?, ?, ?> spec = getSpec();
|
AbstractEndpointSpec<?, ?, ?> spec = getSpec();
|
||||||
spec.setQInstance(qInstance);
|
spec.setQInstance(qInstance);
|
||||||
config.router.apiBuilder(() -> spec.defineRoute(getVersion()));
|
config.router.apiBuilder(() -> spec.defineRoute(testMiddlewareVersion, getVersion()));
|
||||||
|
|
||||||
for(AbstractEndpointSpec<?, ?, ?> additionalSpec : getAdditionalSpecs())
|
for(AbstractEndpointSpec<?, ?, ?> additionalSpec : getAdditionalSpecs())
|
||||||
{
|
{
|
||||||
additionalSpec.setQInstance(qInstance);
|
additionalSpec.setQInstance(qInstance);
|
||||||
config.router.apiBuilder(() -> additionalSpec.defineRoute(getVersion()));
|
config.router.apiBuilder(() -> additionalSpec.defineRoute(testMiddlewareVersion, getVersion()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).start(PORT);
|
).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