Files
colanode/apps/desktop/src/shared/lib/databases.ts
2024-11-29 22:27:23 +01:00

1430 lines
30 KiB
TypeScript

import {
FieldType,
FieldAttributes,
ViewFieldFilterAttributes,
ViewFilterAttributes,
ViewFieldAttributes,
RecordNode,
FieldValue,
MultiSelectFieldAttributes,
SelectFieldAttributes,
ViewType,
generateNodeIndex,
compareString,
isStringArray,
} from '@colanode/core';
export const getDefaultFieldWidth = (type: FieldType): number => {
if (!type) return 0;
switch (type.toLowerCase()) {
case 'name':
return 200;
case 'autonumber':
return 150;
case 'boolean':
return 100;
case 'button':
return 100;
case 'collaborator':
return 200;
case 'created_at':
return 200;
case 'created_by':
return 200;
case 'date':
return 200;
case 'email':
return 200;
case 'file':
return 200;
case 'formula':
return 200;
case 'multi_select':
return 200;
case 'number':
return 150;
case 'phone':
return 200;
case 'relation':
return 200;
case 'rollup':
return 200;
case 'select':
return 200;
case 'text':
return 200;
case 'updated_at':
return 200;
case 'updated_by':
return 200;
case 'url':
return 200;
default:
return 200;
}
};
export const getDefaultNameWidth = (): number => {
return 300;
};
export const getDefaultViewFieldDisplay = (viewType: ViewType): boolean => {
return viewType === 'table';
};
interface SelectOptionColor {
label: string;
value: string;
class: string;
lightClass: string;
}
export const selectOptionColors: SelectOptionColor[] = [
{
label: 'Gray',
value: 'gray',
class: 'bg-gray-200',
lightClass: 'bg-gray-50',
},
{
label: 'Orange',
value: 'orange',
class: 'bg-orange-200',
lightClass: 'bg-orange-50',
},
{
label: 'Yellow',
value: 'yellow',
class: 'bg-yellow-200',
lightClass: 'bg-yellow-50',
},
{
label: 'Green',
value: 'green',
class: 'bg-green-200',
lightClass: 'bg-green-50',
},
{
label: 'Blue',
value: 'blue',
class: 'bg-blue-200',
lightClass: 'bg-blue-50',
},
{
label: 'Purple',
value: 'purple',
class: 'bg-purple-200',
lightClass: 'bg-purple-50',
},
{
label: 'Pink',
value: 'pink',
class: 'bg-pink-200',
lightClass: 'bg-pink-50',
},
{
label: 'Red',
value: 'red',
class: 'bg-red-200',
lightClass: 'bg-red-50',
},
];
export const getSelectOptionColorClass = (color: string): string => {
return selectOptionColors.find((c) => c.value === color)?.class || '';
};
export const getSelectOptionLightColorClass = (color: string): string => {
return selectOptionColors.find((c) => c.value === color)?.lightClass || '';
};
export const getRandomSelectOptionColor = (): string => {
const randomIndex = Math.floor(Math.random() * selectOptionColors.length);
const randomColor = selectOptionColors[randomIndex] ?? selectOptionColors[0]!;
return randomColor.value;
};
export interface FieldFilterOperator {
label: string;
value: string;
}
export const booleanFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is True',
value: 'is_true',
},
{
label: 'Is False',
value: 'is_false',
},
];
export const collaboratorFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is Me',
value: 'is_me',
},
{
label: 'Is Not Me',
value: 'is_not_me',
},
{
label: 'Is In',
value: 'is_in',
},
{
label: 'Is Not In',
value: 'is_not_in',
},
{
label: 'Is Empty',
value: 'is_empty',
},
{
label: 'Is Not Empty',
value: 'is_not_empty',
},
];
export const createdAtFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is Equal To',
value: 'is_equal_to',
},
{
label: 'Is Not Equal To',
value: 'is_not_equal_to',
},
{
label: 'Is on or after',
value: 'is_on_or_after',
},
{
label: 'Is on or before',
value: 'is_on_or_before',
},
{
label: 'Is After',
value: 'is_after',
},
{
label: 'Is Before',
value: 'is_before',
},
];
export const createdByFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is Me',
value: 'is_me',
},
{
label: 'Is Not Me',
value: 'is_not_me',
},
{
label: 'Is In',
value: 'is_in',
},
{
label: 'Is Not In',
value: 'is_not_in',
},
];
export const dateFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is Equal To',
value: 'is_equal_to',
},
{
label: 'Is Not Equal To',
value: 'is_not_equal_to',
},
{
label: 'Is on or after',
value: 'is_on_or_after',
},
{
label: 'Is on or before',
value: 'is_on_or_before',
},
{
label: 'Is After',
value: 'is_after',
},
{
label: 'Is Before',
value: 'is_before',
},
{
label: 'Is Empty',
value: 'is_empty',
},
{
label: 'Is Not Empty',
value: 'is_not_empty',
},
];
export const emailFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is Equal To',
value: 'is_equal_to',
},
{
label: 'Is Not Equal To',
value: 'is_not_equal_to',
},
{
label: 'Contains',
value: 'contains',
},
{
label: 'Does Not Contain',
value: 'does_not_contain',
},
{
label: 'Is Empty',
value: 'is_empty',
},
{
label: 'Is Not Empty',
value: 'is_not_empty',
},
];
export const fileFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is In',
value: 'is_in',
},
{
label: 'Is Not In',
value: 'is_not_in',
},
{
label: 'Is Empty',
value: 'is_empty',
},
{
label: 'Is Not Empty',
value: 'is_not_empty',
},
];
export const multiSelectFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is In',
value: 'is_in',
},
{
label: 'Is Not In',
value: 'is_not_in',
},
{
label: 'Is Empty',
value: 'is_empty',
},
{
label: 'Is Not Empty',
value: 'is_not_empty',
},
];
export const numberFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is Equal To',
value: 'is_equal_to',
},
{
label: 'Is Not Equal To',
value: 'is_not_equal_to',
},
{
label: 'Is Greater Than',
value: 'is_greater_than',
},
{
label: 'Is Less Than',
value: 'is_less_than',
},
{
label: 'Is Greater Than Or Equal To',
value: 'is_greater_than_or_equal_to',
},
{
label: 'Is Less Than Or Equal To',
value: 'is_less_than_or_equal_to',
},
{
label: 'Is Empty',
value: 'is_empty',
},
{
label: 'Is Not Empty',
value: 'is_not_empty',
},
];
export const phoneFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is Empty',
value: 'is_empty',
},
{
label: 'Is Not Empty',
value: 'is_not_empty',
},
{
label: 'Is Equal To',
value: 'is_equal_to',
},
{
label: 'Is Not Equal To',
value: 'is_not_equal_to',
},
{
label: 'Contains',
value: 'contains',
},
{
label: 'Does Not Contain',
value: 'does_not_contain',
},
];
export const selectFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is In',
value: 'is_in',
},
{
label: 'Is Not In',
value: 'is_not_in',
},
{
label: 'Is Empty',
value: 'is_empty',
},
{
label: 'Is Not Empty',
value: 'is_not_empty',
},
];
export const textFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Contains',
value: 'contains',
},
{
label: 'Does Not Contain',
value: 'does_not_contain',
},
{
label: 'Is Equal To',
value: 'is_equal_to',
},
{
label: 'Is Not Equal To',
value: 'is_not_equal_to',
},
{
label: 'Is Empty',
value: 'is_empty',
},
{
label: 'Is Not Empty',
value: 'is_not_empty',
},
];
export const urlFieldFilterOperators: FieldFilterOperator[] = [
{
label: 'Is Equal To',
value: 'is_equal_to',
},
{
label: 'Is Not Equal To',
value: 'is_not_equal_to',
},
{
label: 'Contains',
value: 'contains',
},
{
label: 'Does Not Contain',
value: 'does_not_contain',
},
{
label: 'Is Empty',
value: 'is_empty',
},
{
label: 'Is Not Empty',
value: 'is_not_empty',
},
];
export const getFieldFilterOperators = (
type: FieldType
): FieldFilterOperator[] => {
if (!type) return [];
switch (type) {
case 'boolean':
return booleanFieldFilterOperators;
case 'collaborator':
return collaboratorFieldFilterOperators;
case 'createdAt':
return createdAtFieldFilterOperators;
case 'createdBy':
return createdByFieldFilterOperators;
case 'date':
return dateFieldFilterOperators;
case 'email':
return emailFieldFilterOperators;
case 'file':
return fileFieldFilterOperators;
case 'multiSelect':
return multiSelectFieldFilterOperators;
case 'number':
return numberFieldFilterOperators;
case 'phone':
return phoneFieldFilterOperators;
case 'select':
return selectFieldFilterOperators;
case 'text':
return textFieldFilterOperators;
case 'url':
return urlFieldFilterOperators;
default:
return [];
}
};
export const filterRecords = (
records: RecordNode[],
filter: ViewFilterAttributes,
field: FieldAttributes,
currentUserId: string
): RecordNode[] => {
return records.filter((record) =>
recordMatchesFilter(record, filter, field, currentUserId)
);
};
const recordMatchesFilter = (
record: RecordNode,
filter: ViewFilterAttributes,
field: FieldAttributes,
currentUserId: string
) => {
if (filter.type === 'group') {
return false;
}
switch (field.type) {
case 'boolean':
return recordMatchesBooleanFilter(record, filter, field);
case 'collaborator':
return recordMatchesCollaboratorFilter(record, filter, field);
case 'createdAt':
return recordMatchesCreatedAtFilter(record, filter);
case 'createdBy':
return recordMatchesCreatedByFilter(record, filter, currentUserId);
case 'date':
return recordMatchesDateFilter(record, filter, field);
case 'email':
return recordMatchesEmailFilter(record, filter, field);
case 'file':
return recordMatchesFileFilter(record, filter, field);
case 'multiSelect':
return recordMatchesMultiSelectFilter(record, filter, field);
case 'number':
return recordMatchesNumberFilter(record, filter, field);
case 'phone':
return recordMatchesPhoneFilter(record, filter, field);
case 'select':
return recordMatchesSelectFilter(record, filter, field);
case 'text':
return recordMatchesTextFilter(record, filter, field);
case 'url':
return recordMatchesUrlFilter(record, filter, field);
default:
return false;
}
};
const recordMatchesBooleanFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes,
field: FieldAttributes
) => {
const fieldValue = record.attributes.fields[field.id];
if (filter.operator === 'is_true') {
return (
fieldValue && fieldValue.type === 'boolean' && fieldValue.value === true
);
}
if (filter.operator === 'is_false') {
return (
!fieldValue ||
(fieldValue &&
fieldValue.type === 'boolean' &&
fieldValue.value === false)
);
}
return false;
};
const recordMatchesCollaboratorFilter = (
_: RecordNode,
__: ViewFieldFilterAttributes,
___: FieldAttributes
) => {
return false;
};
const recordMatchesCreatedAtFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes
) => {
if (!filter.value) return false;
if (typeof filter.value !== 'string') {
return true;
}
const filterDate = new Date(filter.value);
filterDate.setHours(0, 0, 0, 0); // Set time to midnight
const recordDate = new Date(record.createdAt);
recordDate.setHours(0, 0, 0, 0); // Set time to midnight
switch (filter.operator) {
case 'is_equal_to':
return recordDate.getTime() === filterDate.getTime();
case 'is_not_equal_to':
return recordDate.getTime() !== filterDate.getTime();
case 'is_on_or_after':
return recordDate.getTime() >= filterDate.getTime();
case 'is_on_or_before':
return recordDate.getTime() <= filterDate.getTime();
case 'is_after':
return recordDate.getTime() > filterDate.getTime();
case 'is_before':
return recordDate.getTime() < filterDate.getTime();
}
return false;
};
const recordMatchesCreatedByFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes,
currentUserId: string
) => {
const createdBy = record.createdBy;
if (!createdBy) {
return false;
}
if (filter.operator === 'is_me') {
return createdBy === currentUserId;
}
if (filter.operator === 'is_not_me') {
return createdBy !== currentUserId;
}
if (!isStringArray(filter.value)) {
return true;
}
if (filter.operator === 'is_in') {
return filter.value.includes(createdBy);
}
if (filter.operator === 'is_not_in') {
return !filter.value.includes(createdBy);
}
return false;
};
const recordMatchesDateFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes,
field: FieldAttributes
) => {
const fieldValue = record.attributes.fields[field.id];
if (filter.operator === 'is_empty') {
return !fieldValue;
}
if (filter.operator === 'is_not_empty') {
return !!fieldValue;
}
if (!fieldValue || fieldValue.type !== 'date') {
return false;
}
const recordDate = new Date(fieldValue.value);
recordDate.setHours(0, 0, 0, 0); // Set time to midnight
if (typeof filter.value !== 'string') {
return true;
}
const filterDate = new Date(filter.value);
filterDate.setHours(0, 0, 0, 0); // Set time to midnight
switch (filter.operator) {
case 'is_equal_to':
return recordDate.getTime() === filterDate.getTime();
case 'is_not_equal_to':
return recordDate.getTime() !== filterDate.getTime();
case 'is_on_or_after':
return recordDate.getTime() >= filterDate.getTime();
case 'is_on_or_before':
return recordDate.getTime() <= filterDate.getTime();
case 'is_after':
return recordDate.getTime() > filterDate.getTime();
case 'is_before':
return recordDate.getTime() < filterDate.getTime();
}
return false;
};
const recordMatchesEmailFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes,
field: FieldAttributes
) => {
const fieldValue = record.attributes.fields[field.id];
if (filter.operator === 'is_empty') {
return !fieldValue;
}
if (filter.operator === 'is_not_empty') {
return !!fieldValue;
}
if (!fieldValue || fieldValue.type !== 'email') {
return false;
}
if (typeof filter.value !== 'string') {
return true;
}
const filterValue = filter.value;
if (!filterValue) {
return true;
}
switch (filter.operator) {
case 'is_equal_to':
return fieldValue.value === filterValue;
case 'is_not_equal_to':
return fieldValue.value !== filterValue;
case 'contains':
return fieldValue.value.includes(filterValue);
case 'does_not_contain':
return !fieldValue.value.includes(filterValue);
}
return false;
};
const recordMatchesFileFilter = (
_: RecordNode,
__: ViewFieldFilterAttributes,
___: FieldAttributes
) => {
return false;
};
const recordMatchesMultiSelectFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes,
field: FieldAttributes
) => {
const fieldValue = record.attributes.fields[field.id];
const selectValues =
fieldValue?.type === 'multiSelect' ? fieldValue.value : [];
if (filter.operator === 'is_empty') {
return selectValues.length === 0;
}
if (filter.operator === 'is_not_empty') {
return selectValues.length > 0;
}
if (!isStringArray(filter.value)) {
return true;
}
switch (filter.operator) {
case 'is_in':
return filter.value.some((value) => selectValues.includes(value));
case 'is_not_in':
return !filter.value.some((value) => selectValues.includes(value));
}
return false;
};
const recordMatchesNumberFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes,
field: FieldAttributes
) => {
const fieldValue = record.attributes.fields[field.id];
if (filter.operator === 'is_empty') {
return !fieldValue;
}
if (filter.operator === 'is_not_empty') {
return !!fieldValue;
}
if (!fieldValue || fieldValue.type !== 'number') {
return false;
}
if (typeof filter.value !== 'number') {
return true;
}
const filterValue = filter.value;
if (!filterValue) {
return true;
}
switch (filter.operator) {
case 'is_equal_to':
return fieldValue.value === filterValue;
case 'is_not_equal_to':
return fieldValue.value !== filterValue;
case 'is_greater_than':
return fieldValue.value > filterValue;
case 'is_less_than':
return fieldValue.value < filterValue;
case 'is_greater_than_or_equal_to':
return fieldValue.value >= filterValue;
case 'is_less_than_or_equal_to':
return fieldValue.value <= filterValue;
}
return false;
};
const recordMatchesPhoneFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes,
field: FieldAttributes
) => {
const fieldValue = record.attributes.fields[field.id];
if (filter.operator === 'is_empty') {
return !fieldValue;
}
if (filter.operator === 'is_not_empty') {
return !!fieldValue;
}
if (!fieldValue || fieldValue.type !== 'phone') {
return false;
}
if (typeof filter.value !== 'string') {
return true;
}
const filterValue = filter.value;
if (!filterValue) {
return true;
}
switch (filter.operator) {
case 'is_equal_to':
return fieldValue.value === filterValue;
case 'is_not_equal_to':
return fieldValue.value !== filterValue;
case 'contains':
return fieldValue.value.includes(filterValue);
case 'does_not_contain':
return !fieldValue.value.includes(filterValue);
}
return false;
};
const recordMatchesSelectFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes,
field: FieldAttributes
) => {
const fieldValue = record.attributes.fields[field.id];
if (filter.operator === 'is_empty') {
return !fieldValue;
}
if (filter.operator === 'is_not_empty') {
return !!fieldValue;
}
if (!fieldValue || fieldValue.type !== 'select') {
return false;
}
if (!isStringArray(filter.value)) {
return true;
}
const selectValues = fieldValue.value;
switch (filter.operator) {
case 'is_in':
return filter.value.some((value) => selectValues.includes(value));
case 'is_not_in':
return !filter.value.some((value) => selectValues.includes(value));
}
return false;
};
const recordMatchesTextFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes,
field: FieldAttributes
) => {
const fieldValue = record.attributes.fields[field.id];
if (filter.operator === 'is_empty') {
return !fieldValue;
}
if (filter.operator === 'is_not_empty') {
return !!fieldValue;
}
if (!fieldValue || fieldValue.type !== 'text') {
return false;
}
if (typeof filter.value !== 'string') {
return true;
}
const filterValue = filter.value;
if (!filterValue) {
return true;
}
switch (filter.operator) {
case 'is_equal_to':
return fieldValue.value === filterValue;
case 'is_not_equal_to':
return fieldValue.value !== filterValue;
case 'contains':
return fieldValue.value.includes(filterValue);
case 'does_not_contain':
return !fieldValue.value.includes(filterValue);
}
return false;
};
const recordMatchesUrlFilter = (
record: RecordNode,
filter: ViewFieldFilterAttributes,
field: FieldAttributes
) => {
const fieldValue = record.attributes.fields[field.id];
if (filter.operator === 'is_empty') {
return !fieldValue;
}
if (filter.operator === 'is_not_empty') {
return !!fieldValue;
}
if (!fieldValue || fieldValue.type !== 'url') {
return false;
}
if (typeof filter.value !== 'string') {
return true;
}
const filterValue = filter.value;
if (!filterValue) {
return true;
}
switch (filter.operator) {
case 'is_equal_to':
return fieldValue.value === filterValue;
case 'is_not_equal_to':
return fieldValue.value !== filterValue;
case 'contains':
return fieldValue.value.includes(filterValue);
case 'does_not_contain':
return !fieldValue.value.includes(filterValue);
}
return false;
};
export const isFilterableField = (field: FieldAttributes) => {
// TODO: Implement this
return true;
};
export const isSortableField = (field: FieldAttributes) => {
return (
field.type === 'text' ||
field.type === 'number' ||
field.type === 'date' ||
field.type === 'createdAt' ||
field.type === 'email' ||
field.type === 'phone' ||
field.type === 'select' ||
field.type === 'url'
);
};
export const generateViewFieldIndex = (
databaseFields: FieldAttributes[],
viewFields: ViewFieldAttributes[],
fieldId: string,
after: string
): string | null => {
const field = databaseFields.find((f) => f.id === fieldId);
if (!field) {
return null;
}
if (databaseFields.length <= 1) {
return null;
}
const mergedIndexes = databaseFields
.map((f) => {
const viewField = viewFields.find((vf) => vf.id === f.id);
return {
id: f.id,
databaseIndex: f.index,
viewIndex: viewField?.index ?? null,
};
})
.sort((a, b) =>
compareString(
a.viewIndex ?? a.databaseIndex,
b.viewIndex ?? b.databaseIndex
)
);
let previousIndex: string | null = null;
let nextIndex: string | null = null;
if (after === 'name') {
const lowestIndex = mergedIndexes[0];
if (!lowestIndex) {
return null;
}
nextIndex = lowestIndex.viewIndex ?? lowestIndex.databaseIndex;
} else {
const afterFieldArrayIndex = mergedIndexes.findIndex((f) => f.id === after);
if (afterFieldArrayIndex === -1) {
return null;
}
const afterFieldIndex = mergedIndexes[afterFieldArrayIndex];
previousIndex =
afterFieldIndex?.viewIndex ?? afterFieldIndex?.databaseIndex ?? null;
if (afterFieldArrayIndex < mergedIndexes.length) {
const nextFieldIndex = mergedIndexes[afterFieldArrayIndex + 1];
nextIndex =
nextFieldIndex?.viewIndex ?? nextFieldIndex?.databaseIndex ?? null;
}
}
let newIndex = generateNodeIndex(previousIndex, nextIndex);
const lastDatabaseField = mergedIndexes.sort((a, b) =>
compareString(a.databaseIndex, b.databaseIndex)
)[mergedIndexes.length - 1]!;
const newPotentialFieldIndex = generateNodeIndex(
lastDatabaseField.databaseIndex,
null
);
if (newPotentialFieldIndex === newIndex) {
newIndex = generateNodeIndex(previousIndex, newPotentialFieldIndex);
}
return newIndex;
};
export const generateFieldValuesFromFilters = (
fields: FieldAttributes[],
filters: ViewFilterAttributes[],
userId: string
): Record<string, FieldValue> => {
if (fields.length === 0 || filters.length === 0) {
return {};
}
const fieldValues: Record<string, FieldValue> = {};
for (const filter of filters) {
if (filter.type !== 'field') continue;
const field = fields.find((f) => f.id === filter.fieldId);
if (!field) continue;
const value = generateValueFromFilter(field, filter, userId);
if (!value) continue;
fieldValues[field.id] = value;
}
return fieldValues;
};
const generateValueFromFilter = (
field: FieldAttributes,
filter: ViewFieldFilterAttributes,
userId: string
): FieldValue | null => {
switch (field.type) {
case 'boolean': {
return generateBooleanValue(filter);
}
case 'collaborator': {
return generateCollaboratorValue(filter, userId);
}
case 'date': {
return generateDateValue(filter);
}
case 'email': {
return generateEmailValue(filter);
}
case 'file': {
return generateFileValue(filter);
}
case 'multiSelect': {
return generateMultiSelectValue(field, filter);
}
case 'number': {
return generateNumberValue(filter);
}
case 'phone': {
return generatePhoneValue(filter);
}
case 'select': {
return generateSelectValue(field, filter);
}
case 'text': {
return generateTextValue(filter);
}
case 'url': {
return generateUrlValue(filter);
}
default:
return null;
}
};
const generateBooleanValue = (
filter: ViewFieldFilterAttributes
): FieldValue | null => {
if (filter.operator === 'is_true') {
return { type: 'boolean', value: true };
}
if (filter.operator === 'is_false') {
return { type: 'boolean', value: false };
}
return null;
};
const generateCollaboratorValue = (
filter: ViewFieldFilterAttributes,
userId: string
): FieldValue | null => {
if (filter.operator === 'is_me') {
return { type: 'collaborator', value: [userId] };
}
if (filter.operator === 'is_in' && Array.isArray(filter.value)) {
const firstValue = filter.value[0];
if (!firstValue) {
return null;
}
return { type: 'collaborator', value: [firstValue] };
}
if (filter.operator === 'is_not_empty') {
return { type: 'collaborator', value: [userId] };
}
return null;
};
const generateDateValue = (
filter: ViewFieldFilterAttributes
): FieldValue | null => {
if (typeof filter.value !== 'string') {
return null;
}
if (filter.operator === 'is_equal_to') {
return { type: 'date', value: filter.value };
}
if (filter.operator === 'is_on_or_after') {
return { type: 'date', value: filter.value };
}
if (filter.operator === 'is_on_or_before') {
return { type: 'date', value: filter.value };
}
if (filter.operator === 'is_after') {
const date = new Date(filter.value);
date.setDate(date.getDate() + 1);
return { type: 'date', value: date.toISOString() };
}
if (filter.operator === 'is_before') {
const date = new Date(filter.value);
date.setDate(date.getDate() - 1);
return { type: 'date', value: date.toISOString() };
}
if (filter.operator === 'is_not_empty') {
return { type: 'date', value: new Date().toISOString() };
}
return null;
};
const generateEmailValue = (
filter: ViewFieldFilterAttributes
): FieldValue | null => {
if (typeof filter.value !== 'string') {
return null;
}
if (filter.operator === 'is_equal_to') {
return { type: 'email', value: filter.value };
}
if (filter.operator === 'contains') {
return { type: 'email', value: filter.value };
}
if (filter.operator === 'is_not_empty') {
return { type: 'email', value: '#' };
}
return null;
};
const generateFileValue = (
filter: ViewFieldFilterAttributes
): FieldValue | null => {
if (filter.operator === 'is_in' && Array.isArray(filter.value)) {
const firstValue = filter.value[0];
if (!firstValue) {
return null;
}
return { type: 'file', value: [firstValue] };
}
return null;
};
const generateMultiSelectValue = (
field: MultiSelectFieldAttributes,
filter: ViewFieldFilterAttributes
): FieldValue | null => {
if (filter.operator === 'is_in' && Array.isArray(filter.value)) {
const firstValue = filter.value[0];
if (!firstValue) {
return null;
}
return { type: 'multiSelect', value: [firstValue] };
}
if (
filter.operator === 'is_not_empty' &&
field.options &&
Object.keys(field.options).length > 0
) {
const firstOption = Object.values(field.options)[0];
if (!firstOption) {
return null;
}
return { type: 'multiSelect', value: [firstOption.id] };
}
return null;
};
const generateNumberValue = (
filter: ViewFieldFilterAttributes
): FieldValue | null => {
if (typeof filter.value !== 'number') {
return null;
}
if (filter.operator === 'is_equal_to') {
return { type: 'number', value: filter.value };
}
if (filter.operator === 'is_greater_than') {
return { type: 'number', value: filter.value + 1 };
}
if (filter.operator === 'is_less_than') {
return { type: 'number', value: filter.value - 1 };
}
if (filter.operator === 'is_greater_than_or_equal_to') {
return { type: 'number', value: filter.value };
}
if (filter.operator === 'is_less_than_or_equal_to') {
return { type: 'number', value: filter.value };
}
if (filter.operator === 'is_not_empty') {
return { type: 'number', value: 0 };
}
return null;
};
const generatePhoneValue = (
filter: ViewFieldFilterAttributes
): FieldValue | null => {
if (typeof filter.value !== 'string') {
return null;
}
if (filter.operator === 'is_equal_to') {
return { type: 'phone', value: filter.value };
}
if (filter.operator === 'contains') {
return { type: 'phone', value: filter.value };
}
if (filter.operator === 'is_not_empty') {
return { type: 'phone', value: '#' };
}
return null;
};
const generateSelectValue = (
field: SelectFieldAttributes,
filter: ViewFieldFilterAttributes
): FieldValue | null => {
if (filter.operator === 'is_in' && Array.isArray(filter.value)) {
const firstValue = filter.value[0];
if (!firstValue) {
return null;
}
return { type: 'select', value: firstValue };
}
if (
filter.operator === 'is_not_empty' &&
field.options &&
Object.keys(field.options).length > 0
) {
const firstOption = Object.values(field.options)[0];
if (!firstOption) {
return null;
}
return { type: 'select', value: firstOption.id };
}
return null;
};
const generateTextValue = (
filter: ViewFieldFilterAttributes
): FieldValue | null => {
if (typeof filter.value !== 'string') {
return null;
}
if (filter.operator === 'is_equal_to') {
return { type: 'text', value: filter.value };
}
if (filter.operator === 'contains') {
return { type: 'text', value: filter.value };
}
if (filter.operator === 'is_not_empty') {
return { type: 'text', value: '#' };
}
return null;
};
const generateUrlValue = (
filter: ViewFieldFilterAttributes
): FieldValue | null => {
if (typeof filter.value !== 'string') {
return null;
}
if (filter.operator === 'is_equal_to') {
return { type: 'url', value: filter.value };
}
if (filter.operator === 'contains') {
return { type: 'url', value: filter.value };
}
if (filter.operator === 'is_not_empty') {
return { type: 'url', value: '#' };
}
return null;
};