Fixed issues with query builder

This commit is contained in:
Umar Adilov 2026-06-01 23:18:12 +05:00
parent a1c95a019a
commit f04aaca29e
6 changed files with 899 additions and 632 deletions

View File

@ -5,7 +5,7 @@ const nextConfig: NextConfig = {
remotePatterns: [
{
protocol: 'https',
hostname: 'media.bambooapp.ai',
hostname: 'media.taylordb.ai',
pathname: '/files/**',
},
{

View File

@ -7,7 +7,8 @@
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "eslint ."
"lint": "eslint .",
"regenerate:types": "npx @taylordb/cli generate-schema af483cef-ec47-48fc-b186-e11022dbb0e2 src/shared/database.types.ts"
},
"dependencies": {
"@hookform/resolvers": "^5.0.1",
@ -25,7 +26,8 @@
"@radix-ui/react-toast": "^1.2.11",
"@radix-ui/react-tooltip": "^1.2.6",
"@reduxjs/toolkit": "^2.7.0",
"@taylordb/query-builder": "^0.10.1",
"@taylordb/cli": "^0.18.2",
"@taylordb/query-builder": "^0.18.2",
"aos": "^2.3.4",
"axios": "^1.9.0",
"class-variance-authority": "^0.7.1",
@ -87,4 +89,4 @@
"@types/react-dom": "19.2.3"
}
}
}
}

639
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,33 @@
import { isEmpty } from 'lodash';
import { TaylorDatabase } from '@/shared/types/database.types';
import {
AttachmentColumnValue,
TableRaws,
} from '@/shared/types/database.types';
type TaylorColumnRaw<TColumn> = TColumn extends {
raw: infer TRaw;
isRequired: true;
}
? TRaw
: TColumn extends { raw: infer TRaw }
? TRaw | undefined
: never;
// Helper to get image URL from Attachment array
export const getAttachmentUrl = (
attachments: AttachmentColumnValue[] | undefined | null,
): string | null => {
if (isEmpty(attachments) || !attachments?.[0]) return null;
const attachment = attachments[0];
return `${process.env.TAYLOR_MEDIA_URL}/${attachment.url}`;
type TableRaws<TTableName extends keyof TaylorDatabase> = {
[K in keyof TaylorDatabase[TTableName]]: TaylorColumnRaw<
TaylorDatabase[TTableName][K]
>;
};
// Helper to get link select name (link to selectTable returns object with name)
export const getLinkSelectName = (
link: { name: string } | undefined | null,
): string | null => {
return link?.name || null;
};
const getAttachmentUrl = (urls: string[] | undefined): string | null => {
if (!urls?.length) return null;
// Helper to get multiple link select names (for arrays of links)
export const getLinkSelectNames = (
links: Array<{ name: string }> | undefined | null,
): string[] => {
if (!links || isEmpty(links)) return [];
return links.map((link) => link.name);
const [url] = urls;
if (!url) return null;
if (/^https?:\/\//.test(url)) {
return url;
}
return process.env.TAYLOR_MEDIA_URL
? `${process.env.TAYLOR_MEDIA_URL}/${url}`
: url;
};
// Presenters for TaylorDB query builder results (direct array format, no wrapper)
@ -53,13 +54,9 @@ export const presentJobsFromTaylor = (
return jobs.map((job, index) => ({
id: index + 1,
name: job.zagolovok || '',
// tegi is a LinkColumnType, so it returns objects when loaded with .with()
tags: Array.isArray(job.tegi)
? (job.tegi as Array<{ name: string }>).map((tag) => tag.name)
: [],
// tip and lokaciya are SingleSelectColumnType, which return arrays of strings
location: job.lokaciya?.[0] || null,
type: job.tip?.[0] || null,
tags: job.tegi || [],
location: job.lokaciya || null,
type: job.tip || null,
}));
};
@ -108,9 +105,7 @@ export const presentStationsFromTaylor = (
name: station.imya || '',
description: station.opisanie || '',
address: station.adress || '',
// chasyRaboty and region are SingleSelectColumnType, which return arrays of strings
workingHours: station.chasyRaboty?.[0] || null,
// Parse string coordinates to numbers
workingHours: station.chasyRaboty || null,
latitude: parseFloat(station.lat || '0') || 0,
longitude: parseFloat(station.long || '0') || 0,
carWash: station.avtomojka || false,
@ -122,7 +117,7 @@ export const presentStationsFromTaylor = (
electricCharge: station.zaryadnayaStanciya || false,
miniMarket: station.miniMarket || false,
toilet: station.tualet || false,
region: station.region?.[0] || null,
region: station.region || null,
image: getAttachmentUrl(station.foto),
}));
};

