Merged feature/filesystem-list-single-file-optimization into integration

This commit is contained in:
2025-04-08 13:45:21 -05:00
3 changed files with 78 additions and 13 deletions

View File

@ -59,9 +59,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.variants.BackendVariantSett
import com.kingsrook.qqq.backend.core.model.metadata.variants.BackendVariantsUtil; import com.kingsrook.qqq.backend.core.model.metadata.variants.BackendVariantsUtil;
import com.kingsrook.qqq.backend.core.model.statusmessages.SystemErrorStatusMessage; import com.kingsrook.qqq.backend.core.model.statusmessages.SystemErrorStatusMessage;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.utils.BackendQueryFilterUtils; import com.kingsrook.qqq.backend.core.modules.backend.implementations.utils.BackendQueryFilterUtils;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils; import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
import com.kingsrook.qqq.backend.core.utils.ObjectUtils; import com.kingsrook.qqq.backend.core.utils.ObjectUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils; import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeSupplier; import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeSupplier;
import com.kingsrook.qqq.backend.module.filesystem.base.FilesystemRecordBackendDetailFields; import com.kingsrook.qqq.backend.module.filesystem.base.FilesystemRecordBackendDetailFields;
import com.kingsrook.qqq.backend.module.filesystem.base.model.metadata.AbstractFilesystemBackendMetaData; import com.kingsrook.qqq.backend.module.filesystem.base.model.metadata.AbstractFilesystemBackendMetaData;
@ -297,6 +299,21 @@ public abstract class AbstractBaseFilesystemAction<FILE>
QueryOutput queryOutput = new QueryOutput(queryInput); QueryOutput queryOutput = new QueryOutput(queryInput);
String requestedPath = null; String requestedPath = null;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// if this is a query for a single file name, then get that file name in the requestedPath param for the listFiles call //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(queryInput.getFilter() != null)
{
for(QFilterCriteria criteria : CollectionUtils.nonNullList(queryInput.getFilter().getCriteria()))
{
if(criteria.getFieldName().equals(tableDetails.getFileNameFieldName()) && criteria.getOperator().equals(QCriteriaOperator.EQUALS))
{
requestedPath = ValueUtils.getValueAsString(criteria.getValues().get(0));
}
}
}
List<FILE> files = listFiles(table, queryInput.getBackend(), requestedPath); List<FILE> files = listFiles(table, queryInput.getBackend(), requestedPath);
switch(tableDetails.getCardinality()) switch(tableDetails.getCardinality())

View File

@ -325,7 +325,37 @@ public class AbstractSFTPAction extends AbstractBaseFilesystemAction<SFTPDirEntr
fullPath = "." + fullPath; fullPath = "." + fullPath;
} }
for(SftpClient.DirEntry dirEntry : sftpClient.readDir(fullPath)) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// in case we were asked to list a single file name, make sure we don't put a slash on the end (which wouldn't be found) //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(fullPath.endsWith("/"))
{
fullPath = fullPath.substring(0, fullPath.length() - 1);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// make a 'stat' call, to find out if the path is found, and if it is, if it describes a single file, or a directory //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SftpClient.Attributes stat = sftpClient.stat(fullPath);
if(stat == null)
{
return (rs);
}
else if(stat.isRegularFile())
{
///////////////////////////////////////////////////////////////////////////
// split up the fullPath into its directory prefix, and file name suffix //
///////////////////////////////////////////////////////////////////////////
int lastSlashIndex = fullPath.lastIndexOf("/");
String directory = lastSlashIndex == -1 ? "./" : fullPath.substring(0, lastSlashIndex);
String fileBaseName = lastSlashIndex == -1 ? fullPath : fullPath.substring(lastSlashIndex + 1);
SftpClient.DirEntry dirEntry = new SftpClient.DirEntry(fileBaseName, fullPath, stat);
rs.add(new SFTPDirEntryWithPath(directory, dirEntry));
}
else if(stat.isDirectory())
{
for(SftpClient.DirEntry dirEntry : sftpClient.readEntries(fullPath))
{ {
if(".".equals(dirEntry.getFilename()) || "..".equals(dirEntry.getFilename())) if(".".equals(dirEntry.getFilename()) || "..".equals(dirEntry.getFilename()))
{ {
@ -340,6 +370,7 @@ public class AbstractSFTPAction extends AbstractBaseFilesystemAction<SFTPDirEntr
rs.add(new SFTPDirEntryWithPath(fullPath, dirEntry)); rs.add(new SFTPDirEntryWithPath(fullPath, dirEntry));
} }
}
return (rs); return (rs);
} }

View File

@ -62,6 +62,23 @@ public class S3QueryActionTest extends BaseS3Test
/*******************************************************************************
**
*******************************************************************************/
@Test
public void testGet() throws QException
{
QueryInput queryInput = new QueryInput(TestUtils.TABLE_NAME_BLOB_S3)
.withFilter(new QQueryFilter(new QFilterCriteria("fileName", QCriteriaOperator.EQUALS, "BLOB-1.txt")));
S3QueryAction s3QueryAction = new S3QueryAction();
s3QueryAction.setS3Utils(getS3Utils());
QueryOutput queryOutput = s3QueryAction.execute(queryInput);
Assertions.assertEquals(1, queryOutput.getRecords().size(), "Expected # of rows from query");
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/