Fix filter transform with logic operators (#5269)

Various fixes

- Remote objects are read-only for now, we already hide and block most
of the write actions but the button that allows you to add a new record
in an empty collection was still visible.
- CreatedAt is not mandatory on remote objects (at least for now) so it
was breaking the show page, it now checks if createdAt exists and is not
null before trying to display the human readable format `Added x days
ago`
- The filters are overwritten in query-runner-args.factory.ts to handle
NUMBER field type, this was only working with filters like
```
      {
        "id": {
          "in": [
            1
          ]
        }
```
but not with more depth such as 
```
    "and": [
      {},
      {
        "id": {
          "in": [
            1
          ]
        }
      }
    ]
 ```
- Fixes CREATE FOREIGN TABLE raw query which was missing ",".
This commit is contained in:
Weiko 2024-05-03 14:52:20 +02:00 committed by GitHub
parent 30ffe0160e
commit 50421863d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 68 additions and 46 deletions

View File

@ -81,6 +81,8 @@ export const RecordTableWithWrappers = ({
const objectLabel = foundObjectMetadataItem?.labelSingular;
const isRemote = foundObjectMetadataItem?.isRemote ?? false;
return (
<EntityDeleteContext.Provider value={deleteOneRecord}>
<ScrollWrapper>
@ -113,25 +115,27 @@ export const RecordTableWithWrappers = ({
recordTableId={recordTableId}
tableBodyRef={tableBodyRef}
/>
{!isRecordTableInitialLoading && numberOfTableRows === 0 && (
<AnimatedPlaceholderEmptyContainer>
<AnimatedPlaceholder type="noRecord" />
<AnimatedPlaceholderEmptyTextContainer>
<AnimatedPlaceholderEmptyTitle>
Add your first {objectLabel}
</AnimatedPlaceholderEmptyTitle>
<AnimatedPlaceholderEmptySubTitle>
Use our API or add your first {objectLabel} manually
</AnimatedPlaceholderEmptySubTitle>
</AnimatedPlaceholderEmptyTextContainer>
<Button
Icon={IconPlus}
title={`Add a ${objectLabel}`}
variant={'secondary'}
onClick={createRecord}
/>
</AnimatedPlaceholderEmptyContainer>
)}
{!isRecordTableInitialLoading &&
numberOfTableRows === 0 &&
!isRemote && (
<AnimatedPlaceholderEmptyContainer>
<AnimatedPlaceholder type="noRecord" />
<AnimatedPlaceholderEmptyTextContainer>
<AnimatedPlaceholderEmptyTitle>
Add your first {objectLabel}
</AnimatedPlaceholderEmptyTitle>
<AnimatedPlaceholderEmptySubTitle>
Use our API or add your first {objectLabel} manually
</AnimatedPlaceholderEmptySubTitle>
</AnimatedPlaceholderEmptyTextContainer>
<Button
Icon={IconPlus}
title={`Add a ${objectLabel}`}
variant={'secondary'}
onClick={createRecord}
/>
</AnimatedPlaceholderEmptyContainer>
)}
</StyledTableContainer>
</StyledTableWithHeader>
</RecordUpdateContext.Provider>

View File

@ -112,7 +112,11 @@ export const ShowPageSummaryCard = ({
</StyledAvatarWrapper>
<StyledInfoContainer>
<StyledTitle>{title}</StyledTitle>
<StyledDate id={dateElementId}>Added {beautifiedCreatedAt}</StyledDate>
{beautifiedCreatedAt && (
<StyledDate id={dateElementId}>
Added {beautifiedCreatedAt}
</StyledDate>
)}
<StyledTooltip
anchorSelect={`#${dateElementId}`}
content={exactCreatedAt}

View File

@ -131,30 +131,46 @@ export class QueryRunnerArgsFactory {
return;
}
const createArgPromiseByArgKey = Object.entries(filter).map(
([key, value]) => {
const fieldMetadata = fieldMetadataMap.get(key);
if (!fieldMetadata) {
return [key, value];
const overrideFilter = (filterObject: RecordFilter) => {
return Object.entries(filterObject).reduce((acc, [key, value]) => {
if (key === 'and' || key === 'or') {
acc[key] = value.map((nestedFilter: RecordFilter) =>
overrideFilter(nestedFilter),
);
} else if (key === 'not') {
acc[key] = overrideFilter(value);
} else {
acc[key] = this.transformValueByType(key, value, fieldMetadataMap);
}
const createFilterByKey = Object.entries(value).map(
([filterKey, filterValue]) => {
switch (fieldMetadata.type) {
case FieldMetadataType.NUMBER:
return [filterKey, Number(filterValue)];
default:
return [filterKey, filterValue];
}
},
return acc;
}, {});
};
return overrideFilter(filter);
}
private transformValueByType(
key: string,
value: any,
fieldMetadataMap: Map<string, FieldMetadataInterface>,
) {
const fieldMetadata = fieldMetadataMap.get(key);
if (!fieldMetadata) {
return value;
}
switch (fieldMetadata.type) {
case 'NUMBER':
return Object.fromEntries(
Object.entries(value).map(([filterKey, filterValue]) => [
filterKey,
Number(filterValue),
]),
);
return [key, Object.fromEntries(createFilterByKey)];
},
);
return Object.fromEntries(createArgPromiseByArgKey);
default:
return value;
}
}
private async overrideValueByFieldMetadata(

View File

@ -495,11 +495,9 @@ export class WorkspaceMigrationRunnerService {
)
.join(', ');
let serverOptions = '';
Object.entries(foreignTable.referencedTable).forEach(([key, value]) => {
serverOptions += ` ${key} '${value}'`;
});
const serverOptions = Object.entries(foreignTable.referencedTable)
.map(([key, value]) => `${key} '${value}'`)
.join(', ');
await queryRunner.query(
`CREATE FOREIGN TABLE ${schemaName}."${name}" (${foreignTableColumns}) SERVER "${foreignTable.foreignDataWrapperId}" OPTIONS (${serverOptions})`,