mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-09-28 18:53:37 +00:00
Moving qqq-backend-core into its own subdir
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleDispatcher;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ActionHelper
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void validateSession(AbstractActionInput request) throws QException
|
||||
{
|
||||
QAuthenticationModuleDispatcher qAuthenticationModuleDispatcher = new QAuthenticationModuleDispatcher();
|
||||
QAuthenticationModuleInterface authenticationModule = qAuthenticationModuleDispatcher.getQModule(request.getAuthenticationMetaData());
|
||||
if(!authenticationModule.isSessionValid(request.getSession()))
|
||||
{
|
||||
throw new QAuthenticationException("Invalid session in request");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.async;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface to be implemented (as lambdas), for working with AsyncJobManager.
|
||||
*******************************************************************************/
|
||||
@FunctionalInterface
|
||||
public interface AsyncJob<T>
|
||||
{
|
||||
/*******************************************************************************
|
||||
** Run the job, taking a callback object (where you can communicate your status
|
||||
** back), returning a result when you're done..
|
||||
*******************************************************************************/
|
||||
T run(AsyncJobCallback callback) throws Exception;
|
||||
}
|
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.async;
|
||||
|
||||
|
||||
import java.util.UUID;
|
||||
import com.kingsrook.qqq.backend.core.state.StateType;
|
||||
import com.kingsrook.qqq.backend.core.state.UUIDAndTypeStateKey;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Argument passed to an AsyncJob when it runs, which can be used to communicate
|
||||
** data back out of the job.
|
||||
**
|
||||
** TODO - future - allow cancellation to be indicated here?
|
||||
*******************************************************************************/
|
||||
public class AsyncJobCallback
|
||||
{
|
||||
private UUID jobUUID;
|
||||
private AsyncJobStatus asyncJobStatus;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AsyncJobCallback(UUID jobUUID, AsyncJobStatus asyncJobStatus)
|
||||
{
|
||||
this.jobUUID = jobUUID;
|
||||
this.asyncJobStatus = asyncJobStatus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Update the message
|
||||
*******************************************************************************/
|
||||
public void updateStatus(String message)
|
||||
{
|
||||
this.asyncJobStatus.setMessage(message);
|
||||
storeUpdatedStatus();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Update all 3 status fields
|
||||
*******************************************************************************/
|
||||
public void updateStatus(String message, int current, int total)
|
||||
{
|
||||
this.asyncJobStatus.setMessage(message);
|
||||
this.asyncJobStatus.setCurrent(current);
|
||||
this.asyncJobStatus.setTotal(total);
|
||||
storeUpdatedStatus();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Update the current and total fields (e.g., 1 of 2, 2 of 2, 3 of 2)
|
||||
*******************************************************************************/
|
||||
public void updateStatus(int current, int total)
|
||||
{
|
||||
this.asyncJobStatus.setCurrent(current);
|
||||
this.asyncJobStatus.setTotal(total);
|
||||
storeUpdatedStatus();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Remove the values from the current & total fields
|
||||
*******************************************************************************/
|
||||
public void clearCurrentAndTotal()
|
||||
{
|
||||
this.asyncJobStatus.setCurrent(null);
|
||||
this.asyncJobStatus.setTotal(null);
|
||||
storeUpdatedStatus();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected void storeUpdatedStatus()
|
||||
{
|
||||
AsyncJobManager.getStateProvider().put(new UUIDAndTypeStateKey(jobUUID, StateType.ASYNC_JOB_STATUS), asyncJobStatus);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.async;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.state.InMemoryStateProvider;
|
||||
import com.kingsrook.qqq.backend.core.state.StateProviderInterface;
|
||||
import com.kingsrook.qqq.backend.core.state.StateType;
|
||||
import com.kingsrook.qqq.backend.core.state.UUIDAndTypeStateKey;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Class to manage running asynchronous actions, and working with their statuses.
|
||||
*******************************************************************************/
|
||||
public class AsyncJobManager
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(AsyncJobManager.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Start a job - if it finishes within the specified timeout, get its results,
|
||||
** else, get back an exception with the job id.
|
||||
*******************************************************************************/
|
||||
public <T extends Serializable> T startJob(long timeout, TimeUnit timeUnit, AsyncJob<T> asyncJob) throws JobGoingAsyncException, QException
|
||||
{
|
||||
return (startJob("Anonymous", timeout, timeUnit, asyncJob));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Start a job - if it finishes within the specified timeout, get its results,
|
||||
** else, get back an exception with the job id.
|
||||
*******************************************************************************/
|
||||
public <T extends Serializable> T startJob(String jobName, long timeout, TimeUnit timeUnit, AsyncJob<T> asyncJob) throws JobGoingAsyncException, QException
|
||||
{
|
||||
UUIDAndTypeStateKey uuidAndTypeStateKey = new UUIDAndTypeStateKey(UUID.randomUUID(), StateType.ASYNC_JOB_STATUS);
|
||||
AsyncJobStatus asyncJobStatus = new AsyncJobStatus();
|
||||
asyncJobStatus.setState(AsyncJobState.RUNNING);
|
||||
getStateProvider().put(uuidAndTypeStateKey, asyncJobStatus);
|
||||
|
||||
try
|
||||
{
|
||||
CompletableFuture<T> future = CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
return (runAsyncJob(jobName, asyncJob, uuidAndTypeStateKey, asyncJobStatus));
|
||||
});
|
||||
|
||||
if(timeout == 0)
|
||||
{
|
||||
throw (new JobGoingAsyncException(uuidAndTypeStateKey.getUuid().toString()));
|
||||
}
|
||||
|
||||
T result = future.get(timeout, timeUnit);
|
||||
return (result);
|
||||
}
|
||||
catch(InterruptedException | ExecutionException e)
|
||||
{
|
||||
throw (new QException("Error running job", e));
|
||||
}
|
||||
catch(TimeoutException e)
|
||||
{
|
||||
LOG.info("Job going async " + uuidAndTypeStateKey.getUuid());
|
||||
throw (new JobGoingAsyncException(uuidAndTypeStateKey.getUuid().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Start a job, and always, just get back the job UUID.
|
||||
*******************************************************************************/
|
||||
public <T extends Serializable> String startJob(AsyncJob<T> asyncJob) throws QException
|
||||
{
|
||||
return (startJob("Anonymous", asyncJob));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Start a job, and always, just get back the job UUID.
|
||||
*******************************************************************************/
|
||||
public <T extends Serializable> String startJob(String jobName, AsyncJob<T> asyncJob) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
startJob(jobName, 0, TimeUnit.MILLISECONDS, asyncJob);
|
||||
throw (new QException("Job was expected to go asynchronous, but did not"));
|
||||
}
|
||||
catch(JobGoingAsyncException jgae)
|
||||
{
|
||||
return (jgae.getJobUUID());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** run the job.
|
||||
*******************************************************************************/
|
||||
private <T extends Serializable> T runAsyncJob(String jobName, AsyncJob<T> asyncJob, UUIDAndTypeStateKey uuidAndTypeStateKey, AsyncJobStatus asyncJobStatus)
|
||||
{
|
||||
String originalThreadName = Thread.currentThread().getName();
|
||||
Thread.currentThread().setName("Job:" + jobName + ":" + uuidAndTypeStateKey.getUuid().toString().substring(0, 8));
|
||||
try
|
||||
{
|
||||
LOG.info("Starting job " + uuidAndTypeStateKey.getUuid());
|
||||
T result = asyncJob.run(new AsyncJobCallback(uuidAndTypeStateKey.getUuid(), asyncJobStatus));
|
||||
asyncJobStatus.setState(AsyncJobState.COMPLETE);
|
||||
getStateProvider().put(uuidAndTypeStateKey, asyncJobStatus);
|
||||
LOG.info("Completed job " + uuidAndTypeStateKey.getUuid());
|
||||
return (result);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
asyncJobStatus.setState(AsyncJobState.ERROR);
|
||||
asyncJobStatus.setCaughtException(e);
|
||||
getStateProvider().put(uuidAndTypeStateKey, asyncJobStatus);
|
||||
LOG.warn("Job " + uuidAndTypeStateKey.getUuid() + " ended with an exception: ", e);
|
||||
throw (new CompletionException(e));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setName(originalThreadName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get the status of the job identified by the given UUID.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Optional<AsyncJobStatus> getJobStatus(String uuid)
|
||||
{
|
||||
UUIDAndTypeStateKey uuidAndTypeStateKey = new UUIDAndTypeStateKey(UUID.fromString(uuid), StateType.ASYNC_JOB_STATUS);
|
||||
return (getStateProvider().get(AsyncJobStatus.class, uuidAndTypeStateKey));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Load an instance of the appropriate state provider
|
||||
**
|
||||
*******************************************************************************/
|
||||
static StateProviderInterface getStateProvider()
|
||||
{
|
||||
// TODO - read this from somewhere in meta data eh?
|
||||
return InMemoryStateProvider.getInstance();
|
||||
|
||||
// todo - by using JSON serialization internally, this makes stupidly large payloads and crashes things.
|
||||
// return TempFileStateProvider.getInstance();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.async;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Possible states for an async job's "running"-ness.
|
||||
*******************************************************************************/
|
||||
public enum AsyncJobState
|
||||
{
|
||||
RUNNING,
|
||||
COMPLETE,
|
||||
ERROR
|
||||
}
|
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.async;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Object to track current status of an async job - e.g., its state, and some
|
||||
** messages from the backend like "x of y"
|
||||
*******************************************************************************/
|
||||
public class AsyncJobStatus implements Serializable
|
||||
{
|
||||
private AsyncJobState state;
|
||||
private String message;
|
||||
private Integer current;
|
||||
private Integer total;
|
||||
private Exception caughtException;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "AsyncJobStatus{"
|
||||
+ "state=" + state
|
||||
+ ", message='" + message + '\''
|
||||
+ ", current=" + current
|
||||
+ ", total=" + total
|
||||
+ ", caughtException=" + caughtException
|
||||
+ '}';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for state
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AsyncJobState getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for state
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setState(AsyncJobState state)
|
||||
{
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for message
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for message
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setMessage(String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for current
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getCurrent()
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for current
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCurrent(Integer current)
|
||||
{
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for total
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getTotal()
|
||||
{
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for total
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTotal(Integer total)
|
||||
{
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for caughtException
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Exception getCaughtException()
|
||||
{
|
||||
return caughtException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for caughtException
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCaughtException(Exception caughtException)
|
||||
{
|
||||
this.caughtException = caughtException;
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.async;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Exception thrown by AsyncJobManager, not to indicate an error, per se, but
|
||||
** rather to indicate that a job has taken too long, as is now "going async".
|
||||
**
|
||||
** So, this exception contains the jobUUID.
|
||||
*******************************************************************************/
|
||||
public class JobGoingAsyncException extends Exception
|
||||
{
|
||||
private String jobUUID;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public JobGoingAsyncException(String jobUUID)
|
||||
{
|
||||
this.jobUUID = jobUUID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for jobUUID
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getJobUUID()
|
||||
{
|
||||
return jobUUID;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.interfaces;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface for the Count action.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface CountInterface
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
CountOutput execute(CountInput countInput) throws QException;
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.interfaces;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface for the Delete action.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface DeleteInterface
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
DeleteOutput execute(DeleteInput deleteInput) throws QException;
|
||||
|
||||
/*******************************************************************************
|
||||
** Specify whether this particular module's delete action natively supports
|
||||
** receiving a queryFilter as input (e.g., SQL does). If the module doesn't
|
||||
** support a query filter, then the qqq framework (DeleteAction) will, if it
|
||||
** receives a queryFilter in its input, it will execute the query, and pass
|
||||
** the list of primary keys down into the module's delete implementation.
|
||||
*******************************************************************************/
|
||||
default boolean supportsQueryFilterInput()
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.interfaces;
|
||||
|
||||
|
||||
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.insert.InsertOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface for the Insert action.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface InsertInterface
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
InsertOutput execute(InsertInput insertInput) throws QException;
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.interfaces;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface for the Query action.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface QueryInterface
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
QueryOutput execute(QueryInput queryInput) throws QException;
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.interfaces;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface for the update action.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface UpdateInterface
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
UpdateOutput execute(UpdateInput updateInput) throws QException;
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.metadata;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action to fetch top-level meta-data in a qqq instance.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class MetaDataAction
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public MetaDataOutput execute(MetaDataInput metaDataInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(metaDataInput);
|
||||
|
||||
// todo pre-customization - just get to modify the request?
|
||||
MetaDataOutput metaDataOutput = new MetaDataOutput();
|
||||
|
||||
Map<String, QFrontendTableMetaData> tables = new LinkedHashMap<>();
|
||||
for(Map.Entry<String, QTableMetaData> entry : metaDataInput.getInstance().getTables().entrySet())
|
||||
{
|
||||
tables.put(entry.getKey(), new QFrontendTableMetaData(entry.getValue(), false));
|
||||
}
|
||||
metaDataOutput.setTables(tables);
|
||||
|
||||
Map<String, QFrontendProcessMetaData> processes = new LinkedHashMap<>();
|
||||
for(Map.Entry<String, QProcessMetaData> entry : metaDataInput.getInstance().getProcesses().entrySet())
|
||||
{
|
||||
processes.put(entry.getKey(), new QFrontendProcessMetaData(entry.getValue(), false));
|
||||
}
|
||||
metaDataOutput.setProcesses(processes);
|
||||
|
||||
// todo post-customization - can do whatever w/ the result if you want
|
||||
|
||||
return metaDataOutput;
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.metadata;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
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.ProcessMetaDataInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.ProcessMetaDataOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action to fetch meta-data for a process.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessMetaDataAction
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaDataOutput execute(ProcessMetaDataInput processMetaDataInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(processMetaDataInput);
|
||||
|
||||
// todo pre-customization - just get to modify the request?
|
||||
ProcessMetaDataOutput processMetaDataOutput = new ProcessMetaDataOutput();
|
||||
|
||||
QProcessMetaData process = processMetaDataInput.getInstance().getProcess(processMetaDataInput.getProcessName());
|
||||
if(process == null)
|
||||
{
|
||||
throw (new QNotFoundException("Process [" + processMetaDataInput.getProcessName() + "] was not found."));
|
||||
}
|
||||
processMetaDataOutput.setProcess(new QFrontendProcessMetaData(process, true));
|
||||
|
||||
// todo post-customization - can do whatever w/ the result if you want
|
||||
|
||||
return processMetaDataOutput;
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.metadata;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
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.TableMetaDataInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.TableMetaDataOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action to fetch meta-data for a table.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableMetaDataAction
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableMetaDataOutput execute(TableMetaDataInput tableMetaDataInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(tableMetaDataInput);
|
||||
|
||||
// todo pre-customization - just get to modify the request?
|
||||
TableMetaDataOutput tableMetaDataOutput = new TableMetaDataOutput();
|
||||
|
||||
QTableMetaData table = tableMetaDataInput.getInstance().getTable(tableMetaDataInput.getTableName());
|
||||
if(table == null)
|
||||
{
|
||||
throw (new QNotFoundException("Table [" + tableMetaDataInput.getTableName() + "] was not found."));
|
||||
}
|
||||
tableMetaDataOutput.setTable(new QFrontendTableMetaData(table, true));
|
||||
|
||||
// todo post-customization - can do whatever w/ the result if you want
|
||||
|
||||
return tableMetaDataOutput;
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.processes;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Simple interface that Backend Steps (e.g., code within processes) must implement
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface BackendStep
|
||||
{
|
||||
/*******************************************************************************
|
||||
** Execute the backend step - using the request as input, and the result as output.
|
||||
**
|
||||
** TODO - think about - why take the Result object as a param, instead of return it?
|
||||
** Is this way easier for inter-language operability maybe?
|
||||
* Also - there's way too much "process-specific gunk" in the Request object - can we simplify it?
|
||||
*******************************************************************************/
|
||||
void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException;
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** When a process/function can't run because it's missing data, this interface
|
||||
** defines how the core framework goes back to a middleware (and possibly to a
|
||||
** frontend) to get the data.
|
||||
*******************************************************************************/
|
||||
public interface QProcessCallback
|
||||
{
|
||||
/*******************************************************************************
|
||||
** Get the filter query for this callback.
|
||||
*******************************************************************************/
|
||||
QQueryFilter getQueryFilter();
|
||||
|
||||
/*******************************************************************************
|
||||
** Get the field values for this callback.
|
||||
*******************************************************************************/
|
||||
Map<String, Serializable> getFieldValues(List<QFieldMetaData> fields);
|
||||
}
|
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
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.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action handler for running backend steps as part of processes.
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class RunBackendStepAction
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(RunBackendStepAction.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepOutput execute(RunBackendStepInput runBackendStepInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(runBackendStepInput);
|
||||
|
||||
QProcessMetaData process = runBackendStepInput.getInstance().getProcess(runBackendStepInput.getProcessName());
|
||||
if(process == null)
|
||||
{
|
||||
throw new QException("Process [" + runBackendStepInput.getProcessName() + "] is not defined in this instance.");
|
||||
}
|
||||
|
||||
QStepMetaData stepMetaData = process.getStep(runBackendStepInput.getStepName());
|
||||
if(stepMetaData == null)
|
||||
{
|
||||
throw new QException("Step [" + runBackendStepInput.getStepName() + "] is not defined in the process [" + process.getName() + "]");
|
||||
}
|
||||
|
||||
if(!(stepMetaData instanceof QBackendStepMetaData backendStepMetaData))
|
||||
{
|
||||
throw new QException("Step [" + runBackendStepInput.getStepName() + "] is not a backend step.");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// ensure input data is set as needed - use callback object to get anything missing //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
ensureRecordsAreInRequest(runBackendStepInput, backendStepMetaData);
|
||||
ensureInputFieldsAreInRequest(runBackendStepInput, backendStepMetaData);
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// load and run the user-defined code that actually does the work //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
return (runStepCode(backendStepMetaData.getCode(), runBackendStepInput));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** check if this step needs any input fields - and if so, if we need to get one
|
||||
** via the callback
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void ensureInputFieldsAreInRequest(RunBackendStepInput runBackendStepInput, QBackendStepMetaData step) throws QException
|
||||
{
|
||||
QFunctionInputMetaData inputMetaData = step.getInputMetaData();
|
||||
if(inputMetaData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<QFieldMetaData> fieldsToGet = new ArrayList<>();
|
||||
List<QFieldMetaData> requiredFieldsMissing = new ArrayList<>();
|
||||
for(QFieldMetaData field : inputMetaData.getFieldList())
|
||||
{
|
||||
Serializable value = runBackendStepInput.getValue(field.getName());
|
||||
if(value == null)
|
||||
{
|
||||
if(field.getDefaultValue() != null)
|
||||
{
|
||||
runBackendStepInput.addValue(field.getName(), field.getDefaultValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldsToGet.add(field);
|
||||
if(field.getIsRequired())
|
||||
{
|
||||
requiredFieldsMissing.add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!fieldsToGet.isEmpty())
|
||||
{
|
||||
QProcessCallback callback = runBackendStepInput.getCallback();
|
||||
if(callback == null)
|
||||
{
|
||||
if(requiredFieldsMissing.isEmpty())
|
||||
{
|
||||
///////////////////////////////////////////////////////////////
|
||||
// if no required fields are missing, just return gracefully //
|
||||
///////////////////////////////////////////////////////////////
|
||||
return;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// but if any required fields ARE missing, then that's an error. //
|
||||
///////////////////////////////////////////////////////////////////
|
||||
LOG.info("Missing value for required fields: " + requiredFieldsMissing.stream().map(QFieldMetaData::getName).collect(Collectors.joining(", ")));
|
||||
throw (new QUserFacingException("Missing values for one or more fields",
|
||||
new QException("Function is missing values for fields, but no callback was present to request fields from a user")));
|
||||
}
|
||||
|
||||
Map<String, Serializable> fieldValues = callback.getFieldValues(fieldsToGet);
|
||||
if(fieldValues != null)
|
||||
{
|
||||
for(Map.Entry<String, Serializable> entry : fieldValues.entrySet())
|
||||
{
|
||||
runBackendStepInput.addValue(entry.getKey(), entry.getValue());
|
||||
// todo - check to make sure got values back?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** check if this step uses a record list - and if so, if we need to get one
|
||||
** via the callback
|
||||
*******************************************************************************/
|
||||
private void ensureRecordsAreInRequest(RunBackendStepInput runBackendStepInput, QBackendStepMetaData step) throws QException
|
||||
{
|
||||
QFunctionInputMetaData inputMetaData = step.getInputMetaData();
|
||||
if(inputMetaData != null && inputMetaData.getRecordListMetaData() != null)
|
||||
{
|
||||
if(CollectionUtils.nullSafeIsEmpty(runBackendStepInput.getRecords()))
|
||||
{
|
||||
QueryInput queryInput = new QueryInput(runBackendStepInput.getInstance());
|
||||
queryInput.setSession(runBackendStepInput.getSession());
|
||||
queryInput.setTableName(inputMetaData.getRecordListMetaData().getTableName());
|
||||
|
||||
// todo - handle this being async (e.g., http)
|
||||
// seems like it just needs to throw, breaking this flow, and to send a response to the frontend, directing it to prompt the user for the needed data
|
||||
// then this step can re-run, hopefully with the needed data.
|
||||
|
||||
QProcessCallback callback = runBackendStepInput.getCallback();
|
||||
if(callback == null)
|
||||
{
|
||||
throw (new QUserFacingException("Missing input records.",
|
||||
new QException("Function is missing input records, but no callback was present to request fields from a user")));
|
||||
}
|
||||
|
||||
queryInput.setFilter(callback.getQueryFilter());
|
||||
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
runBackendStepInput.setRecords(queryOutput.getRecords());
|
||||
// todo - handle 0 results found?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private RunBackendStepOutput runStepCode(QCodeReference code, RunBackendStepInput runBackendStepInput)
|
||||
{
|
||||
RunBackendStepOutput runBackendStepOutput = new RunBackendStepOutput();
|
||||
try
|
||||
{
|
||||
runBackendStepOutput.seedFromRequest(runBackendStepInput);
|
||||
|
||||
Class<?> codeClass = Class.forName(code.getName());
|
||||
Object codeObject = codeClass.getConstructor().newInstance();
|
||||
if(!(codeObject instanceof BackendStep backendStepCodeObject))
|
||||
{
|
||||
throw (new QException("The supplied code [" + codeClass.getName() + "] is not an instance of FunctionBody"));
|
||||
}
|
||||
|
||||
backendStepCodeObject.run(runBackendStepInput, runBackendStepOutput);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
runBackendStepOutput = new RunBackendStepOutput();
|
||||
runBackendStepOutput.setException(e);
|
||||
LOG.info("Error running backend step code", e);
|
||||
}
|
||||
|
||||
return (runBackendStepOutput);
|
||||
}
|
||||
}
|
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessState;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.state.InMemoryStateProvider;
|
||||
import com.kingsrook.qqq.backend.core.state.StateProviderInterface;
|
||||
import com.kingsrook.qqq.backend.core.state.StateType;
|
||||
import com.kingsrook.qqq.backend.core.state.UUIDAndTypeStateKey;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action handler for running q-processes (which are a sequence of q-functions).
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class RunProcessAction
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(RunProcessAction.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessOutput execute(RunProcessInput runProcessInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(runProcessInput);
|
||||
|
||||
QProcessMetaData process = runProcessInput.getInstance().getProcess(runProcessInput.getProcessName());
|
||||
if(process == null)
|
||||
{
|
||||
throw new QException("Process [" + runProcessInput.getProcessName() + "] is not defined in this instance.");
|
||||
}
|
||||
|
||||
RunProcessOutput runProcessOutput = new RunProcessOutput();
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// generate a UUID for the process, if one wasn't given //
|
||||
//////////////////////////////////////////////////////////
|
||||
if(runProcessInput.getProcessUUID() == null)
|
||||
{
|
||||
runProcessInput.setProcessUUID(UUID.randomUUID().toString());
|
||||
}
|
||||
runProcessOutput.setProcessUUID(runProcessInput.getProcessUUID());
|
||||
|
||||
UUIDAndTypeStateKey stateKey = new UUIDAndTypeStateKey(UUID.fromString(runProcessInput.getProcessUUID()), StateType.PROCESS_STATUS);
|
||||
ProcessState processState = primeProcessState(runProcessInput, stateKey);
|
||||
|
||||
// todo - custom routing
|
||||
List<QStepMetaData> stepList = getAvailableStepList(process, runProcessInput);
|
||||
try
|
||||
{
|
||||
STEP_LOOP:
|
||||
for(QStepMetaData step : stepList)
|
||||
{
|
||||
if(step instanceof QFrontendStepMetaData)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Handle what to do with frontend steps, per request setting //
|
||||
////////////////////////////////////////////////////////////////
|
||||
switch(runProcessInput.getFrontendStepBehavior())
|
||||
{
|
||||
case BREAK ->
|
||||
{
|
||||
LOG.info("Breaking process [" + process.getName() + "] at frontend step (as requested by caller): " + step.getName());
|
||||
processState.setNextStepName(step.getName());
|
||||
break STEP_LOOP;
|
||||
}
|
||||
case SKIP ->
|
||||
{
|
||||
LOG.info("Skipping frontend step [" + step.getName() + "] in process [" + process.getName() + "] (as requested by caller)");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// much less error prone in case this code changes in the future... //
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// noinspection UnnecessaryContinue
|
||||
continue;
|
||||
}
|
||||
case FAIL ->
|
||||
{
|
||||
LOG.info("Throwing error for frontend step [" + step.getName() + "] in process [" + process.getName() + "] (as requested by caller)");
|
||||
throw (new QException("Failing process at step " + step.getName() + " (as requested, to fail on frontend steps)"));
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected value: " + runProcessInput.getFrontendStepBehavior());
|
||||
}
|
||||
}
|
||||
else if(step instanceof QBackendStepMetaData backendStepMetaData)
|
||||
{
|
||||
///////////////////////
|
||||
// Run backend steps //
|
||||
///////////////////////
|
||||
runBackendStep(runProcessInput, process, runProcessOutput, stateKey, backendStepMetaData, process, processState);
|
||||
}
|
||||
else
|
||||
{
|
||||
//////////////////////////////////////////////////
|
||||
// in case we have a different step type, throw //
|
||||
//////////////////////////////////////////////////
|
||||
throw (new QException("Unsure how to run a step of type: " + step.getClass().getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(QException qe)
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
// upon exception (e.g., one thrown by a step), throw it. //
|
||||
////////////////////////////////////////////////////////////
|
||||
throw (qe);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
// upon exception (e.g., one thrown by a step), throw it. //
|
||||
////////////////////////////////////////////////////////////
|
||||
throw (new QException("Error running process", e));
|
||||
}
|
||||
finally
|
||||
{
|
||||
//////////////////////////////////////////////////////
|
||||
// always put the final state in the process result //
|
||||
//////////////////////////////////////////////////////
|
||||
runProcessOutput.setProcessState(processState);
|
||||
}
|
||||
|
||||
return (runProcessOutput);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** When we start running a process (or resuming it), get data in the RunProcessRequest
|
||||
** either from the state provider (if they're found, for a resume).
|
||||
*******************************************************************************/
|
||||
ProcessState primeProcessState(RunProcessInput runProcessInput, UUIDAndTypeStateKey stateKey) throws QException
|
||||
{
|
||||
Optional<ProcessState> optionalProcessState = loadState(stateKey);
|
||||
if(optionalProcessState.isEmpty())
|
||||
{
|
||||
if(runProcessInput.getStartAfterStep() == null)
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// this is fine - it means its our first time running in the backend. //
|
||||
// Go ahead and store the state that we have (e.g., w/ initial records & values) //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
storeState(stateKey, runProcessInput.getProcessState());
|
||||
optionalProcessState = Optional.of(runProcessInput.getProcessState());
|
||||
}
|
||||
else
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if this isn't the first step, but there's no state, then that's a problem, so fail //
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
throw (new QException("Could not find state for process [" + runProcessInput.getProcessName() + "] [" + stateKey.getUuid() + "] in state provider."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// capture any values that the caller may have supplied in the request, before restoring from state //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Map<String, Serializable> valuesFromCaller = runProcessInput.getValues();
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// if there is a previously stored state, use it //
|
||||
///////////////////////////////////////////////////
|
||||
runProcessInput.seedFromProcessState(optionalProcessState.get());
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// if there were values from the caller, put those (back) in the request //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
if(valuesFromCaller != null)
|
||||
{
|
||||
for(Map.Entry<String, Serializable> entry : valuesFromCaller.entrySet())
|
||||
{
|
||||
runProcessInput.addValue(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProcessState processState = optionalProcessState.get();
|
||||
processState.clearNextStepName();
|
||||
return processState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Run a single backend step.
|
||||
*******************************************************************************/
|
||||
private void runBackendStep(RunProcessInput runProcessInput, QProcessMetaData process, RunProcessOutput runProcessOutput, UUIDAndTypeStateKey stateKey, QBackendStepMetaData backendStep, QProcessMetaData qProcessMetaData, ProcessState processState) throws Exception
|
||||
{
|
||||
RunBackendStepInput runBackendStepInput = new RunBackendStepInput(runProcessInput.getInstance(), processState);
|
||||
runBackendStepInput.setProcessName(process.getName());
|
||||
runBackendStepInput.setStepName(backendStep.getName());
|
||||
runBackendStepInput.setTableName(process.getTableName());
|
||||
runBackendStepInput.setSession(runProcessInput.getSession());
|
||||
runBackendStepInput.setCallback(runProcessInput.getCallback());
|
||||
runBackendStepInput.setAsyncJobCallback(runProcessInput.getAsyncJobCallback());
|
||||
RunBackendStepOutput lastFunctionResult = new RunBackendStepAction().execute(runBackendStepInput);
|
||||
storeState(stateKey, lastFunctionResult.getProcessState());
|
||||
|
||||
if(lastFunctionResult.getException() != null)
|
||||
{
|
||||
runProcessOutput.setException(lastFunctionResult.getException());
|
||||
throw (lastFunctionResult.getException());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get the list of steps which are eligible to run.
|
||||
*******************************************************************************/
|
||||
private List<QStepMetaData> getAvailableStepList(QProcessMetaData process, RunProcessInput runProcessInput)
|
||||
{
|
||||
if(runProcessInput.getStartAfterStep() == null)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// if the caller did not supply a 'startAfterStep', then use the full list //
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
return (process.getStepList());
|
||||
}
|
||||
else
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// else, loop until the startAfterStep is found, and return the ones after it //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
boolean foundStartAfterStep = false;
|
||||
List<QStepMetaData> rs = new ArrayList<>();
|
||||
|
||||
for(QStepMetaData step : process.getStepList())
|
||||
{
|
||||
if(foundStartAfterStep)
|
||||
{
|
||||
rs.add(step);
|
||||
}
|
||||
|
||||
if(step.getName().equals(runProcessInput.getStartAfterStep()))
|
||||
{
|
||||
foundStartAfterStep = true;
|
||||
}
|
||||
}
|
||||
return (rs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Load an instance of the appropriate state provider
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static StateProviderInterface getStateProvider()
|
||||
{
|
||||
// TODO - read this from somewhere in meta data eh?
|
||||
return InMemoryStateProvider.getInstance();
|
||||
|
||||
// todo - by using JSON serialization internally, this makes stupidly large payloads and crashes things.
|
||||
// return TempFileStateProvider.getInstance();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** public method to get a process state just by UUID.
|
||||
*******************************************************************************/
|
||||
public static Optional<ProcessState> getState(String processUUID)
|
||||
{
|
||||
return (getStateProvider().get(ProcessState.class, new UUIDAndTypeStateKey(UUID.fromString(processUUID), StateType.PROCESS_STATUS)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Store the process state from a function result to the state provider
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void storeState(UUIDAndTypeStateKey stateKey, ProcessState processState)
|
||||
{
|
||||
getStateProvider().put(stateKey, processState);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Load the process state.
|
||||
**
|
||||
*******************************************************************************/
|
||||
private Optional<ProcessState> loadState(UUIDAndTypeStateKey stateKey)
|
||||
{
|
||||
return (getStateProvider().get(ProcessState.class, stateKey));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.reporting;
|
||||
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.adapters.QRecordToCsvAdapter;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QReportingException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** CSV report format implementation
|
||||
*******************************************************************************/
|
||||
public class CsvReportStreamer implements ReportStreamerInterface
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(CsvReportStreamer.class);
|
||||
|
||||
private final QRecordToCsvAdapter qRecordToCsvAdapter;
|
||||
|
||||
private ReportInput reportInput;
|
||||
private QTableMetaData table;
|
||||
private List<QFieldMetaData> fields;
|
||||
private OutputStream outputStream;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public CsvReportStreamer()
|
||||
{
|
||||
qRecordToCsvAdapter = new QRecordToCsvAdapter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void start(ReportInput reportInput, List<QFieldMetaData> fields) throws QReportingException
|
||||
{
|
||||
this.reportInput = reportInput;
|
||||
this.fields = fields;
|
||||
table = reportInput.getTable();
|
||||
outputStream = this.reportInput.getReportOutputStream();
|
||||
|
||||
writeReportHeaderRow();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void writeReportHeaderRow() throws QReportingException
|
||||
{
|
||||
try
|
||||
{
|
||||
int col = 0;
|
||||
for(QFieldMetaData column : fields)
|
||||
{
|
||||
if(col++ > 0)
|
||||
{
|
||||
outputStream.write(',');
|
||||
}
|
||||
outputStream.write(('"' + column.getLabel() + '"').getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
outputStream.write('\n');
|
||||
outputStream.flush();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QReportingException("Error starting CSV report"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public int takeRecordsFromPipe(RecordPipe recordPipe) throws QReportingException
|
||||
{
|
||||
List<QRecord> qRecords = recordPipe.consumeAvailableRecords();
|
||||
LOG.info("Consuming [" + qRecords.size() + "] records from the pipe");
|
||||
|
||||
try
|
||||
{
|
||||
for(QRecord qRecord : qRecords)
|
||||
{
|
||||
String csv = qRecordToCsvAdapter.recordToCsv(table, qRecord, fields);
|
||||
outputStream.write(csv.getBytes(StandardCharsets.UTF_8));
|
||||
outputStream.flush(); // todo - less often?
|
||||
}
|
||||
return (qRecords.size());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QReportingException("Error writing CSV report", e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void finish()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.reporting;
|
||||
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QReportingException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dhatim.fastexcel.Workbook;
|
||||
import org.dhatim.fastexcel.Worksheet;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Excel report format implementation
|
||||
*******************************************************************************/
|
||||
public class ExcelReportStreamer implements ReportStreamerInterface
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(ExcelReportStreamer.class);
|
||||
|
||||
private ReportInput reportInput;
|
||||
private QTableMetaData table;
|
||||
private List<QFieldMetaData> fields;
|
||||
private OutputStream outputStream;
|
||||
|
||||
private Workbook workbook;
|
||||
private Worksheet worksheet;
|
||||
private int row = 1;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ExcelReportStreamer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void start(ReportInput reportInput, List<QFieldMetaData> fields) throws QReportingException
|
||||
{
|
||||
this.reportInput = reportInput;
|
||||
this.fields = fields;
|
||||
table = reportInput.getTable();
|
||||
outputStream = this.reportInput.getReportOutputStream();
|
||||
|
||||
workbook = new Workbook(outputStream, "QQQ", null);
|
||||
worksheet = workbook.newWorksheet("Sheet 1");
|
||||
|
||||
writeReportHeaderRow();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void writeReportHeaderRow() throws QReportingException
|
||||
{
|
||||
try
|
||||
{
|
||||
int col = 0;
|
||||
for(QFieldMetaData column : fields)
|
||||
{
|
||||
worksheet.value(0, col, column.getLabel());
|
||||
col++;
|
||||
}
|
||||
|
||||
worksheet.flush();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QReportingException("Error starting Excel report"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public int takeRecordsFromPipe(RecordPipe recordPipe) throws QReportingException
|
||||
{
|
||||
List<QRecord> qRecords = recordPipe.consumeAvailableRecords();
|
||||
LOG.info("Consuming [" + qRecords.size() + "] records from the pipe");
|
||||
|
||||
try
|
||||
{
|
||||
for(QRecord qRecord : qRecords)
|
||||
{
|
||||
int col = 0;
|
||||
for(QFieldMetaData column : fields)
|
||||
{
|
||||
Serializable value = qRecord.getValue(column.getName());
|
||||
if(value != null)
|
||||
{
|
||||
if(value instanceof String s)
|
||||
{
|
||||
worksheet.value(row, col, s);
|
||||
}
|
||||
else if(value instanceof Number n)
|
||||
{
|
||||
worksheet.value(row, col, n);
|
||||
}
|
||||
else if(value instanceof Boolean b)
|
||||
{
|
||||
worksheet.value(row, col, b);
|
||||
}
|
||||
else if(value instanceof Date d)
|
||||
{
|
||||
worksheet.value(row, col, d);
|
||||
worksheet.style(row, col).format("yyyy-MM-dd").set();
|
||||
}
|
||||
else if(value instanceof LocalDate d)
|
||||
{
|
||||
worksheet.value(row, col, d);
|
||||
worksheet.style(row, col).format("yyyy-MM-dd").set();
|
||||
}
|
||||
else if(value instanceof LocalDateTime d)
|
||||
{
|
||||
worksheet.value(row, col, d);
|
||||
worksheet.style(row, col).format("yyyy-MM-dd H:mm:ss").set();
|
||||
}
|
||||
else if(value instanceof ZonedDateTime d)
|
||||
{
|
||||
worksheet.value(row, col, d);
|
||||
worksheet.style(row, col).format("yyyy-MM-dd H:mm:ss").set();
|
||||
}
|
||||
else
|
||||
{
|
||||
worksheet.value(row, col, ValueUtils.getValueAsString(value));
|
||||
}
|
||||
}
|
||||
col++;
|
||||
}
|
||||
|
||||
row++;
|
||||
worksheet.flush(); // todo? not at all? or just sometimes?
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
workbook.finish();
|
||||
outputStream.close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
throw (new QReportingException("Error generating Excel report", e));
|
||||
}
|
||||
}
|
||||
|
||||
return (qRecords.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void finish() throws QReportingException
|
||||
{
|
||||
try
|
||||
{
|
||||
if(workbook != null)
|
||||
{
|
||||
workbook.finish();
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QReportingException("Error finishing Excel report", e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.reporting;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Object to connect a producer of records with a consumer.
|
||||
** Best for those to be on different threads, to avoid deadlock.
|
||||
*******************************************************************************/
|
||||
public class RecordPipe
|
||||
{
|
||||
private ArrayBlockingQueue<QRecord> queue = new ArrayBlockingQueue<>(10_000);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Add a record to the pipe
|
||||
** Returns true iff the record fit in the pipe; false if the pipe is currently full.
|
||||
*******************************************************************************/
|
||||
public boolean addRecord(QRecord record)
|
||||
{
|
||||
return (queue.offer(record));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Add a list of records to the pipe
|
||||
*******************************************************************************/
|
||||
public void addRecords(List<QRecord> records)
|
||||
{
|
||||
queue.addAll(records);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> consumeAvailableRecords()
|
||||
{
|
||||
List<QRecord> rs = new ArrayList<>();
|
||||
|
||||
while(true)
|
||||
{
|
||||
QRecord record = queue.poll();
|
||||
if(record == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
rs.add(record);
|
||||
}
|
||||
|
||||
return (rs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public int countAvailableRecords()
|
||||
{
|
||||
return (queue.size());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.reporting;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobManager;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobState;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobStatus;
|
||||
import com.kingsrook.qqq.backend.core.actions.interfaces.CountInterface;
|
||||
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QReportingException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportOutput;
|
||||
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.model.actions.tables.query.QueryInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.SleepUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action to generate a report.
|
||||
**
|
||||
** At this time (future may change?), this action starts a new thread to run
|
||||
** the query in the backend module. As records are produced by the query,
|
||||
** they are put into a RecordPipe, which the ReportStreamer pulls from, to write
|
||||
** to the report output stream. This action will block until the query job
|
||||
** is complete, and the final records have been consumed from the pipe, at which
|
||||
** time the report outputStream can be closed.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ReportAction
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(ReportAction.class);
|
||||
|
||||
private boolean preExecuteRan = false;
|
||||
private Integer countFromPreExecute = null;
|
||||
|
||||
private static final int TIMEOUT_AFTER_NO_RECORDS_MS = 10 * 60 * 1000;
|
||||
private static final int MAX_SLEEP_MS = 1000;
|
||||
private static final int INIT_SLEEP_MS = 10;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Validation logic, that will run before the action is executed -- ideally, if
|
||||
** a caller is going to run the execution in a thread, they'd call this method
|
||||
** first, in their thread, to catch any validation errors before they start
|
||||
** the thread (which they may abandon).
|
||||
*******************************************************************************/
|
||||
public void preExecute(ReportInput reportInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(reportInput);
|
||||
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
QBackendModuleInterface backendModule = qBackendModuleDispatcher.getQBackendModule(reportInput.getBackend());
|
||||
|
||||
///////////////////////////////////
|
||||
// verify field names (if given) //
|
||||
///////////////////////////////////
|
||||
if(CollectionUtils.nullSafeHasContents(reportInput.getFieldNames()))
|
||||
{
|
||||
QTableMetaData table = reportInput.getTable();
|
||||
List<String> badFieldNames = new ArrayList<>();
|
||||
for(String fieldName : reportInput.getFieldNames())
|
||||
{
|
||||
try
|
||||
{
|
||||
table.getField(fieldName);
|
||||
}
|
||||
catch(IllegalArgumentException iae)
|
||||
{
|
||||
badFieldNames.add(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
if(!badFieldNames.isEmpty())
|
||||
{
|
||||
throw (new QUserFacingException(badFieldNames.size() == 1
|
||||
? ("Field name " + badFieldNames.get(0) + " was not found on the " + table.getLabel() + " table.")
|
||||
: ("Fields names " + StringUtils.joinWithCommasAndAnd(badFieldNames) + " were not found on the " + table.getLabel() + " table.")));
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// check if this report format has a max-rows limit -- if so, do a count to verify we're under the limit //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ReportFormat reportFormat = reportInput.getReportFormat();
|
||||
verifyCountUnderMax(reportInput, backendModule, reportFormat);
|
||||
|
||||
preExecuteRan = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Run the report.
|
||||
*******************************************************************************/
|
||||
public ReportOutput execute(ReportInput reportInput) throws QException
|
||||
{
|
||||
if(!preExecuteRan)
|
||||
{
|
||||
/////////////////////////////////////
|
||||
// ensure that pre-execute has ran //
|
||||
/////////////////////////////////////
|
||||
preExecute(reportInput);
|
||||
}
|
||||
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
QBackendModuleInterface backendModule = qBackendModuleDispatcher.getQBackendModule(reportInput.getBackend());
|
||||
|
||||
//////////////////////////
|
||||
// set up a query input //
|
||||
//////////////////////////
|
||||
QueryInterface queryInterface = backendModule.getQueryInterface();
|
||||
QueryInput queryInput = new QueryInput(reportInput.getInstance());
|
||||
queryInput.setSession(reportInput.getSession());
|
||||
queryInput.setTableName(reportInput.getTableName());
|
||||
queryInput.setFilter(reportInput.getQueryFilter());
|
||||
queryInput.setLimit(reportInput.getLimit());
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// tell this query that it needs to put its output into a pipe //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
RecordPipe recordPipe = new RecordPipe();
|
||||
queryInput.setRecordPipe(recordPipe);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set up a report streamer, which will read rows from the pipe, and write formatted report rows to the output stream //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ReportFormat reportFormat = reportInput.getReportFormat();
|
||||
ReportStreamerInterface reportStreamer = reportFormat.newReportStreamer();
|
||||
reportStreamer.start(reportInput, getFields(reportInput));
|
||||
|
||||
//////////////////////////////////////////
|
||||
// run the query action as an async job //
|
||||
//////////////////////////////////////////
|
||||
AsyncJobManager asyncJobManager = new AsyncJobManager();
|
||||
String queryJobUUID = asyncJobManager.startJob("ReportAction>QueryAction", (status) -> (queryInterface.execute(queryInput)));
|
||||
LOG.info("Started query job [" + queryJobUUID + "] for report");
|
||||
|
||||
AsyncJobState queryJobState = AsyncJobState.RUNNING;
|
||||
AsyncJobStatus asyncJobStatus = null;
|
||||
|
||||
long recordCount = 0;
|
||||
int nextSleepMillis = INIT_SLEEP_MS;
|
||||
long lastReceivedRecordsAt = System.currentTimeMillis();
|
||||
long reportStartTime = System.currentTimeMillis();
|
||||
|
||||
while(queryJobState.equals(AsyncJobState.RUNNING))
|
||||
{
|
||||
if(recordPipe.countAvailableRecords() == 0)
|
||||
{
|
||||
///////////////////////////////////////////////////////////
|
||||
// if the pipe is empty, sleep to let the producer work. //
|
||||
// todo - smarter sleep? like get notified vs. sleep? //
|
||||
///////////////////////////////////////////////////////////
|
||||
LOG.info("No records are available in the pipe. Sleeping [" + nextSleepMillis + "] ms to give producer a chance to work");
|
||||
SleepUtils.sleep(nextSleepMillis, TimeUnit.MILLISECONDS);
|
||||
nextSleepMillis = Math.min(nextSleepMillis * 2, MAX_SLEEP_MS);
|
||||
|
||||
long timeSinceLastReceivedRecord = System.currentTimeMillis() - lastReceivedRecordsAt;
|
||||
if(timeSinceLastReceivedRecord > TIMEOUT_AFTER_NO_RECORDS_MS)
|
||||
{
|
||||
throw (new QReportingException("Query action appears to have stopped producing records (last record received " + timeSinceLastReceivedRecord + " ms ago)."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if the pipe has records, consume them. reset the sleep timer so if we sleep again it'll be short. //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
lastReceivedRecordsAt = System.currentTimeMillis();
|
||||
nextSleepMillis = INIT_SLEEP_MS;
|
||||
|
||||
int recordsConsumed = reportStreamer.takeRecordsFromPipe(recordPipe);
|
||||
recordCount += recordsConsumed;
|
||||
|
||||
LOG.info(countFromPreExecute != null
|
||||
? String.format("Processed %,d of %,d records so far", recordCount, countFromPreExecute)
|
||||
: String.format("Processed %,d records so far", recordCount));
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
// refresh the query job's status //
|
||||
////////////////////////////////////
|
||||
Optional<AsyncJobStatus> optionalAsyncJobStatus = asyncJobManager.getJobStatus(queryJobUUID);
|
||||
if(optionalAsyncJobStatus.isEmpty())
|
||||
{
|
||||
/////////////////////////////////////////////////
|
||||
// todo - ... maybe some version of try-again? //
|
||||
/////////////////////////////////////////////////
|
||||
throw (new QException("Could not get status of report query job [" + queryJobUUID + "]"));
|
||||
}
|
||||
asyncJobStatus = optionalAsyncJobStatus.get();
|
||||
queryJobState = asyncJobStatus.getState();
|
||||
}
|
||||
|
||||
LOG.info("Query job [" + queryJobUUID + "] for report completed with status: " + asyncJobStatus);
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// send the final records to the report streamer //
|
||||
///////////////////////////////////////////////////
|
||||
int recordsConsumed = reportStreamer.takeRecordsFromPipe(recordPipe);
|
||||
recordCount += recordsConsumed;
|
||||
|
||||
long reportEndTime = System.currentTimeMillis();
|
||||
LOG.info((countFromPreExecute != null
|
||||
? String.format("Processed %,d of %,d records", recordCount, countFromPreExecute)
|
||||
: String.format("Processed %,d records", recordCount))
|
||||
+ String.format(" at end of report in %,d ms (%.2f records/second).", (reportEndTime - reportStartTime), 1000d * (recordCount / (.001d + (reportEndTime - reportStartTime)))));
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Critical: we must close the stream here as our final action //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
reportStreamer.finish();
|
||||
|
||||
try
|
||||
{
|
||||
reportInput.getReportOutputStream().close();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QReportingException("Error completing report", e));
|
||||
}
|
||||
|
||||
ReportOutput reportOutput = new ReportOutput();
|
||||
reportOutput.setRecordCount(recordCount);
|
||||
|
||||
return (reportOutput);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private List<QFieldMetaData> getFields(ReportInput reportInput)
|
||||
{
|
||||
QTableMetaData table = reportInput.getTable();
|
||||
if(reportInput.getFieldNames() != null)
|
||||
{
|
||||
return (reportInput.getFieldNames().stream().map(table::getField).toList());
|
||||
}
|
||||
else
|
||||
{
|
||||
return (new ArrayList<>(table.getFields().values()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void verifyCountUnderMax(ReportInput reportInput, QBackendModuleInterface backendModule, ReportFormat reportFormat) throws QException
|
||||
{
|
||||
if(reportFormat.getMaxCols() != null)
|
||||
{
|
||||
List<QFieldMetaData> fields = getFields(reportInput);
|
||||
if (fields.size() > reportFormat.getMaxCols())
|
||||
{
|
||||
throw (new QUserFacingException("The requested report would include more columns ("
|
||||
+ String.format("%,d", fields.size()) + ") than the maximum allowed ("
|
||||
+ String.format("%,d", reportFormat.getMaxCols()) + ") for the selected file format (" + reportFormat + ")."));
|
||||
}
|
||||
}
|
||||
|
||||
if(reportFormat.getMaxRows() != null)
|
||||
{
|
||||
if(reportInput.getLimit() == null || reportInput.getLimit() > reportFormat.getMaxRows())
|
||||
{
|
||||
CountInterface countInterface = backendModule.getCountInterface();
|
||||
CountInput countInput = new CountInput(reportInput.getInstance());
|
||||
countInput.setSession(reportInput.getSession());
|
||||
countInput.setTableName(reportInput.getTableName());
|
||||
countInput.setFilter(reportInput.getQueryFilter());
|
||||
CountOutput countOutput = countInterface.execute(countInput);
|
||||
countFromPreExecute = countOutput.getCount();
|
||||
if(countFromPreExecute > reportFormat.getMaxRows())
|
||||
{
|
||||
throw (new QUserFacingException("The requested report would include more rows ("
|
||||
+ String.format("%,d", countFromPreExecute) + ") than the maximum allowed ("
|
||||
+ String.format("%,d", reportFormat.getMaxRows()) + ") for the selected file format (" + reportFormat + ")."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.reporting;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QReportingException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface for various report formats to implement.
|
||||
*******************************************************************************/
|
||||
public interface ReportStreamerInterface
|
||||
{
|
||||
/*******************************************************************************
|
||||
** Called once, before any rows are available. Meant to write a header, for example.
|
||||
*******************************************************************************/
|
||||
void start(ReportInput reportInput, List<QFieldMetaData> fields) throws QReportingException;
|
||||
|
||||
/*******************************************************************************
|
||||
** Called as records flow into the pipe.
|
||||
******************************************************************************/
|
||||
int takeRecordsFromPipe(RecordPipe recordPipe) throws QReportingException;
|
||||
|
||||
/*******************************************************************************
|
||||
** Called once, after all rows are available. Meant to write a footer, or close resources, for example.
|
||||
*******************************************************************************/
|
||||
void finish() throws QReportingException;
|
||||
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.tables;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
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.modules.backend.QBackendModuleDispatcher;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action to run a count against a table.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class CountAction
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public CountOutput execute(CountInput countInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(countInput);
|
||||
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(countInput.getBackend());
|
||||
// todo pre-customization - just get to modify the request?
|
||||
CountOutput countOutput = qModule.getCountInterface().execute(countInput);
|
||||
// todo post-customization - can do whatever w/ the result if you want
|
||||
return countOutput;
|
||||
}
|
||||
}
|
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.tables;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.interfaces.DeleteInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
|
||||
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.modules.backend.QBackendModuleDispatcher;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action to delete 1 or more records.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class DeleteAction
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(DeleteAction.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public DeleteOutput execute(DeleteInput deleteInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(deleteInput);
|
||||
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(deleteInput.getBackend());
|
||||
// todo pre-customization - just get to modify the request?
|
||||
|
||||
if(CollectionUtils.nullSafeHasContents(deleteInput.getPrimaryKeys()) && deleteInput.getQueryFilter() != null)
|
||||
{
|
||||
throw (new QException("A delete request may not contain both a list of primary keys and a query filter."));
|
||||
}
|
||||
|
||||
DeleteInterface deleteInterface = qModule.getDeleteInterface();
|
||||
if(deleteInput.getQueryFilter() != null && !deleteInterface.supportsQueryFilterInput())
|
||||
{
|
||||
LOG.info("Querying for primary keys, for backend module " + qModule.getBackendType() + " which does not support queryFilter input for deletes");
|
||||
List<Serializable> primaryKeyList = getPrimaryKeysFromQueryFilter(deleteInput);
|
||||
deleteInput.setPrimaryKeys(primaryKeyList);
|
||||
|
||||
if(primaryKeyList.isEmpty())
|
||||
{
|
||||
LOG.info("0 primaryKeys found. Returning with no-op");
|
||||
DeleteOutput deleteOutput = new DeleteOutput();
|
||||
deleteOutput.setRecordsWithErrors(new ArrayList<>());
|
||||
deleteOutput.setDeletedRecordCount(0);
|
||||
return (deleteOutput);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteOutput deleteResult = deleteInterface.execute(deleteInput);
|
||||
// todo post-customization - can do whatever w/ the result if you want
|
||||
|
||||
return deleteResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** For an implementation that doesn't support a queryFilter as its input,
|
||||
** but a scenario where a query filter was passed in - run the query, to
|
||||
** get a list of primary keys.
|
||||
*******************************************************************************/
|
||||
public static List<Serializable> getPrimaryKeysFromQueryFilter(DeleteInput deleteInput) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(deleteInput.getBackend());
|
||||
|
||||
QueryInput queryInput = new QueryInput(deleteInput.getInstance(), deleteInput.getSession());
|
||||
queryInput.setTableName(deleteInput.getTableName());
|
||||
queryInput.setFilter(deleteInput.getQueryFilter());
|
||||
QueryOutput queryOutput = qModule.getQueryInterface().execute(queryInput);
|
||||
|
||||
return (queryOutput.getRecords().stream()
|
||||
.map(r -> r.getValue(deleteInput.getTable().getPrimaryKeyField()))
|
||||
.toList());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error getting primary keys from query filter before bulk-delete", e);
|
||||
throw (new QException("Error getting keys from filter prior to delete.", e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.tables;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
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.insert.InsertOutput;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action to insert one or more records.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class InsertAction
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(InsertAction.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public InsertOutput execute(InsertInput insertInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(insertInput);
|
||||
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(insertInput.getBackend());
|
||||
// todo pre-customization - just get to modify the request?
|
||||
InsertOutput insertOutput = qModule.getInsertInterface().execute(insertInput);
|
||||
// todo post-customization - can do whatever w/ the result if you want
|
||||
return insertOutput;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.tables;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
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.modules.backend.QBackendModuleDispatcher;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action to run a query against a table.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QueryAction
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryOutput execute(QueryInput queryInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(queryInput);
|
||||
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(queryInput.getBackend());
|
||||
// todo pre-customization - just get to modify the request?
|
||||
QueryOutput queryOutput = qModule.getQueryInterface().execute(queryInput);
|
||||
// todo post-customization - can do whatever w/ the result if you want
|
||||
return queryOutput;
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.actions.tables;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Action to update one or more records.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class UpdateAction
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public UpdateOutput execute(UpdateInput updateInput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(updateInput);
|
||||
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(updateInput.getBackend());
|
||||
// todo pre-customization - just get to modify the request?
|
||||
UpdateOutput updateResult = qModule.getUpdateInterface().execute(updateInput);
|
||||
// todo post-customization - can do whatever w/ the result if you want
|
||||
return updateResult;
|
||||
}
|
||||
}
|
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.adapters;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.shared.mapping.AbstractQFieldMapping;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Adapter class to convert a CSV string into a list of QRecords.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class CsvToQRecordAdapter
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** convert a CSV String into a List of QRecords, for a given table, optionally
|
||||
** using a given mapping.
|
||||
**
|
||||
** todo - meta-data validation, type handling
|
||||
*******************************************************************************/
|
||||
public List<QRecord> buildRecordsFromCsv(String csv, QTableMetaData table, AbstractQFieldMapping<?> mapping)
|
||||
{
|
||||
if(!StringUtils.hasContent(csv))
|
||||
{
|
||||
throw (new IllegalArgumentException("Empty csv value was provided."));
|
||||
}
|
||||
|
||||
List<QRecord> rs = new ArrayList<>();
|
||||
try
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if there's no mapping (e.g., table-standard field names), or key-based mapping, then first row is headers //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(mapping == null || AbstractQFieldMapping.SourceType.KEY.equals(mapping.getSourceType()))
|
||||
{
|
||||
CSVParser csvParser = new CSVParser(new StringReader(csv),
|
||||
CSVFormat.DEFAULT
|
||||
.withFirstRecordAsHeader()
|
||||
.withIgnoreHeaderCase()
|
||||
.withTrim());
|
||||
|
||||
List<String> headers = csvParser.getHeaderNames();
|
||||
headers = makeHeadersUnique(headers);
|
||||
|
||||
List<CSVRecord> csvRecords = csvParser.getRecords();
|
||||
for(CSVRecord csvRecord : csvRecords)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// put values from the CSV record into a map of header -> value //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
Map<String, String> csvValues = new HashMap<>();
|
||||
for(int i=0; i<headers.size(); i++)
|
||||
{
|
||||
csvValues.put(headers.get(i), csvRecord.get(i));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// now move values into the QRecord, using the mapping to get the 'header' corresponding to each QField //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
QRecord qRecord = new QRecord();
|
||||
rs.add(qRecord);
|
||||
for(QFieldMetaData field : table.getFields().values())
|
||||
{
|
||||
String fieldSource = mapping == null ? field.getName() : String.valueOf(mapping.getFieldSource(field.getName()));
|
||||
qRecord.setValue(field.getName(), csvValues.get(fieldSource));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(AbstractQFieldMapping.SourceType.INDEX.equals(mapping.getSourceType()))
|
||||
{
|
||||
///////////////////////////////
|
||||
// else, index-based mapping //
|
||||
///////////////////////////////
|
||||
CSVParser csvParser = new CSVParser(new StringReader(csv),
|
||||
CSVFormat.DEFAULT
|
||||
.withTrim());
|
||||
|
||||
List<CSVRecord> csvRecords = csvParser.getRecords();
|
||||
for(CSVRecord csvRecord : csvRecords)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// put values from the CSV record into a map of index -> value //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
Map<Integer, String> csvValues = new HashMap<>();
|
||||
int index = 1;
|
||||
for(String value : csvRecord)
|
||||
{
|
||||
csvValues.put(index++, value);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// now move values into the QRecord, using the mapping to get the 'header' corresponding to each QField //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
QRecord qRecord = new QRecord();
|
||||
rs.add(qRecord);
|
||||
for(QFieldMetaData field : table.getFields().values())
|
||||
{
|
||||
Integer fieldIndex = (Integer) mapping.getFieldSource(field.getName());
|
||||
qRecord.setValue(field.getName(), csvValues.get(fieldIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new IllegalArgumentException("Unrecognized mapping source type: " + mapping.getSourceType()));
|
||||
}
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
throw (new IllegalArgumentException("Error parsing CSV: " + e.getMessage(), e));
|
||||
}
|
||||
|
||||
return (rs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** For a list of headers, if any duplicates are found, add a numeric suffix
|
||||
** to the duplicates.
|
||||
**
|
||||
** So this header row: A,B,C,C,C
|
||||
** Would become: A,B,C,C 2,C 3
|
||||
**
|
||||
** See unit test for more scenarios - some of which we do not handle well yet,
|
||||
** such as "C 2, C, C 3"
|
||||
*******************************************************************************/
|
||||
protected List<String> makeHeadersUnique(List<String> headers)
|
||||
{
|
||||
Map<String, Integer> countsByHeader = new HashMap<>();
|
||||
List<String> rs = new ArrayList<>();
|
||||
|
||||
for(String header : headers)
|
||||
{
|
||||
String headerToUse = header;
|
||||
String headerWithoutSuffix = header.replaceFirst(" \\d+$", "");
|
||||
|
||||
if(countsByHeader.containsKey(headerWithoutSuffix))
|
||||
{
|
||||
int suffix = countsByHeader.get(headerWithoutSuffix) + 1;
|
||||
countsByHeader.put(headerWithoutSuffix, suffix);
|
||||
headerToUse = headerWithoutSuffix + " " + suffix;
|
||||
}
|
||||
else
|
||||
{
|
||||
countsByHeader.put(headerWithoutSuffix, 1);
|
||||
}
|
||||
rs.add(headerToUse);
|
||||
}
|
||||
return (rs);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.adapters;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.shared.mapping.AbstractQFieldMapping;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.shared.mapping.QIndexBasedFieldMapping;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.shared.mapping.QKeyBasedFieldMapping;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Adapter class to convert a JSON string into a QFieldMapping object
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class JsonToQFieldMappingAdapter
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** adapts a json string into an AbstractQFieldMapping.
|
||||
**
|
||||
** The mapping will be a QKeyBasedFieldMapping if the keys in the json object are
|
||||
** Strings. It will be a QIndexBasedFieldMapping if the keys are integers.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AbstractQFieldMapping<?> buildMappingFromJson(String json)
|
||||
{
|
||||
if(!StringUtils.hasContent(json))
|
||||
{
|
||||
throw (new IllegalArgumentException("Empty json value was provided."));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(json);
|
||||
jsonObject = promoteInnerMappingIfAppropriate(jsonObject);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// look at the keys in the mapping - if they're strings, then we're doing key-based mapping //
|
||||
// if they're numbers, then we're doing index based -- and if they're a mix, that's illegal //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AbstractQFieldMapping.SourceType sourceType = determineSourceType(jsonObject);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
AbstractQFieldMapping mapping = null;
|
||||
|
||||
switch(sourceType)
|
||||
{
|
||||
case KEY:
|
||||
{
|
||||
mapping = new QKeyBasedFieldMapping();
|
||||
for(String fieldName : jsonObject.keySet())
|
||||
{
|
||||
((QKeyBasedFieldMapping) mapping).addMapping(fieldName, jsonObject.getString(fieldName));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INDEX:
|
||||
{
|
||||
mapping = new QIndexBasedFieldMapping();
|
||||
for(String fieldName : jsonObject.keySet())
|
||||
{
|
||||
((QIndexBasedFieldMapping) mapping).addMapping(fieldName, jsonObject.getInt(fieldName));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new IllegalArgumentException("Unsupported sourceType: " + sourceType));
|
||||
}
|
||||
}
|
||||
|
||||
return (mapping);
|
||||
}
|
||||
catch(JSONException je)
|
||||
{
|
||||
throw (new IllegalArgumentException("Malformed JSON value: " + je.getMessage(), je));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** So - this class was first written assuming that the JSON it would take would
|
||||
** just be a mapping - e.g., {a:b, c:d} or {a:0, b:1}.
|
||||
**
|
||||
** But - it turns out, callers may expect that they can create an instance of
|
||||
** AbstractQFieldMapping, then serialize it, then de-serialize it, and that seems sane.
|
||||
**
|
||||
** So - this method tries to determine if the JSON Object we took in looks like
|
||||
** a serialized from of a AbstractQFieldMapping - and if so, then it "promotes"
|
||||
** the "mapping" object from within that outer json object, since the rest of
|
||||
** this class knows how to (and expects to) handle that object.
|
||||
*******************************************************************************/
|
||||
private JSONObject promoteInnerMappingIfAppropriate(JSONObject jsonObject)
|
||||
{
|
||||
if(jsonObject.has("mapping") && jsonObject.has("sourceType") && jsonObject.keySet().size() == 2)
|
||||
{
|
||||
return (jsonObject.getJSONObject("mapping"));
|
||||
}
|
||||
return (jsonObject);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private AbstractQFieldMapping.SourceType determineSourceType(JSONObject jsonObject)
|
||||
{
|
||||
for(String fieldName : jsonObject.keySet())
|
||||
{
|
||||
Object sourceObject = jsonObject.get(fieldName);
|
||||
if(sourceObject instanceof String)
|
||||
{
|
||||
return (AbstractQFieldMapping.SourceType.KEY);
|
||||
}
|
||||
else if(sourceObject instanceof Integer)
|
||||
{
|
||||
return (AbstractQFieldMapping.SourceType.INDEX);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Source object is unsupported type: " + sourceObject.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No fields were found in the mapping.");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.adapters;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.shared.mapping.AbstractQFieldMapping;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Adapter class to convert a JSON string into a list of QRecords.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class JsonToQRecordAdapter
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** convert a JSON String into a List of QRecords, for a given table, optionally
|
||||
** using a given mapping.
|
||||
**
|
||||
** todo - meta-data validation, use the mapping, type handling
|
||||
*******************************************************************************/
|
||||
public List<QRecord> buildRecordsFromJson(String json, QTableMetaData table, AbstractQFieldMapping<?> mapping)
|
||||
{
|
||||
if(!StringUtils.hasContent(json))
|
||||
{
|
||||
throw (new IllegalArgumentException("Empty json value was provided."));
|
||||
}
|
||||
|
||||
List<QRecord> rs = new ArrayList<>();
|
||||
try
|
||||
{
|
||||
if(JsonUtils.looksLikeObject(json))
|
||||
{
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(json);
|
||||
rs.add(buildRecordFromJsonObject(jsonObject, table, mapping));
|
||||
}
|
||||
else if(JsonUtils.looksLikeArray(json))
|
||||
{
|
||||
JSONArray jsonArray = JsonUtils.toJSONArray(json);
|
||||
for(Object object : jsonArray)
|
||||
{
|
||||
if(object instanceof JSONObject jsonObject)
|
||||
{
|
||||
rs.add(buildRecordFromJsonObject(jsonObject, table, mapping));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new IllegalArgumentException("Element at index " + rs.size() + " in json array was not a json object."));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new IllegalArgumentException("Malformed JSON value - did not start with '{' or '['."));
|
||||
}
|
||||
}
|
||||
catch(JSONException je)
|
||||
{
|
||||
throw (new IllegalArgumentException("Malformed JSON value: " + je.getMessage(), je));
|
||||
}
|
||||
|
||||
return (rs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** private method to build one QRecord from one jsonObject
|
||||
**
|
||||
** todo - meta-data validation, type handling
|
||||
*******************************************************************************/
|
||||
private QRecord buildRecordFromJsonObject(JSONObject jsonObject, QTableMetaData table, AbstractQFieldMapping<?> mapping)
|
||||
{
|
||||
QRecord record = new QRecord();
|
||||
|
||||
for(QFieldMetaData field : table.getFields().values())
|
||||
{
|
||||
String fieldSource = mapping == null ? field.getName() : String.valueOf(mapping.getFieldSource(field.getName()));
|
||||
// todo - so if the mapping didn't say how to map this field, does that mean we should use the default name for the field?
|
||||
if(jsonObject.has(fieldSource))
|
||||
{
|
||||
record.setValue(field.getName(), (Serializable) jsonObject.get(fieldSource));
|
||||
}
|
||||
}
|
||||
|
||||
return (record);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.adapters;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Methods for adapting qInstances to serialized (string) formats (e.g., json),
|
||||
** and vice versa.
|
||||
*******************************************************************************/
|
||||
public class QInstanceAdapter
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** Convert a qInstance to JSON.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String qInstanceToJson(QInstance qInstance)
|
||||
{
|
||||
return (JsonUtils.toJson(qInstance));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Convert a qInstance to JSON.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String qInstanceToJsonIncludingBackend(QInstance qInstance)
|
||||
{
|
||||
String jsonString = JsonUtils.toJson(qInstance);
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(jsonString);
|
||||
|
||||
String backendsJsonString = JsonUtils.toJson(qInstance.getBackends());
|
||||
JSONObject backendsJsonObject = JsonUtils.toJSONObject(backendsJsonString);
|
||||
jsonObject.put("backends", backendsJsonObject);
|
||||
|
||||
return (jsonObject.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Build a qInstance from JSON.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QInstance jsonToQInstance(String json) throws IOException
|
||||
{
|
||||
return (JsonUtils.toObject(json, QInstance.class));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Build a qInstance from JSON.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QInstance jsonToQInstanceIncludingBackends(String json) throws IOException
|
||||
{
|
||||
QInstance qInstance = JsonUtils.toObject(json, QInstance.class);
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(json);
|
||||
JSONObject backendsJsonObject = jsonObject.getJSONObject("backends");
|
||||
Map<String, QBackendMetaData> backends = JsonUtils.toObject(backendsJsonObject.toString(), new TypeReference<>()
|
||||
{
|
||||
});
|
||||
qInstance.setBackends(backends);
|
||||
return qInstance;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.adapters;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Class to convert QRecords to CSV Strings.
|
||||
*******************************************************************************/
|
||||
public class QRecordToCsvAdapter
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String recordToCsv(QTableMetaData table, QRecord record)
|
||||
{
|
||||
return (recordToCsv(table, record, new ArrayList<>(table.getFields().values())));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String recordToCsv(QTableMetaData table, QRecord record, List<QFieldMetaData> fields)
|
||||
{
|
||||
StringBuilder rs = new StringBuilder();
|
||||
int fieldNo = 0;
|
||||
|
||||
for(QFieldMetaData field : fields)
|
||||
{
|
||||
if(fieldNo++ > 0)
|
||||
{
|
||||
rs.append(',');
|
||||
}
|
||||
rs.append('"');
|
||||
Serializable value = record.getValue(field.getName());
|
||||
String valueAsString = ValueUtils.getValueAsString(value);
|
||||
if(StringUtils.hasContent(valueAsString))
|
||||
{
|
||||
rs.append(sanitize(valueAsString));
|
||||
}
|
||||
rs.append('"');
|
||||
}
|
||||
rs.append('\n');
|
||||
return (rs.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** todo - kinda weak... can we find this in a CSV lib??
|
||||
*******************************************************************************/
|
||||
private String sanitize(String value)
|
||||
{
|
||||
return (value.replaceAll("\"", "\"\"").replaceAll("\n", " "));
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.exceptions;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Exception thrown doing authentication
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class QAuthenticationException extends QException
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QAuthenticationException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message & cause
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QAuthenticationException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.exceptions;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Base class for checked exceptions thrown in qqq.
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class QException extends Exception
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message & cause
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.exceptions;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Exception thrown during qqq-starup, if a QInstance is found to have validation
|
||||
** issues. Contains a list of reasons (to avoid spoon-feeding as much as possible).
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QInstanceValidationException extends QException
|
||||
{
|
||||
private List<String> reasons;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message - does not populate reasons!
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QInstanceValidationException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of a list of reasons. They feed into the core exception message.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QInstanceValidationException(List<String> reasons)
|
||||
{
|
||||
super(
|
||||
(reasons != null && reasons.size() > 0)
|
||||
? "Instance validation failed for the following reasons: " + StringUtils.joinWithCommasAndAnd(reasons)
|
||||
: "Validation failed, but no reasons were provided");
|
||||
|
||||
if(reasons != null && reasons.size() > 0)
|
||||
{
|
||||
this.reasons = reasons;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of an array/varargs of reasons. They feed into the core exception message.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QInstanceValidationException(String... reasons)
|
||||
{
|
||||
super(
|
||||
(reasons != null && reasons.length > 0)
|
||||
? "Instance validation failed for the following reasons: " + StringUtils.joinWithCommasAndAnd(Arrays.stream(reasons).toList())
|
||||
: "Validation failed, but no reasons were provided");
|
||||
|
||||
if(reasons != null && reasons.length > 0)
|
||||
{
|
||||
this.reasons = Arrays.stream(reasons).toList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message & cause - does not populate reasons!
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QInstanceValidationException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for reasons
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<String> getReasons()
|
||||
{
|
||||
return reasons;
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.exceptions;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Exception thrown while doing module-dispatch
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class QModuleDispatchException extends QException
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QModuleDispatchException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message & cause
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QModuleDispatchException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.exceptions;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** User-facing exception for when something wasn't found (e.g., a named table or
|
||||
** record-by-id).
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QNotFoundException extends QUserFacingException
|
||||
{
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QNotFoundException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message & cause
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QNotFoundException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.exceptions;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Exception thrown while generating reports
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class QReportingException extends QException
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QReportingException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message & cause
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QReportingException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.exceptions;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Exception with a good-quality message meant to be shown to an end-user.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QUserFacingException extends QException
|
||||
{
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QUserFacingException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message & cause
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QUserFacingException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.exceptions;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Exception for when there's a problem with a value (like a string that you need
|
||||
** to be an integer, but it isn't).
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QValueException extends RuntimeException
|
||||
{
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QValueException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message & cause
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QValueException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.instances;
|
||||
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Class-level annotation to declare what fields should run through the variable
|
||||
** interpreter - e.g., to be replaced with env-var values at run-time.
|
||||
*******************************************************************************/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface InterpretableFields
|
||||
{
|
||||
/*******************************************************************************
|
||||
** list of field names in the class that are interpretable.
|
||||
*******************************************************************************/
|
||||
String[] fieldNames() default {};
|
||||
}
|
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.instances;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QComponentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendComponentMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.delete.BulkDeleteStoreStep;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.edit.BulkEditReceiveValuesStep;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.edit.BulkEditStoreRecordsStep;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.insert.BulkInsertReceiveFileStep;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.insert.BulkInsertStoreRecordsStep;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.general.LoadInitialRecordsStep;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** As part of helping a QInstance be created and/or validated, apply some default
|
||||
** transformations to it, such as populating missing labels based on names.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QInstanceEnricher
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void enrich(QInstance qInstance)
|
||||
{
|
||||
if(qInstance.getTables() != null)
|
||||
{
|
||||
qInstance.getTables().values().forEach(this::enrich);
|
||||
defineTableBulkProcesses(qInstance);
|
||||
}
|
||||
|
||||
if(qInstance.getProcesses() != null)
|
||||
{
|
||||
qInstance.getProcesses().values().forEach(this::enrich);
|
||||
}
|
||||
|
||||
if(qInstance.getBackends() != null)
|
||||
{
|
||||
qInstance.getBackends().values().forEach(this::enrich);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void enrich(QBackendMetaData qBackendMetaData)
|
||||
{
|
||||
qBackendMetaData.enrich();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void enrich(QTableMetaData table)
|
||||
{
|
||||
if(!StringUtils.hasContent(table.getLabel()))
|
||||
{
|
||||
table.setLabel(nameToLabel(table.getName()));
|
||||
}
|
||||
|
||||
if(table.getFields() != null)
|
||||
{
|
||||
table.getFields().values().forEach(this::enrich);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void enrich(QProcessMetaData process)
|
||||
{
|
||||
if(!StringUtils.hasContent(process.getLabel()))
|
||||
{
|
||||
process.setLabel(nameToLabel(process.getName()));
|
||||
}
|
||||
|
||||
if(process.getStepList() != null)
|
||||
{
|
||||
process.getStepList().forEach(this::enrich);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void enrich(QStepMetaData step)
|
||||
{
|
||||
if(!StringUtils.hasContent(step.getLabel()))
|
||||
{
|
||||
step.setLabel(nameToLabel(step.getName()));
|
||||
}
|
||||
|
||||
step.getInputFields().forEach(this::enrich);
|
||||
step.getOutputFields().forEach(this::enrich);
|
||||
|
||||
if(step instanceof QFrontendStepMetaData frontendStepMetaData)
|
||||
{
|
||||
if(frontendStepMetaData.getFormFields() != null)
|
||||
{
|
||||
frontendStepMetaData.getFormFields().forEach(this::enrich);
|
||||
}
|
||||
if(frontendStepMetaData.getViewFields() != null)
|
||||
{
|
||||
frontendStepMetaData.getViewFields().forEach(this::enrich);
|
||||
}
|
||||
if(frontendStepMetaData.getRecordListFields() != null)
|
||||
{
|
||||
frontendStepMetaData.getRecordListFields().forEach(this::enrich);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void enrich(QFieldMetaData field)
|
||||
{
|
||||
if(!StringUtils.hasContent(field.getLabel()))
|
||||
{
|
||||
field.setLabel(nameToLabel(field.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private String nameToLabel(String name)
|
||||
{
|
||||
if(name == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (name.substring(0, 1).toUpperCase(Locale.ROOT) + name.substring(1).replaceAll("([A-Z])", " $1"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Add bulk insert/edit/delete processes to all tables (unless the meta data
|
||||
** already had these processes defined (e.g., the user defined custom ones)
|
||||
*******************************************************************************/
|
||||
private void defineTableBulkProcesses(QInstance qInstance)
|
||||
{
|
||||
for(QTableMetaData table : qInstance.getTables().values())
|
||||
{
|
||||
if(table.getFields() == null)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// these processes can't be defined if there aren't any fields //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
continue;
|
||||
}
|
||||
|
||||
// todo - add idea of 'supportsBulkX'
|
||||
String bulkInsertProcessName = table.getName() + ".bulkInsert";
|
||||
if(qInstance.getProcess(bulkInsertProcessName) == null)
|
||||
{
|
||||
defineTableBulkInsert(qInstance, table, bulkInsertProcessName);
|
||||
}
|
||||
|
||||
String bulkEditProcessName = table.getName() + ".bulkEdit";
|
||||
if(qInstance.getProcess(bulkEditProcessName) == null)
|
||||
{
|
||||
defineTableBulkEdit(qInstance, table, bulkEditProcessName);
|
||||
}
|
||||
|
||||
String bulkDeleteProcessName = table.getName() + ".bulkDelete";
|
||||
if(qInstance.getProcess(bulkDeleteProcessName) == null)
|
||||
{
|
||||
defineTableBulkDelete(qInstance, table, bulkDeleteProcessName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void defineTableBulkInsert(QInstance qInstance, QTableMetaData table, String processName)
|
||||
{
|
||||
List<QFieldMetaData> editableFields = table.getFields().values().stream()
|
||||
.filter(QFieldMetaData::getIsEditable)
|
||||
.toList();
|
||||
|
||||
String fieldsForHelpText = editableFields.stream()
|
||||
.map(QFieldMetaData::getLabel)
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
QFrontendStepMetaData uploadScreen = new QFrontendStepMetaData()
|
||||
.withName("upload")
|
||||
.withLabel("Upload File")
|
||||
.withFormField(new QFieldMetaData("theFile", QFieldType.BLOB).withIsRequired(true))
|
||||
.withComponent(new QFrontendComponentMetaData()
|
||||
.withType(QComponentType.HELP_TEXT)
|
||||
// .withValue("text", "Upload a CSV or XLSX file with the following columns: " + fieldsForHelpText));
|
||||
.withValue("text", "Upload a CSV file with the following columns: " + fieldsForHelpText));
|
||||
|
||||
QBackendStepMetaData receiveFileStep = new QBackendStepMetaData()
|
||||
.withName("receiveFile")
|
||||
.withCode(new QCodeReference(BulkInsertReceiveFileStep.class))
|
||||
.withOutputMetaData(new QFunctionOutputMetaData()
|
||||
.withFieldList(List.of(new QFieldMetaData("noOfFileRows", QFieldType.INTEGER))));
|
||||
|
||||
QFrontendStepMetaData reviewScreen = new QFrontendStepMetaData()
|
||||
.withName("review")
|
||||
.withRecordListFields(editableFields)
|
||||
.withComponent(new QFrontendComponentMetaData()
|
||||
.withType(QComponentType.HELP_TEXT)
|
||||
.withValue("text", "The records below were parsed from your file, and will be inserted if you click Submit."))
|
||||
.withViewField(new QFieldMetaData("noOfFileRows", QFieldType.INTEGER).withLabel("# of file rows"));
|
||||
|
||||
QBackendStepMetaData storeStep = new QBackendStepMetaData()
|
||||
.withName("storeRecords")
|
||||
.withCode(new QCodeReference(BulkInsertStoreRecordsStep.class))
|
||||
.withOutputMetaData(new QFunctionOutputMetaData()
|
||||
.withFieldList(List.of(new QFieldMetaData("noOfFileRows", QFieldType.INTEGER))));
|
||||
|
||||
QFrontendStepMetaData resultsScreen = new QFrontendStepMetaData()
|
||||
.withName("results")
|
||||
.withRecordListFields(new ArrayList<>(table.getFields().values()))
|
||||
.withComponent(new QFrontendComponentMetaData()
|
||||
.withType(QComponentType.HELP_TEXT)
|
||||
.withValue("text", "The records below have been inserted."))
|
||||
.withViewField(new QFieldMetaData("noOfFileRows", QFieldType.INTEGER).withLabel("# of file rows"));
|
||||
|
||||
qInstance.addProcess(
|
||||
new QProcessMetaData()
|
||||
.withName(processName)
|
||||
.withLabel(table.getLabel() + " Bulk Insert")
|
||||
.withTableName(table.getName())
|
||||
.withIsHidden(true)
|
||||
.withStepList(List.of(
|
||||
uploadScreen,
|
||||
receiveFileStep,
|
||||
reviewScreen,
|
||||
storeStep,
|
||||
resultsScreen
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void defineTableBulkEdit(QInstance qInstance, QTableMetaData table, String processName)
|
||||
{
|
||||
List<QFieldMetaData> editableFields = table.getFields().values().stream()
|
||||
.filter(QFieldMetaData::getIsEditable)
|
||||
.toList();
|
||||
|
||||
QFrontendStepMetaData editScreen = new QFrontendStepMetaData()
|
||||
.withName("edit")
|
||||
.withLabel("Edit Values")
|
||||
.withFormFields(editableFields)
|
||||
.withComponent(new QFrontendComponentMetaData()
|
||||
.withType(QComponentType.HELP_TEXT)
|
||||
.withValue("text", """
|
||||
Flip the switches next to the fields that you want to edit.
|
||||
The values you supply here will be updated in all of the records you are bulk editing.
|
||||
You can clear out the value in a field by flipping the switch on for that field and leaving the input field blank.
|
||||
Fields whose switches are off will not be updated."""))
|
||||
.withComponent(new QFrontendComponentMetaData()
|
||||
.withType(QComponentType.BULK_EDIT_FORM)
|
||||
);
|
||||
|
||||
QBackendStepMetaData receiveValuesStep = new QBackendStepMetaData()
|
||||
.withName("receiveValues")
|
||||
.withCode(new QCodeReference(BulkEditReceiveValuesStep.class))
|
||||
.withInputData(new QFunctionInputMetaData()
|
||||
.withRecordListMetaData(new QRecordListMetaData().withTableName(table.getName()))
|
||||
.withField(new QFieldMetaData(BulkEditReceiveValuesStep.FIELD_ENABLED_FIELDS, QFieldType.STRING))
|
||||
.withFields(editableFields));
|
||||
|
||||
QFrontendStepMetaData reviewScreen = new QFrontendStepMetaData()
|
||||
.withName("review")
|
||||
.withRecordListFields(editableFields)
|
||||
.withViewField(new QFieldMetaData(BulkEditReceiveValuesStep.FIELD_VALUES_BEING_UPDATED, QFieldType.STRING))
|
||||
.withComponent(new QFrontendComponentMetaData()
|
||||
.withType(QComponentType.HELP_TEXT)
|
||||
.withValue("text", "The records below will be updated if you click Submit."));
|
||||
|
||||
QBackendStepMetaData storeStep = new QBackendStepMetaData()
|
||||
.withName("storeRecords")
|
||||
.withCode(new QCodeReference(BulkEditStoreRecordsStep.class))
|
||||
.withOutputMetaData(new QFunctionOutputMetaData()
|
||||
.withFieldList(List.of(new QFieldMetaData("noOfFileRows", QFieldType.INTEGER))));
|
||||
|
||||
QFrontendStepMetaData resultsScreen = new QFrontendStepMetaData()
|
||||
.withName("results")
|
||||
.withRecordListFields(new ArrayList<>(table.getFields().values()))
|
||||
.withViewField(new QFieldMetaData(BulkEditReceiveValuesStep.FIELD_VALUES_BEING_UPDATED, QFieldType.STRING))
|
||||
.withComponent(new QFrontendComponentMetaData()
|
||||
.withType(QComponentType.HELP_TEXT)
|
||||
.withValue("text", "The records below have been updated."));
|
||||
|
||||
qInstance.addProcess(
|
||||
new QProcessMetaData()
|
||||
.withName(processName)
|
||||
.withLabel(table.getLabel() + " Bulk Edit")
|
||||
.withTableName(table.getName())
|
||||
.withIsHidden(true)
|
||||
.withStepList(List.of(
|
||||
LoadInitialRecordsStep.defineMetaData(table.getName()),
|
||||
editScreen,
|
||||
receiveValuesStep,
|
||||
reviewScreen,
|
||||
storeStep,
|
||||
resultsScreen
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void defineTableBulkDelete(QInstance qInstance, QTableMetaData table, String processName)
|
||||
{
|
||||
QFrontendStepMetaData reviewScreen = new QFrontendStepMetaData()
|
||||
.withName("review")
|
||||
.withRecordListFields(new ArrayList<>(table.getFields().values()))
|
||||
.withComponent(new QFrontendComponentMetaData()
|
||||
.withType(QComponentType.HELP_TEXT)
|
||||
.withValue("text", "The records below will be deleted if you click Submit."));
|
||||
|
||||
QBackendStepMetaData storeStep = new QBackendStepMetaData()
|
||||
.withName("delete")
|
||||
.withCode(new QCodeReference(BulkDeleteStoreStep.class));
|
||||
|
||||
QFrontendStepMetaData resultsScreen = new QFrontendStepMetaData()
|
||||
.withName("results")
|
||||
.withRecordListFields(new ArrayList<>(table.getFields().values()))
|
||||
.withComponent(new QFrontendComponentMetaData()
|
||||
.withType(QComponentType.HELP_TEXT)
|
||||
.withValue("text", "The records below have been deleted."));
|
||||
|
||||
qInstance.addProcess(
|
||||
new QProcessMetaData()
|
||||
.withName(processName)
|
||||
.withLabel(table.getLabel() + " Bulk Delete")
|
||||
.withTableName(table.getName())
|
||||
.withIsHidden(true)
|
||||
.withStepList(List.of(
|
||||
LoadInitialRecordsStep.defineMetaData(table.getName()),
|
||||
reviewScreen,
|
||||
storeStep,
|
||||
resultsScreen
|
||||
)));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.instances;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Object used to mark a QInstance has having been validated.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public final class QInstanceValidationKey
|
||||
{
|
||||
/*******************************************************************************
|
||||
** package-private constructor, so that only this package can create an instance
|
||||
** of this class, but an instance of this class is required to mark an instance
|
||||
** as validated, so no one can cheat.
|
||||
**
|
||||
*******************************************************************************/
|
||||
QInstanceValidationKey()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.instances;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Class that knows how to take a look at the data in a QInstance, and report
|
||||
** if it is all valid - e.g., non-null things are set; references line-up (e.g.,
|
||||
** a table's backend must be a defined backend).
|
||||
**
|
||||
** Prior to doing validation, the the QInstanceEnricher is ran over the QInstance,
|
||||
** e.g., to fill in things that can be defaulted or assumed. TODO let the instance
|
||||
** customize or opt-out of Enrichment.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QInstanceValidator
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void validate(QInstance qInstance) throws QInstanceValidationException
|
||||
{
|
||||
if(qInstance.getHasBeenValidated())
|
||||
{
|
||||
//////////////////////////////////////////
|
||||
// don't re-validate if previously done //
|
||||
//////////////////////////////////////////
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// before validation, enrich the object (e.g., to fill in values that the user doesn't have to //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TODO - possible point of customization (use a different enricher, or none, or pass it options).
|
||||
new QInstanceEnricher().enrich(qInstance);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QInstanceValidationException("Error enriching qInstance prior to validation.", e));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// do the validation checks - a good qInstance has all conditions TRUE! //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
List<String> errors = new ArrayList<>();
|
||||
try
|
||||
{
|
||||
if(assertCondition(errors, CollectionUtils.nullSafeHasContents(qInstance.getBackends()),
|
||||
"At least 1 backend must be defined."))
|
||||
{
|
||||
qInstance.getBackends().forEach((backendName, backend) ->
|
||||
{
|
||||
assertCondition(errors, Objects.equals(backendName, backend.getName()),
|
||||
"Inconsistent naming for backend: " + backendName + "/" + backend.getName() + ".");
|
||||
});
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// validate the tables //
|
||||
/////////////////////////
|
||||
if(assertCondition(errors, CollectionUtils.nullSafeHasContents(qInstance.getTables()),
|
||||
"At least 1 table must be defined."))
|
||||
{
|
||||
qInstance.getTables().forEach((tableName, table) ->
|
||||
{
|
||||
assertCondition(errors, Objects.equals(tableName, table.getName()),
|
||||
"Inconsistent naming for table: " + tableName + "/" + table.getName() + ".");
|
||||
|
||||
////////////////////////////////////////
|
||||
// validate the backend for the table //
|
||||
////////////////////////////////////////
|
||||
if(assertCondition(errors, StringUtils.hasContent(table.getBackendName()),
|
||||
"Missing backend name for table " + tableName + "."))
|
||||
{
|
||||
if(CollectionUtils.nullSafeHasContents(qInstance.getBackends()))
|
||||
{
|
||||
assertCondition(errors, qInstance.getBackendForTable(tableName) != null,
|
||||
"Unrecognized backend " + table.getBackendName() + " for table " + tableName + ".");
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// validate fields in the table //
|
||||
//////////////////////////////////
|
||||
if(assertCondition(errors, CollectionUtils.nullSafeHasContents(table.getFields()),
|
||||
"At least 1 field must be defined in table " + tableName + "."))
|
||||
{
|
||||
table.getFields().forEach((fieldName, field) ->
|
||||
{
|
||||
assertCondition(errors, Objects.equals(fieldName, field.getName()),
|
||||
"Inconsistent naming in table " + tableName + " for field " + fieldName + "/" + field.getName() + ".");
|
||||
|
||||
if(field.getPossibleValueSourceName() != null)
|
||||
{
|
||||
assertCondition(errors, qInstance.getPossibleValueSource(field.getPossibleValueSourceName()) != null,
|
||||
"Unrecognized possibleValueSourceName " + field.getPossibleValueSourceName() + " in table " + tableName + " for field " + fieldName + ".");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QInstanceValidationException("Error performing qInstance validation.", e));
|
||||
}
|
||||
|
||||
if(!errors.isEmpty())
|
||||
{
|
||||
throw (new QInstanceValidationException(errors));
|
||||
}
|
||||
|
||||
qInstance.setHasBeenValidated(new QInstanceValidationKey());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private boolean assertCondition(List<String> errors, boolean condition, String message)
|
||||
{
|
||||
if(!condition)
|
||||
{
|
||||
errors.add(message);
|
||||
}
|
||||
|
||||
return (condition);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.instances;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** To avoid having secrets (passwords, access keys, etc) committed into meta data
|
||||
** files, as well as to just let some meta data not be hard-coded, this class is
|
||||
** used by the Enricher to "promote" values, such as ${env.ACCESS_KEY}
|
||||
** to be read from the environment (or other secret providers (to be implemented)).
|
||||
**
|
||||
** Supported syntax / value sources are:
|
||||
** ${env.VAR} = system environment variables, e.g., export VAR=val
|
||||
** ${prop.VAR} = properties, e.g., -DVAR=val
|
||||
** ${literal.VAR} = get back a literal "VAR" (in case VAR matches some of the other supported syntax in here)
|
||||
*******************************************************************************/
|
||||
public class QMetaDataVariableInterpreter
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(QMetaDataVariableInterpreter.class);
|
||||
|
||||
private Map<String, String> customEnvironment;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void interpretObject(Object o) throws QException
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// get the InterpretableFields from the object's class - exiting if the annotation isn't present //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
InterpretableFields interpretableFields = o.getClass().getAnnotation(InterpretableFields.class);
|
||||
if(interpretableFields == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// iterate over interpretable fields, interpreting each //
|
||||
//////////////////////////////////////////////////////////
|
||||
for(String fieldName : interpretableFields.fieldNames())
|
||||
{
|
||||
try
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// get the getter & setter methods for the field (getMethod will throw if not found) //
|
||||
// enforce Strings-only at this time. //
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
String fieldNameUcFirst = fieldName.substring(0, 1).toUpperCase(Locale.ROOT) + fieldName.substring(1);
|
||||
Method getter = o.getClass().getMethod("get" + fieldNameUcFirst);
|
||||
Class<?> fieldType = getter.getReturnType();
|
||||
if(!fieldType.equals(String.class))
|
||||
{
|
||||
throw new QException("Interpretable field: " + fieldName + " on class " + o.getClass() + " is not a String (which is required at this time)");
|
||||
}
|
||||
Method setter = o.getClass().getMethod("set" + fieldNameUcFirst, fieldType);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// get the value - if it's null, move on, else, interpret it, and put it back in the object //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Object value = getter.invoke(o);
|
||||
if(value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
String interpreted = interpret((String) value);
|
||||
setter.invoke(o, interpreted);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QException("Error interpreting variables in object " + o, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Interpret a value string, which may be a variable, into its run-time value.
|
||||
**
|
||||
** If input is null, output is null.
|
||||
** If input looks like ${env.X}, then the return value is the value of the env variable 'X'
|
||||
** If input looks like ${prop.X}, then the return value is the value of the system property 'X'
|
||||
** If input looks like ${literal.X}, then the return value is the literal 'X'
|
||||
** - used if you really want to get back the literal value, ${env.X}, for example.
|
||||
** Else the output is the input.
|
||||
*******************************************************************************/
|
||||
public String interpret(String value)
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
String envPrefix = "${env.";
|
||||
if(value.startsWith(envPrefix) && value.endsWith("}"))
|
||||
{
|
||||
String envVarName = value.substring(envPrefix.length()).replaceFirst("}$", "");
|
||||
String envValue = getEnvironment().get(envVarName);
|
||||
return (envValue);
|
||||
}
|
||||
|
||||
String propPrefix = "${prop.";
|
||||
if(value.startsWith(propPrefix) && value.endsWith("}"))
|
||||
{
|
||||
String propertyName = value.substring(propPrefix.length()).replaceFirst("}$", "");
|
||||
String propertyValue = System.getProperty(propertyName);
|
||||
return (propertyValue);
|
||||
}
|
||||
|
||||
String literalPrefix = "${literal.";
|
||||
if(value.startsWith(literalPrefix) && value.endsWith("}"))
|
||||
{
|
||||
String literalValue = value.substring(literalPrefix.length()).replaceFirst("}$", "");
|
||||
return (literalValue);
|
||||
}
|
||||
|
||||
return (value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for customEnvironment - protected - meant to be called (at least at this
|
||||
** time), only in unit test
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected void setCustomEnvironment(Map<String, String> customEnvironment)
|
||||
{
|
||||
this.customEnvironment = customEnvironment;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private Map<String, String> getEnvironment()
|
||||
{
|
||||
if(this.customEnvironment != null)
|
||||
{
|
||||
return (this.customEnvironment);
|
||||
}
|
||||
|
||||
return System.getenv();
|
||||
}
|
||||
}
|
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions;
|
||||
|
||||
|
||||
import java.util.UUID;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobCallback;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobStatus;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
||||
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Base input class for all Q actions.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract class AbstractActionInput
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(AbstractActionInput.class);
|
||||
|
||||
protected QInstance instance;
|
||||
protected QSession session;
|
||||
|
||||
private AsyncJobCallback asyncJobCallback;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AbstractActionInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AbstractActionInput(QInstance instance)
|
||||
{
|
||||
this.instance = instance;
|
||||
validateInstance(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** performance instance validation (if not previously done).
|
||||
*******************************************************************************/
|
||||
private void validateInstance(QInstance instance)
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
// if this instance hasn't been validated yet, do so now //
|
||||
// noting that this will also enrich any missing metaData //
|
||||
////////////////////////////////////////////////////////////
|
||||
if(!instance.getHasBeenValidated())
|
||||
{
|
||||
try
|
||||
{
|
||||
new QInstanceValidator().validate(instance);
|
||||
}
|
||||
catch(QInstanceValidationException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
throw (new IllegalArgumentException("QInstance failed validation" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QAuthenticationMetaData getAuthenticationMetaData()
|
||||
{
|
||||
return (instance.getAuthentication());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for instance
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QInstance getInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for instance
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setInstance(QInstance instance)
|
||||
{
|
||||
validateInstance(instance);
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for session
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QSession getSession()
|
||||
{
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for session
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setSession(QSession session)
|
||||
{
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for asyncJobCallback
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AsyncJobCallback getAsyncJobCallback()
|
||||
{
|
||||
if(asyncJobCallback == null)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// don't return null here (too easy to NPE). instead, if someone wants one of these, create one and give it to them. //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
asyncJobCallback = new AsyncJobCallback(UUID.randomUUID(), new AsyncJobStatus());
|
||||
}
|
||||
return asyncJobCallback;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for asyncJobCallback
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setAsyncJobCallback(AsyncJobCallback asyncJobCallback)
|
||||
{
|
||||
this.asyncJobCallback = asyncJobCallback;
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Abstract base class for any qqq-action's output.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract class AbstractActionOutput
|
||||
{
|
||||
// todo - status codes?
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AbstractActionOutput()
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Base class for input for any qqq action that works against a table.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract class AbstractTableActionInput extends AbstractActionInput
|
||||
{
|
||||
private String tableName;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QBackendMetaData getBackend()
|
||||
{
|
||||
return (instance.getBackendForTable(getTableName()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QTableMetaData getTable()
|
||||
{
|
||||
return (instance.getTable(getTableName()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AbstractTableActionInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AbstractTableActionInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.metadata;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input for the meta-data action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class MetaDataInput extends AbstractActionInput
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public MetaDataInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public MetaDataInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.metadata;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Output for a metaData action
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class MetaDataOutput extends AbstractActionOutput
|
||||
{
|
||||
private Map<String, QFrontendTableMetaData> tables;
|
||||
private Map<String, QFrontendProcessMetaData> processes;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tables
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, QFrontendTableMetaData> getTables()
|
||||
{
|
||||
return tables;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tables
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTables(Map<String, QFrontendTableMetaData> tables)
|
||||
{
|
||||
this.tables = tables;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processes
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, QFrontendProcessMetaData> getProcesses()
|
||||
{
|
||||
return processes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processes
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setProcesses(Map<String, QFrontendProcessMetaData> processes)
|
||||
{
|
||||
this.processes = processes;
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.metadata;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input for meta-data for a process.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessMetaDataInput extends AbstractActionInput
|
||||
{
|
||||
private String processName;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaDataInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaDataInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getProcessName()
|
||||
{
|
||||
return processName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.metadata;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Output for a process-metaData action
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class ProcessMetaDataOutput extends AbstractActionOutput
|
||||
{
|
||||
private QFrontendProcessMetaData process;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for process
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFrontendProcessMetaData getProcess()
|
||||
{
|
||||
return process;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for process
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setProcess(QFrontendProcessMetaData process)
|
||||
{
|
||||
this.process = process;
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.metadata;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input for meta-data for a table.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TableMetaDataInput extends AbstractActionInput
|
||||
{
|
||||
private String tableName;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableMetaDataInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableMetaDataInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.metadata;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Output for a table-metaData action
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class TableMetaDataOutput extends AbstractActionOutput
|
||||
{
|
||||
private QFrontendTableMetaData table;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for table
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFrontendTableMetaData getTable()
|
||||
{
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for table
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTable(QFrontendTableMetaData table)
|
||||
{
|
||||
this.table = table;
|
||||
}
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessState implements Serializable
|
||||
{
|
||||
private List<QRecord> records = new ArrayList<>();
|
||||
private Map<String, Serializable> values = new HashMap<>();
|
||||
private Optional<String> nextStepName = Optional.empty();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return records;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecords(List<QRecord> records)
|
||||
{
|
||||
this.records = records;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for nextStepName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Optional<String> getNextStepName()
|
||||
{
|
||||
return nextStepName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for nextStepName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setNextStepName(String nextStepName)
|
||||
{
|
||||
this.nextStepName = Optional.of(nextStepName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** clear out the value of nextStepName (set the Optional to empty)
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void clearNextStepName()
|
||||
{
|
||||
this.nextStepName = Optional.empty();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Model a file that a user uploaded (or otherwise submitted to the qqq backend).
|
||||
*******************************************************************************/
|
||||
public class QUploadedFile implements Serializable
|
||||
{
|
||||
public static final String DEFAULT_UPLOADED_FILE_FIELD_NAME = "uploadedFileKey";
|
||||
|
||||
private String filename;
|
||||
private byte[] bytes;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for filename
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getFilename()
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for filename
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFilename(String filename)
|
||||
{
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for bytes
|
||||
**
|
||||
*******************************************************************************/
|
||||
public byte[] getBytes()
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for bytes
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setBytes(byte[] bytes)
|
||||
{
|
||||
this.bytes = bytes;
|
||||
}
|
||||
}
|
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobCallback;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobStatus;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallback;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input data container for the RunBackendStep action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class RunBackendStepInput extends AbstractActionInput
|
||||
{
|
||||
private ProcessState processState;
|
||||
private String processName;
|
||||
private String tableName;
|
||||
private String stepName;
|
||||
private QProcessCallback callback;
|
||||
private AsyncJobCallback asyncJobCallback;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepInput()
|
||||
{
|
||||
processState = new ProcessState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
processState = new ProcessState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepInput(QInstance instance, ProcessState processState)
|
||||
{
|
||||
super(instance);
|
||||
this.processState = processState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QStepMetaData getStepMetaData()
|
||||
{
|
||||
return (instance.getProcessStep(getProcessName(), getStepName()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getProcessName()
|
||||
{
|
||||
return processName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepInput withProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepInput withTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QTableMetaData getTable()
|
||||
{
|
||||
if(tableName == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (instance.getTable(tableName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for functionName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getStepName()
|
||||
{
|
||||
return stepName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for functionName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setStepName(String stepName)
|
||||
{
|
||||
this.stepName = stepName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for functionName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepInput withFunctionName(String functionName)
|
||||
{
|
||||
this.stepName = functionName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return processState.getRecords();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecords(List<QRecord> records)
|
||||
{
|
||||
this.processState.setRecords(records);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepInput withRecords(List<QRecord> records)
|
||||
{
|
||||
this.processState.setRecords(records);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return processState.getValues();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.processState.setValues(values);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepInput withValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.processState.setValues(values);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepInput addValue(String fieldName, Serializable value)
|
||||
{
|
||||
this.processState.getValues().put(fieldName, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for callback
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QProcessCallback getCallback()
|
||||
{
|
||||
return callback;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for callback
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCallback(QProcessCallback callback)
|
||||
{
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for callback
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepInput withCallback(QProcessCallback callback)
|
||||
{
|
||||
this.callback = callback;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getValue(String fieldName)
|
||||
{
|
||||
return (processState.getValues().get(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's date value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public LocalDate getValueLocalDate(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsLocalDate(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getValueString(String fieldName)
|
||||
{
|
||||
return ((String) getValue(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getValueInteger(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsInteger(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Accessor for processState - protected, because we generally want to access
|
||||
** its members through wrapper methods, we think
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected ProcessState getProcessState()
|
||||
{
|
||||
return processState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setAsyncJobCallback(AsyncJobCallback asyncJobCallback)
|
||||
{
|
||||
this.asyncJobCallback = asyncJobCallback;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AsyncJobCallback getAsyncJobCallback()
|
||||
{
|
||||
if(asyncJobCallback == null)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// avoid NPE in case we didn't have one of these! create a new one... //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
asyncJobCallback = new AsyncJobCallback(UUID.randomUUID(), new AsyncJobStatus());
|
||||
}
|
||||
return (asyncJobCallback);
|
||||
}
|
||||
}
|
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Output data container for the RunBackendStep action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class RunBackendStepOutput extends AbstractActionOutput
|
||||
{
|
||||
private ProcessState processState;
|
||||
private Exception exception; // todo - make optional
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "RunBackendStepOutput{exception?='" + (exception == null ? "null" : exception.getMessage())
|
||||
+ ",records.size()=" + (processState == null ? null : processState.getRecords().size())
|
||||
+ ",values=" + (processState == null ? null : processState.getValues())
|
||||
+ "}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepOutput()
|
||||
{
|
||||
this.processState = new ProcessState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** e.g., populate the process state (records, values) in this result object.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void seedFromRequest(RunBackendStepInput runBackendStepInput)
|
||||
{
|
||||
this.processState = runBackendStepInput.getProcessState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return processState.getRecords();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecords(List<QRecord> records)
|
||||
{
|
||||
this.processState.setRecords(records);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepOutput withRecords(List<QRecord> records)
|
||||
{
|
||||
this.processState.setRecords(records);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return processState.getValues();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.processState.setValues(values);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepOutput withValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.processState.setValues(values);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunBackendStepOutput addValue(String fieldName, Serializable value)
|
||||
{
|
||||
this.processState.getValues().put(fieldName, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Accessor for processState
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessState getProcessState()
|
||||
{
|
||||
return processState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setException(Exception exception)
|
||||
{
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Exception getException()
|
||||
{
|
||||
return exception;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getValue(String fieldName)
|
||||
{
|
||||
return (processState.getValues().get(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getValueString(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsString(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getValueInteger(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsInteger(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Boolean getValueBoolean(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsBoolean(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public BigDecimal getValueBigDecimal(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsBigDecimal(getValue(fieldName)));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobCallback;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallback;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input data container for the RunProcess action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class RunProcessInput extends AbstractActionInput
|
||||
{
|
||||
private String processName;
|
||||
private QProcessCallback callback;
|
||||
private ProcessState processState;
|
||||
private FrontendStepBehavior frontendStepBehavior = FrontendStepBehavior.BREAK;
|
||||
private String startAfterStep;
|
||||
private String processUUID;
|
||||
private AsyncJobCallback asyncJobCallback;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public enum FrontendStepBehavior
|
||||
{
|
||||
BREAK,
|
||||
SKIP,
|
||||
FAIL
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessInput()
|
||||
{
|
||||
processState = new ProcessState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
processState = new ProcessState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** e.g., for steps after the first step in a process, seed the data in a run
|
||||
** function request from a process state.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void seedFromProcessState(ProcessState processState)
|
||||
{
|
||||
this.processState = processState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QProcessMetaData getProcessMetaData()
|
||||
{
|
||||
return (instance.getProcess(getProcessName()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getProcessName()
|
||||
{
|
||||
return processName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessInput withProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return processState.getRecords();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecords(List<QRecord> records)
|
||||
{
|
||||
this.processState.setRecords(records);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessInput withRecords(List<QRecord> records)
|
||||
{
|
||||
setRecords(records);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return this.processState.getValues();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.processState.setValues(values);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessInput withValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.processState.setValues(values);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessInput addValue(String fieldName, Serializable value)
|
||||
{
|
||||
this.processState.getValues().put(fieldName, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for callback
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QProcessCallback getCallback()
|
||||
{
|
||||
return callback;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for callback
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCallback(QProcessCallback callback)
|
||||
{
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for callback
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessInput withCallback(QProcessCallback callback)
|
||||
{
|
||||
this.callback = callback;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getValue(String fieldName)
|
||||
{
|
||||
return (this.processState.getValues().get(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getValueString(String fieldName)
|
||||
{
|
||||
return ((String) getValue(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getValueInteger(String fieldName)
|
||||
{
|
||||
return ((Integer) getValue(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Accessor for processState
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessState getProcessState()
|
||||
{
|
||||
return processState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for frontendStepBehavior
|
||||
**
|
||||
*******************************************************************************/
|
||||
public FrontendStepBehavior getFrontendStepBehavior()
|
||||
{
|
||||
return frontendStepBehavior;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for frontendStepBehavior
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFrontendStepBehavior(FrontendStepBehavior frontendStepBehavior)
|
||||
{
|
||||
this.frontendStepBehavior = frontendStepBehavior;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setStartAfterStep(String startAfterStep)
|
||||
{
|
||||
this.startAfterStep = startAfterStep;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getStartAfterStep()
|
||||
{
|
||||
return startAfterStep;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setProcessUUID(String processUUID)
|
||||
{
|
||||
this.processUUID = processUUID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getProcessUUID()
|
||||
{
|
||||
return processUUID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setAsyncJobCallback(AsyncJobCallback asyncJobCallback)
|
||||
{
|
||||
this.asyncJobCallback = asyncJobCallback;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AsyncJobCallback getAsyncJobCallback()
|
||||
{
|
||||
return asyncJobCallback;
|
||||
}
|
||||
}
|
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Output data container for the RunProcess action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class RunProcessOutput extends AbstractActionOutput implements Serializable
|
||||
{
|
||||
private ProcessState processState;
|
||||
private String processUUID;
|
||||
private Optional<Exception> exception = Optional.empty();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessOutput()
|
||||
{
|
||||
processState = new ProcessState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessOutput(ProcessState processState)
|
||||
{
|
||||
this.processState = processState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "RunProcessOutput{uuid='" + processUUID
|
||||
+ ",exception?='" + (exception.isPresent() ? exception.get().getMessage() : "null")
|
||||
+ ",records.size()=" + (processState == null ? null : processState.getRecords().size())
|
||||
+ ",values=" + (processState == null ? null : processState.getValues())
|
||||
+ "}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return processState.getRecords();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecords(List<QRecord> records)
|
||||
{
|
||||
this.processState.setRecords(records);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessOutput withRecords(List<QRecord> records)
|
||||
{
|
||||
this.processState.setRecords(records);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return processState.getValues();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.processState.setValues(values);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessOutput withValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.processState.setValues(values);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessOutput addValue(String fieldName, Serializable value)
|
||||
{
|
||||
this.processState.getValues().put(fieldName, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processUUID
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getProcessUUID()
|
||||
{
|
||||
return processUUID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processUUID
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setProcessUUID(String processUUID)
|
||||
{
|
||||
this.processUUID = processUUID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processState
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessState getProcessState()
|
||||
{
|
||||
return processState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processState
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setProcessState(ProcessState processState)
|
||||
{
|
||||
this.processState = processState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setException(Exception exception)
|
||||
{
|
||||
this.exception = Optional.of(exception);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Optional<Exception> getException()
|
||||
{
|
||||
return exception;
|
||||
}
|
||||
}
|
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.reporting;
|
||||
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.function.Supplier;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.CsvReportStreamer;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.ExcelReportStreamer;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.ReportStreamerInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import org.dhatim.fastexcel.Worksheet;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** QQQ Report/export file formats
|
||||
*******************************************************************************/
|
||||
public enum ReportFormat
|
||||
{
|
||||
XLSX(Worksheet.MAX_ROWS, Worksheet.MAX_COLS, ExcelReportStreamer::new, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
|
||||
CSV(null, null, CsvReportStreamer::new, "text/csv");
|
||||
|
||||
|
||||
private final Integer maxRows;
|
||||
private final Integer maxCols;
|
||||
private final String mimeType;
|
||||
|
||||
private final Supplier<? extends ReportStreamerInterface> streamerConstructor;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
ReportFormat(Integer maxRows, Integer maxCols, Supplier<? extends ReportStreamerInterface> streamerConstructor, String mimeType)
|
||||
{
|
||||
this.maxRows = maxRows;
|
||||
this.maxCols = maxCols;
|
||||
this.mimeType = mimeType;
|
||||
this.streamerConstructor = streamerConstructor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static ReportFormat fromString(String format) throws QUserFacingException
|
||||
{
|
||||
if(!StringUtils.hasContent(format))
|
||||
{
|
||||
throw (new QUserFacingException("Report format was not specified."));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return (ReportFormat.valueOf(format.toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
catch(IllegalArgumentException iae)
|
||||
{
|
||||
throw (new QUserFacingException("Unsupported report format: " + format + "."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for maxRows
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getMaxRows()
|
||||
{
|
||||
return maxRows;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for maxCols
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getMaxCols()
|
||||
{
|
||||
return maxCols;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for mimeType
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getMimeType()
|
||||
{
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ReportStreamerInterface newReportStreamer()
|
||||
{
|
||||
return (streamerConstructor.get());
|
||||
}
|
||||
}
|
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.reporting;
|
||||
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input for a Report action
|
||||
*******************************************************************************/
|
||||
public class ReportInput extends AbstractTableActionInput
|
||||
{
|
||||
private QQueryFilter queryFilter;
|
||||
private Integer limit;
|
||||
private List<String> fieldNames;
|
||||
|
||||
private String filename;
|
||||
private ReportFormat reportFormat;
|
||||
private OutputStream reportOutputStream;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ReportInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ReportInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ReportInput(QInstance instance, QSession session)
|
||||
{
|
||||
super(instance);
|
||||
setSession(session);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for queryFilter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QQueryFilter getQueryFilter()
|
||||
{
|
||||
return queryFilter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for queryFilter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setQueryFilter(QQueryFilter queryFilter)
|
||||
{
|
||||
this.queryFilter = queryFilter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for limit
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getLimit()
|
||||
{
|
||||
return limit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for limit
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setLimit(Integer limit)
|
||||
{
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for fieldNames
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<String> getFieldNames()
|
||||
{
|
||||
return fieldNames;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for fieldNames
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFieldNames(List<String> fieldNames)
|
||||
{
|
||||
this.fieldNames = fieldNames;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for filename
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getFilename()
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for filename
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFilename(String filename)
|
||||
{
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for reportFormat
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ReportFormat getReportFormat()
|
||||
{
|
||||
return reportFormat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for reportFormat
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setReportFormat(ReportFormat reportFormat)
|
||||
{
|
||||
this.reportFormat = reportFormat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for reportOutputStream
|
||||
**
|
||||
*******************************************************************************/
|
||||
public OutputStream getReportOutputStream()
|
||||
{
|
||||
return reportOutputStream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for reportOutputStream
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setReportOutputStream(OutputStream reportOutputStream)
|
||||
{
|
||||
this.reportOutputStream = reportOutputStream;
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.reporting;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Output for a Report action
|
||||
*******************************************************************************/
|
||||
public class ReportOutput implements Serializable
|
||||
{
|
||||
public long recordCount;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for recordCount
|
||||
**
|
||||
*******************************************************************************/
|
||||
public long getRecordCount()
|
||||
{
|
||||
return recordCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for recordCount
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecordCount(long recordCount)
|
||||
{
|
||||
this.recordCount = recordCount;
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.shared.mapping;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** For bulk-loads, define where a QField comes from in an input data source.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract class AbstractQFieldMapping<T>
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** Enum to define the types of sources a mapping may use
|
||||
**
|
||||
*******************************************************************************/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public enum SourceType
|
||||
{
|
||||
KEY(String.class),
|
||||
INDEX(Integer.class);
|
||||
|
||||
private Class sourceClass;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** enum constructor
|
||||
*******************************************************************************/
|
||||
SourceType(Class sourceClass)
|
||||
{
|
||||
this.sourceClass = sourceClass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for sourceClass
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Class getSourceClass()
|
||||
{
|
||||
return sourceClass;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** For a given field, return its source - a key (e.g., from a json object or csv
|
||||
** with a header row) or an index (for a csv w/o a header)
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract T getFieldSource(String fieldName);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** for a mapping instance, get what its source-type is
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract SourceType getSourceType();
|
||||
}
|
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.shared.mapping;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Field Mapping implementation that uses Integer keys (e.g., from a CSV file
|
||||
** WITHOUT a header row).
|
||||
**
|
||||
** Note: 1-based index!!
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QIndexBasedFieldMapping extends AbstractQFieldMapping<Integer>
|
||||
{
|
||||
private Map<String, Integer> mapping;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get the field source (e.g., integer index of a CSV column) corresponding to a
|
||||
** propery qqq table fieldName.
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public Integer getFieldSource(String fieldName)
|
||||
{
|
||||
if(mapping == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (mapping.get(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Tell framework what kind of keys this mapping class uses (INDEX)
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public SourceType getSourceType()
|
||||
{
|
||||
return (SourceType.INDEX);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Add a single mapping to this mapping object. fieldName = qqq metaData fieldName,
|
||||
** key = field index (integer) in the CSV
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addMapping(String fieldName, Integer key)
|
||||
{
|
||||
if(mapping == null)
|
||||
{
|
||||
mapping = new LinkedHashMap<>();
|
||||
}
|
||||
mapping.put(fieldName, key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluently add a single mapping to this mapping object. fieldName = qqq metaData
|
||||
** fieldName, key = field index (integer) in the CSV
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QIndexBasedFieldMapping withMapping(String fieldName, Integer key)
|
||||
{
|
||||
addMapping(fieldName, key);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for mapping
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Integer> getMapping()
|
||||
{
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for mapping
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setMapping(Map<String, Integer> mapping)
|
||||
{
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.shared.mapping;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Field Mapping implementation that uses string keys (e.g., from a CSV file
|
||||
** with a header row, or from one JSON object to the proper qqq field names)
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QKeyBasedFieldMapping extends AbstractQFieldMapping<String>
|
||||
{
|
||||
private Map<String, String> mapping;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get the source field (e.g., name that's in the CSV header or the input json
|
||||
** object) corresponding to a proper qqq table fieldName.
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String getFieldSource(String fieldName)
|
||||
{
|
||||
if(mapping == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (mapping.get(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Tell framework what kind of keys this mapping class uses (KEY)
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public SourceType getSourceType()
|
||||
{
|
||||
return (SourceType.KEY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Add a single mapping to this mapping object. fieldName = qqq metaData fieldName,
|
||||
** key = field name in the CSV or source-json, for example.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addMapping(String fieldName, String key)
|
||||
{
|
||||
if(mapping == null)
|
||||
{
|
||||
mapping = new LinkedHashMap<>();
|
||||
}
|
||||
mapping.put(fieldName, key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluently add a single mapping to this mapping object. fieldName = qqq metaData fieldName,
|
||||
** key = field name in the CSV or source-json, for example.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QKeyBasedFieldMapping withMapping(String fieldName, String key)
|
||||
{
|
||||
addMapping(fieldName, key);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for mapping
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, String> getMapping()
|
||||
{
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for mapping
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setMapping(Map<String, String> mapping)
|
||||
{
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.count;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input data for the Count action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class CountInput extends AbstractTableActionInput
|
||||
{
|
||||
private QQueryFilter filter;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public CountInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public CountInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for filter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QQueryFilter getFilter()
|
||||
{
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for filter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFilter(QQueryFilter filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.count;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Output for a count action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class CountOutput extends AbstractActionOutput
|
||||
{
|
||||
private Integer count;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getCount()
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCount(Integer count)
|
||||
{
|
||||
this.count = count;
|
||||
}
|
||||
}
|
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.delete;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input for a Delete action.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class DeleteInput extends AbstractTableActionInput
|
||||
{
|
||||
private List<Serializable> primaryKeys;
|
||||
private QQueryFilter queryFilter;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public DeleteInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public DeleteInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for ids
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<Serializable> getPrimaryKeys()
|
||||
{
|
||||
return primaryKeys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for ids
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setPrimaryKeys(List<Serializable> primaryKeys)
|
||||
{
|
||||
this.primaryKeys = primaryKeys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for ids
|
||||
**
|
||||
*******************************************************************************/
|
||||
public DeleteInput withPrimaryKeys(List<Serializable> primaryKeys)
|
||||
{
|
||||
this.primaryKeys = primaryKeys;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for queryFilter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QQueryFilter getQueryFilter()
|
||||
{
|
||||
return queryFilter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for queryFilter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setQueryFilter(QQueryFilter queryFilter)
|
||||
{
|
||||
this.queryFilter = queryFilter;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for queryFilter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public DeleteInput withQueryFilter(QQueryFilter queryFilter)
|
||||
{
|
||||
this.queryFilter = queryFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.delete;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Output for a delete action
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class DeleteOutput extends AbstractActionOutput implements Serializable
|
||||
{
|
||||
private int deletedRecordCount = 0;
|
||||
private List<QRecord> recordsWithErrors;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for deletedRecordCount
|
||||
**
|
||||
*******************************************************************************/
|
||||
public int getDeletedRecordCount()
|
||||
{
|
||||
return deletedRecordCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for deletedRecordCount
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setDeletedRecordCount(int deletedRecordCount)
|
||||
{
|
||||
this.deletedRecordCount = deletedRecordCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecordsWithErrors()
|
||||
{
|
||||
return recordsWithErrors;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecordsWithErrors(List<QRecord> recordsWithErrors)
|
||||
{
|
||||
this.recordsWithErrors = recordsWithErrors;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addRecordWithError(QRecord recordWithError)
|
||||
{
|
||||
if(this.recordsWithErrors == null)
|
||||
{
|
||||
this.recordsWithErrors = new ArrayList<>();
|
||||
}
|
||||
this.recordsWithErrors.add(recordWithError);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addToDeletedRecordCount(int i)
|
||||
{
|
||||
deletedRecordCount += i;
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.insert;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input data for the Insert action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class InsertInput extends AbstractTableActionInput
|
||||
{
|
||||
private List<QRecord> records;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public InsertInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public InsertInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return records;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecords(List<QRecord> records)
|
||||
{
|
||||
this.records = records;
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.insert;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Output for an insert action
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class InsertOutput extends AbstractActionOutput
|
||||
{
|
||||
private List<QRecord> records;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return records;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecords(List<QRecord> records)
|
||||
{
|
||||
this.records = records;
|
||||
}
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.query;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Possible query criteria field operators
|
||||
**
|
||||
*******************************************************************************/
|
||||
public enum QCriteriaOperator
|
||||
{
|
||||
EQUALS,
|
||||
NOT_EQUALS,
|
||||
IN,
|
||||
NOT_IN,
|
||||
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
|
||||
}
|
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.query;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* A single criteria Component of a Query
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class QFilterCriteria implements Serializable
|
||||
{
|
||||
private String fieldName;
|
||||
private QCriteriaOperator operator;
|
||||
private List<Serializable> values;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for fieldName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getFieldName()
|
||||
{
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for fieldName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFieldName(String fieldName)
|
||||
{
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for fieldName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFilterCriteria withFieldName(String fieldName)
|
||||
{
|
||||
this.fieldName = fieldName;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for operator
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QCriteriaOperator getOperator()
|
||||
{
|
||||
return operator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for operator
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setOperator(QCriteriaOperator operator)
|
||||
{
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for operator
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFilterCriteria withOperator(QCriteriaOperator operator)
|
||||
{
|
||||
this.operator = operator;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<Serializable> getValues()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setValues(List<Serializable> values)
|
||||
{
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFilterCriteria withValues(List<Serializable> values)
|
||||
{
|
||||
this.values = values;
|
||||
return this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.query;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Bean representing an element of a query order-by clause.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QFilterOrderBy implements Serializable
|
||||
{
|
||||
private String fieldName;
|
||||
private boolean isAscending = true;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for fieldName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getFieldName()
|
||||
{
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for fieldName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFieldName(String fieldName)
|
||||
{
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent Setter for fieldName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFilterOrderBy withFieldName(String fieldName)
|
||||
{
|
||||
this.fieldName = fieldName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for isAscending
|
||||
**
|
||||
*******************************************************************************/
|
||||
public boolean getIsAscending()
|
||||
{
|
||||
return isAscending;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for isAscending
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setIsAscending(boolean ascending)
|
||||
{
|
||||
isAscending = ascending;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent Setter for isAscending
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFilterOrderBy withIsAscending(boolean ascending)
|
||||
{
|
||||
this.isAscending = ascending;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.query;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Full "filter" for a query - a list of criteria and order-bys
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class QQueryFilter implements Serializable
|
||||
{
|
||||
private List<QFilterCriteria> criteria = new ArrayList<>();
|
||||
private List<QFilterOrderBy> orderBys = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for criteria
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QFilterCriteria> getCriteria()
|
||||
{
|
||||
return criteria;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for criteria
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCriteria(List<QFilterCriteria> criteria)
|
||||
{
|
||||
this.criteria = criteria;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for order
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QFilterOrderBy> getOrderBys()
|
||||
{
|
||||
return orderBys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for order
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setOrderBys(List<QFilterOrderBy> orderBys)
|
||||
{
|
||||
this.orderBys = orderBys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addCriteria(QFilterCriteria qFilterCriteria)
|
||||
{
|
||||
if(criteria == null)
|
||||
{
|
||||
criteria = new ArrayList<>();
|
||||
}
|
||||
criteria.add(qFilterCriteria);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QQueryFilter withCriteria(QFilterCriteria qFilterCriteria)
|
||||
{
|
||||
addCriteria(qFilterCriteria);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addOrderBy(QFilterOrderBy qFilterOrderBy)
|
||||
{
|
||||
if(orderBys == null)
|
||||
{
|
||||
orderBys = new ArrayList<>();
|
||||
}
|
||||
orderBys.add(qFilterOrderBy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QQueryFilter withOrderBy(QFilterOrderBy qFilterOrderBy)
|
||||
{
|
||||
addOrderBy(qFilterOrderBy);
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.query;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input data for the Query action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QueryInput extends AbstractTableActionInput
|
||||
{
|
||||
private QQueryFilter filter;
|
||||
private Integer skip;
|
||||
private Integer limit;
|
||||
|
||||
private RecordPipe recordPipe;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryInput(QInstance instance, QSession session)
|
||||
{
|
||||
super(instance);
|
||||
setSession(session);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for filter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QQueryFilter getFilter()
|
||||
{
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for filter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFilter(QQueryFilter filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for skip
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getSkip()
|
||||
{
|
||||
return skip;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for skip
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setSkip(Integer skip)
|
||||
{
|
||||
this.skip = skip;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for limit
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getLimit()
|
||||
{
|
||||
return limit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for limit
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setLimit(Integer limit)
|
||||
{
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for recordPipe
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RecordPipe getRecordPipe()
|
||||
{
|
||||
return recordPipe;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for recordPipe
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecordPipe(RecordPipe recordPipe)
|
||||
{
|
||||
this.recordPipe = recordPipe;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.query;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Output for a query action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QueryOutput extends AbstractActionOutput implements Serializable
|
||||
{
|
||||
private QueryOutputStorageInterface storage;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Construct a new query output, based on a query input (which will drive some
|
||||
** of how our output is structured... e.g., if we pipe the output)
|
||||
*******************************************************************************/
|
||||
public QueryOutput(QueryInput queryInput)
|
||||
{
|
||||
if(queryInput.getRecordPipe() != null)
|
||||
{
|
||||
storage = new QueryOutputRecordPipe(queryInput.getRecordPipe());
|
||||
}
|
||||
else
|
||||
{
|
||||
storage = new QueryOutputList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Add a record to this output. Note - we often don't care, in such a method,
|
||||
** whether the record is "completed" or not (e.g., all of its values have been
|
||||
** populated) - but - note in here - that this records MAY be going into a pipe
|
||||
** that could be read asynchronously, at any time, by another thread - SO - only
|
||||
** completely populated records should be passed into this method.
|
||||
*******************************************************************************/
|
||||
public void addRecord(QRecord record)
|
||||
{
|
||||
storage.addRecord(record);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** add a list of records to this output
|
||||
*******************************************************************************/
|
||||
public void addRecords(List<QRecord> records)
|
||||
{
|
||||
storage.addRecords(records);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return storage.getRecords();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.query;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Kinda the standard way that a QueryOutput would store its records - in a
|
||||
** simple list.
|
||||
*******************************************************************************/
|
||||
class QueryOutputList implements QueryOutputStorageInterface
|
||||
{
|
||||
private List<QRecord> records = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryOutputList()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** add a record to this output
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void addRecord(QRecord record)
|
||||
{
|
||||
records.add(record);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** add a list of records to this output
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void addRecords(List<QRecord> records)
|
||||
{
|
||||
this.records.addAll(records);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get all stored records
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return (records);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.query;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.utils.SleepUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Query output that uses a RecordPipe
|
||||
*******************************************************************************/
|
||||
class QueryOutputRecordPipe implements QueryOutputStorageInterface
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(QueryOutputRecordPipe.class);
|
||||
|
||||
private RecordPipe recordPipe;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryOutputRecordPipe(RecordPipe recordPipe)
|
||||
{
|
||||
this.recordPipe = recordPipe;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** add a record to this output
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void addRecord(QRecord record)
|
||||
{
|
||||
if(!recordPipe.addRecord(record))
|
||||
{
|
||||
do
|
||||
{
|
||||
LOG.debug("Record pipe.add failed (due to full pipe). Blocking.");
|
||||
SleepUtils.sleep(10, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
while(!recordPipe.addRecord(record));
|
||||
LOG.debug("Done blocking.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void blockIfPipeIsTooFull()
|
||||
{
|
||||
if(recordPipe.countAvailableRecords() >= 100_000)
|
||||
{
|
||||
LOG.info("Record pipe is kinda full. Blocking for a bit");
|
||||
do
|
||||
{
|
||||
SleepUtils.sleep(10, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
while(recordPipe.countAvailableRecords() >= 10_000);
|
||||
LOG.info("Done blocking.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** add a list of records to this output
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void addRecords(List<QRecord> records)
|
||||
{
|
||||
recordPipe.addRecords(records);
|
||||
blockIfPipeIsTooFull();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get all stored records
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
throw (new IllegalStateException("getRecords may not be called on a piped query output"));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.query;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface used within QueryOutput, to handle diffrent ways we may store records
|
||||
** (e.g., in a list (that holds them all), or a pipe, that streams them to a consumer thread))
|
||||
*******************************************************************************/
|
||||
interface QueryOutputStorageInterface
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** add a records to this output
|
||||
*******************************************************************************/
|
||||
void addRecord(QRecord record);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** add a list of records to this output
|
||||
*******************************************************************************/
|
||||
void addRecords(List<QRecord> records);
|
||||
|
||||
/*******************************************************************************
|
||||
** Get all stored records
|
||||
*******************************************************************************/
|
||||
List<QRecord> getRecords();
|
||||
}
|
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.update;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Input data handler for the update action
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class UpdateInput extends AbstractTableActionInput
|
||||
{
|
||||
private List<QRecord> records;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// allow a caller to specify that they KNOW this optimization (e.g., in SQL) can be made. //
|
||||
// If you set this to true, but it isn't, then you may not get an accurate update. //
|
||||
// If you set this to false, but it isn't, then you may not get the best performance. //
|
||||
// Just leave it null if you don't know what you're dong. //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private Boolean areAllValuesBeingUpdatedTheSame = null;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public UpdateInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public UpdateInput(QInstance instance)
|
||||
{
|
||||
super(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return records;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for records
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecords(List<QRecord> records)
|
||||
{
|
||||
this.records = records;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for areAllValuesBeingUpdatedTheSame
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Boolean getAreAllValuesBeingUpdatedTheSame()
|
||||
{
|
||||
return areAllValuesBeingUpdatedTheSame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for areAllValuesBeingUpdatedTheSame
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setAreAllValuesBeingUpdatedTheSame(Boolean areAllValuesBeingUpdatedTheSame)
|
||||
{
|
||||
this.areAllValuesBeingUpdatedTheSame = areAllValuesBeingUpdatedTheSame;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.actions.tables.update;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Output for an update action
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class UpdateOutput extends AbstractActionOutput
|
||||
{
|
||||
private List<QRecord> records;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> getRecords()
|
||||
{
|
||||
return records;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setRecords(List<QRecord> records)
|
||||
{
|
||||
this.records = records;
|
||||
}
|
||||
}
|
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.data;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Data Record within qqq. e.g., a single row from a database.
|
||||
**
|
||||
** Actual values (e.g., as stored in the backend system) are in the `values`
|
||||
** map. Keys in this map are fieldNames from the QTableMetaData.
|
||||
**
|
||||
** "Display values" (e.g., labels for possible values, or formatted numbers
|
||||
** (e.g., quantities with commas)) are in the displayValues map.
|
||||
**
|
||||
** backendDetails are additional data about a record, that aren't strictly
|
||||
** values, but are more like meta-data - e.g., for a file-backend, what file the
|
||||
** record came from.
|
||||
**
|
||||
** Errors are meant to hold information about things that went wrong when
|
||||
** processing a record - e.g., in a list of records that may be the output of an
|
||||
** action, like a bulk load. TODO - redo as some status object?
|
||||
*******************************************************************************/
|
||||
public class QRecord implements Serializable
|
||||
{
|
||||
private String tableName;
|
||||
private Map<String, Serializable> values = new LinkedHashMap<>();
|
||||
private Map<String, String> displayValues = new LinkedHashMap<>();
|
||||
private Map<String, Serializable> backendDetails = new LinkedHashMap<>();
|
||||
private List<String> errors = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Default constructor.
|
||||
*******************************************************************************/
|
||||
public QRecord()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QRecord(QTableMetaData tableMetaData, Serializable primaryKeyValue)
|
||||
{
|
||||
setTableName(tableMetaData.getName());
|
||||
setValue(tableMetaData.getPrimaryKeyField(), primaryKeyValue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Copy constructor.
|
||||
** TODO ... should this do deep copies?
|
||||
*******************************************************************************/
|
||||
public QRecord(QRecord record)
|
||||
{
|
||||
this.tableName = record.tableName;
|
||||
this.values = record.values;
|
||||
this.displayValues = record.displayValues;
|
||||
this.backendDetails = record.backendDetails;
|
||||
this.errors = record.errors;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setValue(String fieldName, Serializable value)
|
||||
{
|
||||
values.put(fieldName, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QRecord withValue(String fieldName, Serializable value)
|
||||
{
|
||||
setValue(fieldName, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setDisplayValue(String fieldName, String displayValue)
|
||||
{
|
||||
displayValues.put(fieldName, displayValue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QRecord withDisplayValue(String fieldName, String displayValue)
|
||||
{
|
||||
setDisplayValue(fieldName, displayValue);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QRecord withTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getValue(String fieldName)
|
||||
{
|
||||
return (values.get(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for displayValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, String> getDisplayValues()
|
||||
{
|
||||
return displayValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for displayValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setDisplayValues(Map<String, String> displayValues)
|
||||
{
|
||||
this.displayValues = displayValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getDisplayValue(String fieldName)
|
||||
{
|
||||
return (displayValues.get(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getValueString(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsString(values.get(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getValueInteger(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsInteger(values.get(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public BigDecimal getValueBigDecimal(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsBigDecimal(values.get(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Boolean getValueBoolean(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsBoolean(values.get(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public LocalDate getValueLocalDate(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsLocalDate(values.get(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for backendDetails
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getBackendDetails()
|
||||
{
|
||||
return backendDetails;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for backendDetails
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setBackendDetails(Map<String, Serializable> backendDetails)
|
||||
{
|
||||
this.backendDetails = backendDetails;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Add one backendDetail to this record
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addBackendDetail(String key, Serializable value)
|
||||
{
|
||||
this.backendDetails.put(key, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluently Add one backendDetail to this record
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QRecord withBackendDetail(String key, Serializable value)
|
||||
{
|
||||
addBackendDetail(key, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get one backendDetail from this record
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getBackendDetail(String key)
|
||||
{
|
||||
return this.backendDetails.get(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get one backendDetail from this record as a String
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getBackendDetailString(String key)
|
||||
{
|
||||
return (String) this.backendDetails.get(key);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for errors
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<String> getErrors()
|
||||
{
|
||||
return (errors);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for errors
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setErrors(List<String> errors)
|
||||
{
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Add one error to this record
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addError(String error)
|
||||
{
|
||||
this.errors.add(error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluently Add one error to this record
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QRecord withError(String error)
|
||||
{
|
||||
addError(error);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Convert this record to an QRecordEntity
|
||||
*******************************************************************************/
|
||||
public <T extends QRecordEntity> T toEntity(Class<T> c) throws QException
|
||||
{
|
||||
return (QRecordEntity.fromQRecord(c, this));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.data;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.utils.ListingHash;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Base class for entity beans that are interoperable with QRecords.
|
||||
*******************************************************************************/
|
||||
public abstract class QRecordEntity
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(QRecordEntity.class);
|
||||
|
||||
private static final ListingHash<Class<? extends QRecordEntity>, QRecordEntityField> fieldMapping = new ListingHash<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Build an entity of this QRecord type from a QRecord
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static <T extends QRecordEntity> T fromQRecord(Class<T> c, QRecord qRecord) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
T entity = c.getConstructor().newInstance();
|
||||
|
||||
List<QRecordEntityField> fieldList = getFieldList(c);
|
||||
for(QRecordEntityField qRecordEntityField : fieldList)
|
||||
{
|
||||
Serializable value = qRecord.getValue(qRecordEntityField.getFieldName());
|
||||
Object typedValue = qRecordEntityField.convertValueType(value);
|
||||
qRecordEntityField.getSetter().invoke(entity, typedValue);
|
||||
}
|
||||
|
||||
return (entity);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QException("Error building entity from qRecord.", e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Convert this entity to a QRecord.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QRecord toQRecord() throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
QRecord qRecord = new QRecord();
|
||||
|
||||
List<QRecordEntityField> fieldList = getFieldList(this.getClass());
|
||||
for(QRecordEntityField qRecordEntityField : fieldList)
|
||||
{
|
||||
qRecord.setValue(qRecordEntityField.getFieldName(), (Serializable) qRecordEntityField.getGetter().invoke(this));
|
||||
}
|
||||
|
||||
return (qRecord);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QException("Error building qRecord from entity.", e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static List<QRecordEntityField> getFieldList(Class<? extends QRecordEntity> c)
|
||||
{
|
||||
if(!fieldMapping.containsKey(c))
|
||||
{
|
||||
List<QRecordEntityField> fieldList = new ArrayList<>();
|
||||
for(Method possibleGetter : c.getMethods())
|
||||
{
|
||||
if(isGetter(possibleGetter))
|
||||
{
|
||||
Optional<Method> setter = getSetterForGetter(c, possibleGetter);
|
||||
if(setter.isPresent())
|
||||
{
|
||||
String name = getFieldNameFromGetter(possibleGetter);
|
||||
fieldList.add(new QRecordEntityField(name, possibleGetter, setter.get(), possibleGetter.getReturnType()));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Getter method [" + possibleGetter.getName() + "] does not have a corresponding setter.");
|
||||
}
|
||||
}
|
||||
}
|
||||
fieldMapping.put(c, fieldList);
|
||||
}
|
||||
return (fieldMapping.get(c));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static String getFieldNameFromGetter(Method getter)
|
||||
{
|
||||
String nameWithoutGet = getter.getName().replaceFirst("^get", "");
|
||||
if(nameWithoutGet.length() == 1)
|
||||
{
|
||||
return (nameWithoutGet.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
return (nameWithoutGet.substring(0, 1).toLowerCase(Locale.ROOT) + nameWithoutGet.substring(1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static boolean isGetter(Method method)
|
||||
{
|
||||
if(method.getParameterTypes().length == 0 && method.getName().matches("^get[A-Z].*"))
|
||||
{
|
||||
if(isSupportedFieldType(method.getReturnType()))
|
||||
{
|
||||
return (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!method.getName().equals("getClass"))
|
||||
{
|
||||
LOG.info("Method [" + method.getName() + "] looks like a getter, but its return type, [" + method.getReturnType() + "], isn't supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static Optional<Method> getSetterForGetter(Class<? extends QRecordEntity> c, Method getter)
|
||||
{
|
||||
String setterName = getter.getName().replaceFirst("^get", "set");
|
||||
for(Method method : c.getMethods())
|
||||
{
|
||||
if(method.getName().equals(setterName))
|
||||
{
|
||||
if(method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(getter.getReturnType()))
|
||||
{
|
||||
return (Optional.of(method));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Method [" + method.getName() + "] looks like a setter for [" + getter.getName() + "], but its parameters, [" + Arrays.toString(method.getParameterTypes()) + "], don't match the getter's return type [" + getter.getReturnType() + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
return (Optional.empty());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static boolean isSupportedFieldType(Class<?> returnType)
|
||||
{
|
||||
// todo - more types!!
|
||||
return (returnType.equals(String.class)
|
||||
|| returnType.equals(Integer.class)
|
||||
|| returnType.equals(int.class)
|
||||
|| returnType.equals(Boolean.class)
|
||||
|| returnType.equals(boolean.class)
|
||||
|| returnType.equals(BigDecimal.class));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.data;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Reflective information about a field in a QRecordEntity
|
||||
*******************************************************************************/
|
||||
public class QRecordEntityField
|
||||
{
|
||||
private final String fieldName;
|
||||
private final Method getter;
|
||||
private final Method setter;
|
||||
private final Class<?> type;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor.
|
||||
*******************************************************************************/
|
||||
public QRecordEntityField(String fieldName, Method getter, Method setter, Class<?> type)
|
||||
{
|
||||
this.fieldName = fieldName;
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for fieldName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getFieldName()
|
||||
{
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for getter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Method getGetter()
|
||||
{
|
||||
return getter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for setter
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Method getSetter()
|
||||
{
|
||||
return setter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Class<?> getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Object convertValueType(Serializable value)
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
if(value.getClass().equals(type))
|
||||
{
|
||||
return (value);
|
||||
}
|
||||
|
||||
if(type.equals(String.class))
|
||||
{
|
||||
return (ValueUtils.getValueAsString(value));
|
||||
}
|
||||
|
||||
if(type.equals(Integer.class) || type.equals(int.class))
|
||||
{
|
||||
return (ValueUtils.getValueAsInteger(value));
|
||||
}
|
||||
|
||||
if(type.equals(Boolean.class) || type.equals(boolean.class))
|
||||
{
|
||||
return (ValueUtils.getValueAsBoolean(value));
|
||||
}
|
||||
|
||||
if(type.equals(BigDecimal.class))
|
||||
{
|
||||
return (ValueUtils.getValueAsBigDecimal(value));
|
||||
}
|
||||
|
||||
throw (new QValueException("Unhandled value type [" + type + "] for field [" + fieldName + "]"));
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Enum to define the possible authentication types
|
||||
**
|
||||
*******************************************************************************/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public enum QAuthenticationType
|
||||
{
|
||||
AUTH_0("auth0"),
|
||||
FULLY_ANONYMOUS("fullyAnonymous"),
|
||||
MOCK("mock");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** enum constructor
|
||||
*******************************************************************************/
|
||||
QAuthenticationType(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for name
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.serialization.QBackendMetaDataDeserializer;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Meta-data to provide details of a backend (e.g., RDBMS instance, S3 buckets,
|
||||
** NoSQL table, etc) within a qqq instance
|
||||
**
|
||||
*******************************************************************************/
|
||||
@JsonDeserialize(using = QBackendMetaDataDeserializer.class)
|
||||
public class QBackendMetaData
|
||||
{
|
||||
private String name;
|
||||
private String backendType;
|
||||
|
||||
// todo - at some point, we may want to apply this to secret properties on subclasses?
|
||||
// @JsonFilter("secretsFilter")
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Default Constructor.
|
||||
*******************************************************************************/
|
||||
public QBackendMetaData()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter, returning generically, to help sub-class fluent flows
|
||||
*******************************************************************************/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends QBackendMetaData> T withName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for backendType
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getBackendType()
|
||||
{
|
||||
return backendType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for backendType
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setBackendType(String backendType)
|
||||
{
|
||||
this.backendType = backendType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for backendType
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setBackendType(Class<? extends QBackendModuleInterface> backendModuleClass)
|
||||
{
|
||||
try
|
||||
{
|
||||
QBackendModuleInterface qBackendModuleInterface = backendModuleClass.getConstructor().newInstance();
|
||||
this.backendType = qBackendModuleInterface.getBackendType();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("Error dynamically getting backend type (name) from class [" + backendModuleClass.getName() + "], e)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter, returning generically, to help sub-class fluent flows
|
||||
*******************************************************************************/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends QBackendMetaData> T withBackendType(String backendType)
|
||||
{
|
||||
this.backendType = backendType;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QBackendMetaData withBackendType(Class<? extends QBackendModuleInterface> backendModuleClass)
|
||||
{
|
||||
setBackendType(backendModuleClass);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Called by the QInstanceEnricher - to do backend-type-specific enrichments.
|
||||
** Original use case is: reading secrets into fields (e.g., passwords).
|
||||
*******************************************************************************/
|
||||
public void enrich()
|
||||
{
|
||||
////////////////////////
|
||||
// noop in base class //
|
||||
////////////////////////
|
||||
}
|
||||
}
|
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.kingsrook.qqq.backend.core.instances.QInstanceValidationKey;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Container for all meta-data in a running instance of a QQQ application.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QInstance
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Do not let the backend data be serialized - e.g., sent to a frontend user //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@JsonIgnore
|
||||
private Map<String, QBackendMetaData> backends = new HashMap<>();
|
||||
|
||||
private QAuthenticationMetaData authentication = null;
|
||||
|
||||
private Map<String, QTableMetaData> tables = new HashMap<>();
|
||||
private Map<String, QPossibleValueSource<?>> possibleValueSources = new HashMap<>();
|
||||
private Map<String, QProcessMetaData> processes = new HashMap<>();
|
||||
|
||||
// todo - lock down the object (no more changes allowed) after it's been validated?
|
||||
|
||||
@JsonIgnore
|
||||
private boolean hasBeenValidated = false;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get the backend for a given table name
|
||||
*******************************************************************************/
|
||||
public QBackendMetaData getBackendForTable(String tableName)
|
||||
{
|
||||
QTableMetaData table = tables.get(tableName);
|
||||
if(table == null)
|
||||
{
|
||||
throw (new IllegalArgumentException("No table with name [" + tableName + "] found in this instance."));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// validation should already let us know that this is valid, so no need to check/throw here //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
return (backends.get(table.getBackendName()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get the list of processes associated with a given table name
|
||||
*******************************************************************************/
|
||||
public List<QProcessMetaData> getProcessesForTable(String tableName)
|
||||
{
|
||||
List<QProcessMetaData> rs = new ArrayList<>();
|
||||
for(QProcessMetaData process : processes.values())
|
||||
{
|
||||
if(tableName.equals(process.getTableName()))
|
||||
{
|
||||
rs.add(process);
|
||||
}
|
||||
}
|
||||
return (rs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for hasBeenValidated
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setHasBeenValidated(QInstanceValidationKey key)
|
||||
{
|
||||
this.hasBeenValidated = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addBackend(QBackendMetaData backend)
|
||||
{
|
||||
addBackend(backend.getName(), backend);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addBackend(String name, QBackendMetaData backend)
|
||||
{
|
||||
if(this.backends.containsKey(name))
|
||||
{
|
||||
throw (new IllegalArgumentException("Attempted to add a second backend with name: " + name));
|
||||
}
|
||||
this.backends.put(name, backend);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QBackendMetaData getBackend(String name)
|
||||
{
|
||||
return (this.backends.get(name));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addTable(QTableMetaData table)
|
||||
{
|
||||
addTable(table.getName(), table);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addTable(String name, QTableMetaData table)
|
||||
{
|
||||
if(this.tables.containsKey(name))
|
||||
{
|
||||
throw (new IllegalArgumentException("Attempted to add a second table with name: " + name));
|
||||
}
|
||||
this.tables.put(name, table);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QTableMetaData getTable(String name)
|
||||
{
|
||||
return (this.tables.get(name));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addPossibleValueSource(QPossibleValueSource<?> possibleValueSource)
|
||||
{
|
||||
this.addPossibleValueSource(possibleValueSource.getName(), possibleValueSource);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addPossibleValueSource(String name, QPossibleValueSource possibleValueSource)
|
||||
{
|
||||
if(this.possibleValueSources.containsKey(name))
|
||||
{
|
||||
throw (new IllegalArgumentException("Attempted to add a second possibleValueSource with name: " + name));
|
||||
}
|
||||
this.possibleValueSources.put(name, possibleValueSource);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QPossibleValueSource getPossibleValueSource(String name)
|
||||
{
|
||||
return (this.possibleValueSources.get(name));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QStepMetaData getProcessStep(String processName, String functionName)
|
||||
{
|
||||
QProcessMetaData qProcessMetaData = this.processes.get(processName);
|
||||
if(qProcessMetaData == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (qProcessMetaData.getStep(functionName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addProcess(QProcessMetaData process)
|
||||
{
|
||||
this.addProcess(process.getName(), process);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addProcess(String name, QProcessMetaData process)
|
||||
{
|
||||
if(this.processes.containsKey(name))
|
||||
{
|
||||
throw (new IllegalArgumentException("Attempted to add a second process with name: " + name));
|
||||
}
|
||||
this.processes.put(name, process);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QProcessMetaData getProcess(String name)
|
||||
{
|
||||
return (this.processes.get(name));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for backends
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, QBackendMetaData> getBackends()
|
||||
{
|
||||
return backends;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for backends
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setBackends(Map<String, QBackendMetaData> backends)
|
||||
{
|
||||
this.backends = backends;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tables
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, QTableMetaData> getTables()
|
||||
{
|
||||
return tables;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tables
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTables(Map<String, QTableMetaData> tables)
|
||||
{
|
||||
this.tables = tables;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for possibleValueSources
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, QPossibleValueSource<?>> getPossibleValueSources()
|
||||
{
|
||||
return possibleValueSources;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for possibleValueSources
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setPossibleValueSources(Map<String, QPossibleValueSource<?>> possibleValueSources)
|
||||
{
|
||||
this.possibleValueSources = possibleValueSources;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processes
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, QProcessMetaData> getProcesses()
|
||||
{
|
||||
return processes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processes
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setProcesses(Map<String, QProcessMetaData> processes)
|
||||
{
|
||||
this.processes = processes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for hasBeenValidated
|
||||
**
|
||||
*******************************************************************************/
|
||||
public boolean getHasBeenValidated()
|
||||
{
|
||||
return hasBeenValidated;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for authentication
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QAuthenticationMetaData getAuthentication()
|
||||
{
|
||||
return authentication;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for authentication
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setAuthentication(QAuthenticationMetaData authentication)
|
||||
{
|
||||
this.authentication = authentication;
|
||||
}
|
||||
}
|
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata.code;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Pointer to code to be ran by the qqq framework, e.g., for custom behavior -
|
||||
** maybe process steps, maybe customization to a table, etc.
|
||||
*******************************************************************************/
|
||||
public class QCodeReference
|
||||
{
|
||||
private String name;
|
||||
private QCodeType codeType;
|
||||
private QCodeUsage codeUsage;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Default empty constructor
|
||||
*******************************************************************************/
|
||||
public QCodeReference()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor that takes all args
|
||||
*******************************************************************************/
|
||||
public QCodeReference(String name, QCodeType codeType, QCodeUsage codeUsage)
|
||||
{
|
||||
this.name = name;
|
||||
this.codeType = codeType;
|
||||
this.codeUsage = codeUsage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor that just takes a java class, and infers the other fields.
|
||||
*******************************************************************************/
|
||||
public QCodeReference(Class<?> javaClass)
|
||||
{
|
||||
this.name = javaClass.getName();
|
||||
this.codeType = QCodeType.JAVA;
|
||||
|
||||
if(BackendStep.class.isAssignableFrom(javaClass))
|
||||
{
|
||||
this.codeUsage = QCodeUsage.BACKEND_STEP;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new IllegalStateException("Unable to infer code usage type for class: " + javaClass.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor that just takes a java class and code usage.
|
||||
*******************************************************************************/
|
||||
public QCodeReference(Class<?> javaClass, QCodeUsage codeUsage)
|
||||
{
|
||||
this.name = javaClass.getName();
|
||||
this.codeType = QCodeType.JAVA;
|
||||
this.codeUsage = codeUsage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for name
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for name
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for name
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QCodeReference withName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for codeType
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QCodeType getCodeType()
|
||||
{
|
||||
return codeType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for codeType
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCodeType(QCodeType codeType)
|
||||
{
|
||||
this.codeType = codeType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for codeType
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QCodeReference withCodeType(QCodeType codeType)
|
||||
{
|
||||
this.codeType = codeType;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for codeUsage
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QCodeUsage getCodeUsage()
|
||||
{
|
||||
return codeUsage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for codeUsage
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCodeUsage(QCodeUsage codeUsage)
|
||||
{
|
||||
this.codeUsage = codeUsage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for codeUsage
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QCodeReference withCodeUsage(QCodeUsage codeUsage)
|
||||
{
|
||||
this.codeUsage = codeUsage;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata.code;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Possible types for Q-Code entities
|
||||
**
|
||||
*******************************************************************************/
|
||||
public enum QCodeType
|
||||
{
|
||||
JAVA
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata.code;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Possible usages for Q-Code entities
|
||||
**
|
||||
*******************************************************************************/
|
||||
public enum QCodeUsage
|
||||
{
|
||||
BACKEND_STEP, // a backend-step in a process
|
||||
CUSTOMIZER // a function to customize part of a QQQ table's behavior
|
||||
}
|
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata.fields;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import com.github.hervian.reflection.Fun;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Meta-data to represent a single field in a table.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QFieldMetaData
|
||||
{
|
||||
private String name;
|
||||
private String label;
|
||||
private String backendName;
|
||||
private QFieldType type;
|
||||
private boolean isRequired = false;
|
||||
private boolean isEditable = true;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// if we need "only edit on insert" or "only edit on update" in the future, //
|
||||
// propose doing that in a secondary field, e.g., "onlyEditableOn=insert|update" //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private Serializable defaultValue;
|
||||
private String possibleValueSourceName;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldMetaData()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldMetaData(String name, QFieldType type)
|
||||
{
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Initialize a fieldMetaData from a reference to a getter on an entity.
|
||||
** e.g., new QFieldMetaData(Order::getOrderNo).
|
||||
*******************************************************************************/
|
||||
public <T> QFieldMetaData(Fun.With1ParamAndVoid<T> getterRef) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
Method getter = Fun.toMethod(getterRef);
|
||||
this.name = QRecordEntity.getFieldNameFromGetter(getter);
|
||||
this.type = QFieldType.fromClass(getter.getReturnType());
|
||||
}
|
||||
catch(QException qe)
|
||||
{
|
||||
throw (qe);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QException("Error constructing field from getterRef: " + getterRef, e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldMetaData withName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for type
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setType(QFieldType type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldMetaData withType(QFieldType type)
|
||||
{
|
||||
this.type = type;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setLabel(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldMetaData withLabel(String label)
|
||||
{
|
||||
this.label = label;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for backendName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getBackendName()
|
||||
{
|
||||
return backendName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for backendName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setBackendName(String backendName)
|
||||
{
|
||||
this.backendName = backendName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldMetaData withBackendName(String backendName)
|
||||
{
|
||||
this.backendName = backendName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getPossibleValueSourceName()
|
||||
{
|
||||
return possibleValueSourceName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setPossibleValueSourceName(String possibleValueSourceName)
|
||||
{
|
||||
this.possibleValueSourceName = possibleValueSourceName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldMetaData withPossibleValueSourceName(String possibleValueSourceName)
|
||||
{
|
||||
this.possibleValueSourceName = possibleValueSourceName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for defaultValue
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getDefaultValue()
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for defaultValue
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setDefaultValue(Serializable defaultValue)
|
||||
{
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldMetaData withDefaultValue(Serializable defaultValue)
|
||||
{
|
||||
this.defaultValue = defaultValue;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for isRequired
|
||||
**
|
||||
*******************************************************************************/
|
||||
public boolean getIsRequired()
|
||||
{
|
||||
return isRequired;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for isRequired
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setIsRequired(boolean isRequired)
|
||||
{
|
||||
this.isRequired = isRequired;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldMetaData withIsRequired(boolean isRequired)
|
||||
{
|
||||
this.isRequired = isRequired;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for isEditable
|
||||
**
|
||||
*******************************************************************************/
|
||||
public boolean getIsEditable()
|
||||
{
|
||||
return isEditable;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for isEditable
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setIsEditable(boolean isEditable)
|
||||
{
|
||||
this.isEditable = isEditable;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldMetaData withIsEditable(boolean isEditable)
|
||||
{
|
||||
this.isEditable = isEditable;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata.fields;
|
||||
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Possible data types for Q-fields.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public enum QFieldType
|
||||
{
|
||||
STRING,
|
||||
INTEGER,
|
||||
DECIMAL,
|
||||
DATE,
|
||||
// TIME,
|
||||
DATE_TIME,
|
||||
TEXT,
|
||||
HTML,
|
||||
PASSWORD,
|
||||
BLOB;
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// keep these values in sync with QFieldType.ts in qqq-frontend-core //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get a field type enum constant for a java class.
|
||||
*******************************************************************************/
|
||||
public static QFieldType fromClass(Class<?> c) throws QException
|
||||
{
|
||||
if(c.equals(String.class))
|
||||
{
|
||||
return (STRING);
|
||||
}
|
||||
if(c.equals(Integer.class) || c.equals(int.class))
|
||||
{
|
||||
return (INTEGER);
|
||||
}
|
||||
if(c.equals(BigDecimal.class))
|
||||
{
|
||||
return (DECIMAL);
|
||||
}
|
||||
|
||||
throw (new QException("Unrecognized class [" + c + "]"));
|
||||
}
|
||||
}
|
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata.frontend;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Version of QFieldMetaData that's meant for transmitting to a frontend.
|
||||
* e.g., it excludes backend-only details.
|
||||
*
|
||||
*******************************************************************************/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public class QFrontendFieldMetaData
|
||||
{
|
||||
private String name;
|
||||
private String label;
|
||||
private QFieldType type;
|
||||
private boolean isRequired;
|
||||
private boolean isEditable;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// do not add setters. take values from the source-object in the constructor!! //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
*******************************************************************************/
|
||||
public QFrontendFieldMetaData(QFieldMetaData fieldMetaData)
|
||||
{
|
||||
this.name = fieldMetaData.getName();
|
||||
this.label = fieldMetaData.getLabel();
|
||||
this.type = fieldMetaData.getType();
|
||||
this.isRequired = fieldMetaData.getIsRequired();
|
||||
this.isEditable = fieldMetaData.getIsEditable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for name
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFieldType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for isRequired
|
||||
**
|
||||
*******************************************************************************/
|
||||
public boolean getIsRequired()
|
||||
{
|
||||
return isRequired;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for isEditable
|
||||
**
|
||||
*******************************************************************************/
|
||||
public boolean getIsEditable()
|
||||
{
|
||||
return isEditable;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata.frontend;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Version of QProcessMetaData that's meant for transmitting to a frontend.
|
||||
* e.g., it excludes backend-only details.
|
||||
*
|
||||
*******************************************************************************/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public class QFrontendProcessMetaData
|
||||
{
|
||||
private String name;
|
||||
private String label;
|
||||
private String tableName;
|
||||
private boolean isHidden;
|
||||
|
||||
private List<QFrontendStepMetaData> frontendSteps;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// do not add setters. take values from the source-object in the constructor!! //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFrontendProcessMetaData(QProcessMetaData processMetaData, boolean includeSteps)
|
||||
{
|
||||
this.name = processMetaData.getName();
|
||||
this.label = processMetaData.getLabel();
|
||||
this.tableName = processMetaData.getTableName();
|
||||
this.isHidden = processMetaData.getIsHidden();
|
||||
|
||||
if(includeSteps)
|
||||
{
|
||||
if(CollectionUtils.nullSafeHasContents(processMetaData.getStepList()))
|
||||
{
|
||||
this.frontendSteps = processMetaData.getStepList().stream()
|
||||
.filter(QFrontendStepMetaData.class::isInstance)
|
||||
.map(QFrontendStepMetaData.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
else
|
||||
{
|
||||
frontendSteps = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for name
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for primaryKeyField
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for frontendSteps
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QFrontendStepMetaData> getFrontendSteps()
|
||||
{
|
||||
return frontendSteps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for frontendSteps
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFrontendSteps(List<QFrontendStepMetaData> frontendSteps)
|
||||
{
|
||||
this.frontendSteps = frontendSteps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for isHidden
|
||||
**
|
||||
*******************************************************************************/
|
||||
public boolean getIsHidden()
|
||||
{
|
||||
return isHidden;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for isHidden
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setIsHidden(boolean isHidden)
|
||||
{
|
||||
this.isHidden = isHidden;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata.frontend;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Version of QTableMetaData that's meant for transmitting to a frontend.
|
||||
* e.g., it excludes backend-only details.
|
||||
*
|
||||
*******************************************************************************/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public class QFrontendTableMetaData
|
||||
{
|
||||
private String name;
|
||||
private String label;
|
||||
private boolean isHidden;
|
||||
private String primaryKeyField;
|
||||
|
||||
private Map<String, QFrontendFieldMetaData> fields;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// do not add setters. take values from the source-object in the constructor!! //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFrontendTableMetaData(QTableMetaData tableMetaData, boolean includeFields)
|
||||
{
|
||||
this.name = tableMetaData.getName();
|
||||
this.label = tableMetaData.getLabel();
|
||||
this.isHidden = tableMetaData.getIsHidden();
|
||||
|
||||
if(includeFields)
|
||||
{
|
||||
this.primaryKeyField = tableMetaData.getPrimaryKeyField();
|
||||
this.fields = new HashMap<>();
|
||||
for(Map.Entry<String, QFieldMetaData> entry : tableMetaData.getFields().entrySet())
|
||||
{
|
||||
this.fields.put(entry.getKey(), new QFrontendFieldMetaData(entry.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for name
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for primaryKeyField
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getPrimaryKeyField()
|
||||
{
|
||||
return primaryKeyField;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for fields
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, QFrontendFieldMetaData> getFields()
|
||||
{
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for isHidden
|
||||
**
|
||||
*******************************************************************************/
|
||||
public boolean getIsHidden()
|
||||
{
|
||||
return isHidden;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for isHidden
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setIsHidden(boolean isHidden)
|
||||
{
|
||||
this.isHidden = isHidden;
|
||||
}
|
||||
}
|
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. 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.backend.core.model.metadata.possiblevalues;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Meta-data to represent a single field in a table.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QPossibleValueSource<T>
|
||||
{
|
||||
private String name;
|
||||
private QPossibleValueSourceType type;
|
||||
|
||||
// should these be in sub-types??
|
||||
private List<T> enumValues;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QPossibleValueSource()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QPossibleValueSource<T> withName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QPossibleValueSourceType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setType(QPossibleValueSourceType type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QPossibleValueSource<T> withType(QPossibleValueSourceType type)
|
||||
{
|
||||
this.type = type;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for enumValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<T> getEnumValues()
|
||||
{
|
||||
return enumValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for enumValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setEnumValues(List<T> enumValues)
|
||||
{
|
||||
this.enumValues = enumValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for enumValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QPossibleValueSource<T> withEnumValues(List<T> enumValues)
|
||||
{
|
||||
this.enumValues = enumValues;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent adder for enumValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QPossibleValueSource<T> addEnumValue(T enumValue)
|
||||
{
|
||||
if(this.enumValues == null)
|
||||
{
|
||||
this.enumValues = new ArrayList<>();
|
||||
}
|
||||
this.enumValues.add(enumValue);
|
||||
return this;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user