View File

@ -30,36 +30,16 @@ export async function fetchMainPageContent(): Promise<MainPageData> {
await taylorQueryBuilder
.batch([
// Fetch partners
taylorQueryBuilder
.selectFrom('partnyory')
.selectAll()
.with({
izobrozhenie: (qb) => qb.selectAll(),
}),
taylorQueryBuilder.selectFrom('partnyory').selectAll(),
// Fetch jobs
taylorQueryBuilder
.selectFrom('vakansii')
.selectAll()
.with({
tegi: (qb) => qb.select(['name']),
}),
taylorQueryBuilder.selectFrom('vakansii').selectAll(),
// Fetch discounts
taylorQueryBuilder
.selectFrom('akcii')
.selectAll()
.with({
foto: (qb) => qb.selectAll(),
}),
taylorQueryBuilder.selectFrom('akcii').selectAll(),
// Fetch stations
taylorQueryBuilder
.selectFrom('azs')
.selectAll()
.with({
foto: (qb) => qb.selectAll(),
}),
taylorQueryBuilder.selectFrom('azs').selectAll(),
])
.execute();
@ -82,12 +62,7 @@ export async function fetchAboutUsPageContent(): Promise<AboutUsPageData> {
await taylorQueryBuilder
.batch([
// Fetch team members
taylorQueryBuilder
.selectFrom('komanda')
.selectAll()
.with({
foto: (qb) => qb.selectAll(),
}),
taylorQueryBuilder.selectFrom('komanda').selectAll(),
// Fetch history items
taylorQueryBuilder.selectFrom('istoriyaKompanii').selectAll(),
@ -96,10 +71,7 @@ export async function fetchAboutUsPageContent(): Promise<AboutUsPageData> {
taylorQueryBuilder
.selectFrom('azs')
.selectAll()
.where('foto', 'isNotEmpty')
.with({
foto: (qb) => qb.selectAll(),
}),
.where('foto', 'isNotEmpty'),
// Fetch reviews (filtered by published status)
taylorQueryBuilder
@ -126,9 +98,6 @@ export async function fetchCharityPageContent(): Promise<CharityPageData> {
const charitiesData = await taylorQueryBuilder
.selectFrom('blagotvoritelnyjFond')
.selectAll()
.with({
foto: (qb) => qb.selectAll(),
})
.execute();
console.log('Loading charity page content...');
@ -145,9 +114,6 @@ export async function fetchCertificatesPageContent(): Promise<CertificatesPageDa
const certificatesData = await taylorQueryBuilder
.selectFrom('sertifikaty')
.selectAll()
.with({
foto: (qb) => qb.selectAll(),
})
.execute();
console.log('Loading certificates page content...');
@ -182,9 +148,6 @@ export async function fetchMediaContent(): Promise<
const mediaData = await taylorQueryBuilder
.selectFrom('mediaKontentSajta')
.selectAll()
.with({
foto: (qb) => qb.selectAll(),
})
.execute();
console.log('Loading media content...');

View File

@ -4,545 +4,235 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {
attachmentField,
autoDateField,
autoNumberField,
checkboxField,
dateField,
defineTaylorSchema,
linkField,
numberField,
searchField,
selectField,
textField,
} from '@taylordb/query-builder';
import type { InferTaylorDatabase } from '@taylordb/query-builder';
interface FileInformation {
fieldname: string;
originalname: string;
encoding: string;
mimetype: string;
destination: string;
filename: string;
path: string;
size: number;
format: string;
width: number;
height: number;
}
export const taylorSchema = defineTaylorSchema({
attachmentTable: {
id: autoNumberField(),
name: textField({ required: true }),
metadata: textField({ required: true }),
size: numberField({ required: true }),
fileType: textField({ required: true }),
url: textField({ required: true }),
searchText: searchField(),
},
collaborators: {
id: autoNumberField(),
name: textField({ required: true }),
emailAddress: textField({ required: true }),
avatar: textField({ required: true }),
searchText: searchField(),
},
vakansii: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
zagolovok: textField({ required: false }),
tip: selectField({
required: false,
mode: 'single',
options: ['Офис', 'Заправки'] as const,
}),
lokaciya: selectField({
required: false,
mode: 'single',
options: ['Душанбе'] as const,
}),
tegi: selectField({
required: false,
mode: 'multi',
options: ['Полный день', 'Опыт от 1 года', 'Мужчины'] as const,
}),
},
partnyory: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
nazvanie: textField({ required: false }),
tt: linkField({
linkedTo: 'ff',
required: false
}),
izobrozhenie: attachmentField({ required: false }),
},
azs: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
imya: textField({ required: false }),
adress: textField({ required: false }),
opisanie: textField({ required: false }),
chasyRaboty: selectField({
required: false,
mode: 'single',
options: ['Круглосуточно'] as const,
}),
lat: textField({ required: false }),
long: textField({ required: false }),
avtomojka: checkboxField({ required: false }),
dt: checkboxField({ required: false }),
ai92: checkboxField({ required: false }),
ai95: checkboxField({ required: false }),
z100: checkboxField({ required: false }),
propan: checkboxField({ required: false }),
zaryadnayaStanciya: checkboxField({ required: false }),
miniMarket: checkboxField({ required: false }),
tualet: checkboxField({ required: false }),
region: selectField({
required: false,
mode: 'single',
options: [
'Душанбе',
'Бохтар',
'Худжанд',
'Регар',
'Вахдат',
'А.Джоми',
'Обикиик',
'Кулоб',
'Дахана',
'Ёвон',
'Панч',
'Исфара',
'Мастчох',
'Хисор',
] as const,
}),
foto: attachmentField({ required: false }),
},
akcii: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
zagolovok: textField({ required: false }),
opisanie: textField({ required: false }),
do: dateField({ required: false }),
foto: attachmentField({ required: false }),
},
istoriyaKompanii: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
zagolovok: textField({ required: false }),
god: numberField({ required: false }),
opisanie: textField({ required: false }),
},
komanda: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
polnoeImya: textField({ required: false }),
foto: attachmentField({ required: false }),
zvanie: textField({ required: false }),
},
otzyvy: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
polnoeImya: textField({ required: false }),
otzyv: textField({ required: false }),
rejting: numberField({ required: false }),
status: selectField({
required: false,
mode: 'single',
options: ['Опубликовано', 'Не публиковать'] as const,
}),
},
tekstovyjKontentSajta: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
klyuchNeIzmenyat: textField({ required: true }),
znachenie: textField({ required: true }),
opisanie: selectField({
required: false,
mode: 'multi',
options: [
'Общая',
'Домашняя страница',
'О нас',
'Благотворительность',
'Клиенты',
'Почты',
'Соц сети',
'Карты',
'Лояльность',
'Авторизация',
'Сертификаты',
'Бонусный клиент',
'Корпоративный клиент',
'Транзакции',
] as const,
}),
},
sertifikaty: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
nazvanie: textField({ required: false }),
opisanie: textField({ required: false }),
dataVydachi: dateField({ required: false }),
dejstvitelenDo: dateField({ required: false }),
foto: attachmentField({ required: false }),
},
mediaKontentSajta: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
mestopolozheniya: textField({ required: false }),
klyuchNeIzmenyat: textField({ required: true }),
foto: attachmentField({ required: false }),
stranica: selectField({
required: false,
mode: 'single',
options: [
'Главная',
'О нас',
'Благотворительность',
'Общая',
'Клиенты',
'Программа лояльности',
] as const,
}),
},
blagotvoritelnyjFond: {
id: autoNumberField(),
createdAt: autoDateField(),
updatedAt: autoDateField(),
searchText: searchField(),
zagolovok: textField({ required: false }),
opisanie: textField({ required: false }),
data: dateField({ required: false }),
lokaciya: textField({ required: false }),
foto: attachmentField({ required: false }),
},
});
interface UploadResponse {
collectionName: string;
fileInformation: FileInformation;
metadata: {
thumbnails: any[];
clips: any[];
};
baseId: string;
storageAdaptor: string;
_id: string;
__v: number;
}
export interface AttachmentColumnValue {
url: string;
fileType: string;
size: number;
}
export class Attachment {
public readonly collectionName: string;
public readonly fileInformation: FileInformation;
public readonly metadata: { thumbnails: any[]; clips: any[] };
public readonly baseId: string;
public readonly storageAdaptor: string;
public readonly _id: string;
constructor(data: UploadResponse) {
this.collectionName = data.collectionName;
this.fileInformation = data.fileInformation;
this.metadata = data.metadata;
this.baseId = data.baseId;
this.storageAdaptor = data.storageAdaptor;
this._id = data._id;
}
toColumnValue(): AttachmentColumnValue {
return {
url: this.fileInformation.path,
fileType: this.fileInformation.mimetype,
size: this.fileInformation.size,
};
}
}
type IsWithinOperatorValue =
| 'pastWeek'
| 'pastMonth'
| 'pastYear'
| 'nextWeek'
| 'nextMonth'
| 'nextYear'
| 'daysFromNow'
| 'daysAgo'
| 'currentWeek'
| 'currentMonth'
| 'currentYear';
type DefaultDateFilterValue =
| (
| 'today'
| 'tomorrow'
| 'yesterday'
| 'oneWeekAgo'
| 'oneWeekFromNow'
| 'oneMonthAgo'
| 'oneMonthFromNow'
)
| ['exactDay' | 'exactTimestamp', string]
| ['daysAgo' | 'daysFromNow', number];
type DateFilters = {
'=': DefaultDateFilterValue;
'!=': DefaultDateFilterValue;
'<': DefaultDateFilterValue;
'>': DefaultDateFilterValue;
'<=': DefaultDateFilterValue;
'>=': DefaultDateFilterValue;
isWithIn:
| IsWithinOperatorValue
| { value: 'daysAgo' | 'daysFromNow'; date: number };
isEmpty: boolean;
isNotEmpty: boolean;
};
type DateAggregations = {
empty: number;
filled: number;
unique: number;
percentEmpty: number;
percentFilled: number;
percentUnique: number;
min: number | null;
max: number | null;
daysRange: number | null;
monthRange: number | null;
};
type TextFilters = {
'=': string;
'!=': string;
caseEqual: string;
hasAnyOf: string[];
contains: string;
startsWith: string;
endsWith: string;
doesNotContain: string;
isEmpty: never;
isNotEmpty: never;
};
type LinkFilters = {
hasAnyOf: number[];
hasAllOf: number[];
isExactly: number[];
'=': number;
hasNoneOf: number[];
contains: string;
doesNotContain: string;
isEmpty: never;
isNotEmpty: never;
};
type SelectFilters<O extends readonly string[]> = {
hasAnyOf: O[number][];
hasAllOf: O[number][];
isExactly: O[number][];
'=': O[number];
hasNoneOf: O[number][];
contains: string;
doesNotContain: string;
isEmpty: never;
isNotEmpty: never;
};
type LinkAggregations = {
empty: number;
filled: number;
percentEmpty: number;
percentFilled: number;
};
type NumberFilters = {
'=': number;
'!=': number;
'>': number;
'>=': number;
'<': number;
'<=': number;
hasAnyOf: number[];
hasNoneOf: number[];
isEmpty: never;
isNotEmpty: never;
};
type NumberAggregations = {
sum: number;
average: number;
median: number;
min: number | null;
max: number | null;
range: number;
standardDeviation: number;
histogram: Record<string, number>;
empty: number;
filled: number;
unique: number;
percentEmpty: number;
percentFilled: number;
percentUnique: number;
};
type CheckboxFilters = {
'=': number;
};
/**
*
* Column types
*
*/
export type ColumnType<
S,
U,
I,
R extends boolean,
F extends { [key: string]: any } = object,
A extends { [key: string]: any } = object,
> = {
raw: S;
insert: I;
update: U;
filters: F;
aggregations: A;
isRequired: R;
};
export type DateColumnType<R extends boolean> = ColumnType<
string,
string,
string,
R,
DateFilters,
DateAggregations
>;
export type TextColumnType<R extends boolean> = ColumnType<
string,
string,
string,
R,
TextFilters
>;
export type ALinkColumnType<
T extends string,
S,
U,
I,
R extends boolean,
F extends { [key: string]: any } = LinkFilters,
A extends LinkAggregations = LinkAggregations,
> = ColumnType<S, U, I, R, F, A> & {
linkedTo: T;
};
export type LinkColumnType<
T extends string,
R extends boolean,
> = ALinkColumnType<
T,
object,
number | number[] | { newIds: number[]; deletedIds: number[] },
number | number[],
R
>;
export type AttachmentColumnType<R extends boolean> = ALinkColumnType<
'attachmentTable',
AttachmentColumnValue[],
Attachment[] | { newIds: number[]; deletedIds: number[] } | number[],
Attachment[] | number[],
R
>;
export type NumberColumnType<R extends boolean> = ColumnType<
number,
number,
number,
R,
NumberFilters,
NumberAggregations
>;
export type CheckboxColumnType<R extends boolean> = ColumnType<
boolean,
boolean,
boolean,
R,
CheckboxFilters
>;
export type AutoGeneratedNumberColumnType = ColumnType<
number,
never,
never,
false,
NumberFilters,
NumberAggregations
>;
export type AutoGeneratedDateColumnType = ColumnType<
string,
never,
never,
false,
DateFilters,
DateAggregations
>;
export type SingleSelectColumnType<
O extends readonly string[],
R extends boolean,
> = ALinkColumnType<
'selectTable',
O[number],
O[number] | O[number][],
O[number] | O[number][],
R,
SelectFilters<O>
>;
export type TableRaws<T extends keyof TaylorDatabase> = {
[K in keyof TaylorDatabase[T]]: TaylorDatabase[T][K] extends ColumnType<
infer S,
any,
any,
infer R,
any,
any
>
? R extends true
? S
: S | undefined
: never;
};
export type TableInserts<T extends keyof TaylorDatabase> = {
[K in keyof TaylorDatabase[T]]: TaylorDatabase[T][K] extends ColumnType<
any,
infer I,
any,
infer R,
any,
any
>
? R extends true
? I
: I | undefined
: never;
};
export type TableUpdates<T extends keyof TaylorDatabase> = {
[K in keyof TaylorDatabase[T]]: TaylorDatabase[T][K] extends ColumnType<
any,
any,
infer U,
any,
any,
any
>
? U
: never;
};
export type SelectTable = {
id: AutoGeneratedNumberColumnType;
name: TextColumnType<true>;
color: TextColumnType<true>;
};
export type AttachmentTable = {
id: AutoGeneratedNumberColumnType;
name: TextColumnType<true>;
metadata: TextColumnType<true>;
size: NumberColumnType<true>;
fileType: TextColumnType<true>;
url: TextColumnType<true>;
};
export type CollaboratorsTable = {
id: AutoGeneratedNumberColumnType;
name: TextColumnType<true>;
emailAddress: TextColumnType<true>;
avatar: TextColumnType<true>;
};
export type TaylorDatabase = {
/**
*
*
* Internal tables, these tables can not be queried directly.
*
*/
selectTable: SelectTable;
attachmentTable: AttachmentTable;
collaboratorsTable: CollaboratorsTable;
vakansii: VakansiiTable;
partnyory: PartnyoryTable;
azs: AzsTable;
akcii: AkciiTable;
istoriyaKompanii: IstoriyaKompaniiTable;
komanda: KomandaTable;
otzyvy: OtzyvyTable;
tekstovyjKontentSajta: TekstovyjKontentSajtaTable;
sertifikaty: SertifikatyTable;
mediaKontentSajta: MediaKontentSajtaTable;
blagotvoritelnyjFond: BlagotvoritelnyjFondTable;
};
export const VakansiiTipOptions = ['Офис', 'Заправки'] as const;
export const VakansiiLokaciyaOptions = ['Душанбе'] as const;
type VakansiiTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
zagolovok: TextColumnType<false>;
tip: SingleSelectColumnType<typeof VakansiiTipOptions, false>;
lokaciya: SingleSelectColumnType<typeof VakansiiLokaciyaOptions, false>;
tegi: LinkColumnType<'selectTable', false>;
};
type PartnyoryTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
nazvanie: TextColumnType<false>;
izobrozhenie: AttachmentColumnType<false>;
};
export const AzsChasyRabotyOptions = ['Круглосуточно'] as const;
export const AzsRegionOptions = [
'Душанбе',
'Бохтар',
'Худжанд',
'Регар',
'Вахдат',
'А.Джоми',
'Обикиик',
'Кулоб',
'Дахана',
'Ёвон',
'Панч',
'Исфара',
'Мастчох',
'Хисор',
] as const;
type AzsTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
imya: TextColumnType<false>;
adress: TextColumnType<false>;
opisanie: TextColumnType<false>;
chasyRaboty: SingleSelectColumnType<typeof AzsChasyRabotyOptions, false>;
lat: TextColumnType<false>;
long: TextColumnType<false>;
avtomojka: CheckboxColumnType<false>;
dt: CheckboxColumnType<false>;
ai92: CheckboxColumnType<false>;
ai95: CheckboxColumnType<false>;
z100: CheckboxColumnType<false>;
propan: CheckboxColumnType<false>;
zaryadnayaStanciya: CheckboxColumnType<false>;
miniMarket: CheckboxColumnType<false>;
tualet: CheckboxColumnType<false>;
region: SingleSelectColumnType<typeof AzsRegionOptions, false>;
foto: AttachmentColumnType<false>;
};
type AkciiTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
zagolovok: TextColumnType<false>;
opisanie: TextColumnType<false>;
do: DateColumnType<false>;
foto: AttachmentColumnType<false>;
};
type IstoriyaKompaniiTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
zagolovok: TextColumnType<false>;
god: NumberColumnType<false>;
opisanie: TextColumnType<false>;
};
type KomandaTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
polnoeImya: TextColumnType<false>;
foto: AttachmentColumnType<false>;
zvanie: TextColumnType<false>;
};
export const OtzyvyStatusOptions = ['Опубликовано', 'Не публиковать'] as const;
type OtzyvyTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
polnoeImya: TextColumnType<false>;
otzyv: TextColumnType<false>;
rejting: NumberColumnType<false>;
status: SingleSelectColumnType<typeof OtzyvyStatusOptions, false>;
};
type TekstovyjKontentSajtaTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
klyuchNeIzmenyat: TextColumnType<true>;
znachenie: TextColumnType<true>;
opisanie: LinkColumnType<'selectTable', false>;
};
type SertifikatyTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
nazvanie: TextColumnType<false>;
opisanie: TextColumnType<false>;
dataVydachi: DateColumnType<false>;
dejstvitelenDo: DateColumnType<false>;
foto: AttachmentColumnType<false>;
};
export const MediaKontentSajtaStranicaOptions = [
'Главная',
'О нас',
'Благотворительность',
'Общая',
'Клиенты',
'Программа лояльности',
] as const;
type MediaKontentSajtaTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
mestopolozheniya: TextColumnType<false>;
klyuchNeIzmenyat: TextColumnType<true>;
foto: AttachmentColumnType<false>;
stranica: SingleSelectColumnType<
typeof MediaKontentSajtaStranicaOptions,
false
>;
};
type BlagotvoritelnyjFondTable = {
id: NumberColumnType<false>;
createdAt: AutoGeneratedDateColumnType;
updatedAt: AutoGeneratedDateColumnType;
zagolovok: TextColumnType<false>;
opisanie: TextColumnType<false>;
data: DateColumnType<false>;
lokaciya: TextColumnType<false>;
foto: AttachmentColumnType<false>;
/** Generic type for plugin actions */
export type PluginActionType<I, O> = { input: I; result: O };
export type TaylorDatabase = InferTaylorDatabase<typeof taylorSchema> & {
_plugins: {};
};