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:
@ -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>
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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})`,
|
||||
|
||||
Reference in New Issue
Block a user