diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 5d1a475..f283eea 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -63,7 +63,6 @@ addDecorator(makeDecorator({ events: {} as MittEmitter, isReady: true, isLocaleDomain: false, - isPreview: false, }} > {storyFn(context)} diff --git a/server/nexus/constants.ts b/server/nexus/constants.ts index da7af43..1377e9a 100644 --- a/server/nexus/constants.ts +++ b/server/nexus/constants.ts @@ -2,7 +2,7 @@ * ID ТВшек */ export const TemplateVarIDs = { - coors: 27, + coords: 27, image: 3, gallery: 23, address: 14, diff --git a/server/nexus/generated/nexus.ts b/server/nexus/generated/nexus.ts index 8a64687..8aad672 100644 --- a/server/nexus/generated/nexus.ts +++ b/server/nexus/generated/nexus.ts @@ -70,6 +70,15 @@ export interface NexusGenInputs { equals?: boolean | null // Boolean not?: NexusGenInputs['NestedBoolFilter'] | null // NestedBoolFilter } + CompaniesOrderByCoordsInput: { + // input type + lat: number // Float! + lng: number // Float! + } + CompaniesOrderByInput: { + // input type + coords?: NexusGenInputs['CompaniesOrderByCoordsInput'] | null // CompaniesOrderByCoordsInput + } DateTimeFilter: { // input type equals?: NexusGenScalars['DateTime'] | null // DateTime @@ -1313,11 +1322,9 @@ export interface NexusGenArgTypes { } companies: { // args - cursor?: NexusGenInputs['bani684_site_contentWhereUniqueInput'] | null // bani684_site_contentWhereUniqueInput - orderBy?: NexusGenInputs['bani684_site_contentOrderByInput'][] | null // [bani684_site_contentOrderByInput!] + orderBy?: NexusGenInputs['CompaniesOrderByInput'] | null // CompaniesOrderByInput skip?: number | null // Int take?: number | null // Int - where?: NexusGenInputs['bani684_site_contentWhereInput'] | null // bani684_site_contentWhereInput } ratings: { // args diff --git a/server/nexus/generated/schema.graphql b/server/nexus/generated/schema.graphql index c9ff390..977e417 100644 --- a/server/nexus/generated/schema.graphql +++ b/server/nexus/generated/schema.graphql @@ -81,6 +81,18 @@ type Comment { text: String } +""" +Сортировка по удаленности от координаты +""" +input CompaniesOrderByCoordsInput { + lat: Float! + lng: Float! +} + +input CompaniesOrderByInput { + coords: CompaniesOrderByCoordsInput +} + """ Компания """ @@ -332,13 +344,7 @@ type Query { """ Компании """ - companies( - cursor: bani684_site_contentWhereUniqueInput - orderBy: [bani684_site_contentOrderByInput!] - skip: Int - take: Int - where: bani684_site_contentWhereInput - ): [Company!]! + companies(orderBy: CompaniesOrderByInput, skip: Int, take: Int): [Company!]! """ Рейтинги заведений diff --git a/server/nexus/types/Query/definitions/Resource/Company.ts b/server/nexus/types/Query/definitions/Resource/Company.ts index 77b79b2..73851d7 100644 --- a/server/nexus/types/Query/definitions/Resource/Company.ts +++ b/server/nexus/types/Query/definitions/Resource/Company.ts @@ -1,190 +1,390 @@ /* eslint-disable @typescript-eslint/camelcase */ -import { Prisma } from '@prisma/client' -import { FieldResolver, ObjectDefinitionBlock } from 'nexus/dist/core' +// import { Prisma } from '@prisma/client' +import { bani684_site_content } from '.prisma/client' +import { bani684_site_tmplvar_contentvalues } from '@prisma/client' +import { + arg, + FieldResolver, + inputObjectType, + intArg, + ObjectDefinitionBlock, +} from 'nexus/dist/core' +import { NexusGenObjects } from 'server/nexus/generated/nexus' import { TemplateVarIDs } from '../../../../constants' +import { coordsResolver } from '../../resolvers/coords' + +// const companiesResolver: FieldResolver<'Query', 'companies'> = ( +// _, +// args, +// { prisma } +// ) => { +// const variables = args as Pick< +// Prisma.bani684_site_contentFindManyArgs, +// 'where' +// > + +// const { deleted = false, published = true, hidemenu = false } = +// variables.where || {} + +// const where: Prisma.bani684_site_contentFindManyArgs['where'] = { +// AND: [ +// { +// template: 27, +// deleted, +// published, +// hidemenu, +// }, +// { +// ...variables.where, +// }, +// ], +// } + +// /** +// * Получаем данные компаний +// */ +// return prisma.bani684_site_content +// .findMany({ +// ...variables, +// where, +// select: { +// id: true, +// pagetitle: true, +// longtitle: true, +// description: true, +// alias: true, +// uri: true, +// content: true, +// published: true, +// createdby: true, +// createdon: true, +// editedby: true, +// editedon: true, +// template: true, +// searchable: true, +// TemplateVarValues: { +// select: { +// id: true, +// contentid: true, +// tmplvarid: true, +// value: true, +// }, +// }, +// }, +// }) +// .then((resources) => { +// return resources.map((resource) => { +// const image = +// resource.TemplateVarValues?.find( +// (n) => n.tmplvarid === TemplateVarIDs.image +// )?.value || null + +// return { +// ...resource, +// image, +// } +// }) +// }) +// } + +// export const companies = (t: ObjectDefinitionBlock<'Query'>) => { +// t.crud.bani684SiteContents({ +// alias: 'companies', +// description: 'Компании', +// type: 'Company', +// ordering: true, +// filtering: true, +// resolve: companiesResolver, +// }) +// } + +export type CompaniesResult = { + company_id: NexusGenObjects['Company']['id'] + company_uri: NexusGenObjects['Company']['uri'] + company_pagetitle: NexusGenObjects['Company']['pagetitle'] + company_createdby: NexusGenObjects['Company']['createdby'] + company_createdon: NexusGenObjects['Company']['createdon'] + company_description: NexusGenObjects['Company']['description'] + company_longtitle: NexusGenObjects['Company']['longtitle'] + company_published: NexusGenObjects['Company']['published'] + company_searchable: NexusGenObjects['Company']['searchable'] + company_template: NexusGenObjects['Company']['template'] + company_image_id: number | undefined + company_image: string | undefined + company_gallery_id: number | undefined + company_gallery: string | undefined + company_coords_id: number | undefined + company_coords: string | undefined +} const companiesResolver: FieldResolver<'Query', 'companies'> = ( _, args, - { prisma } + { knex } ) => { - const variables = args as Pick< - Prisma.bani684_site_contentFindManyArgs, - 'where' - > + const { take: limit, skip } = args - const { deleted = false, published = true, hidemenu = false } = - variables.where || {} + const orderByCoords = args.orderBy?.coords - const where: Prisma.bani684_site_contentFindManyArgs['where'] = { - AND: [ - { - template: 27, - deleted, - published, - hidemenu, - }, - { - ...variables.where, - }, - ], - } + // const variables = args as Pick< + // Prisma.bani684_site_contentFindManyArgs, + // 'where' + // > + + // const { deleted = false, published = true, hidemenu = false } = + // variables.where || {} /** * Получаем данные компаний */ - return prisma.bani684_site_content - .findMany({ - ...variables, - where, - select: { - id: true, - pagetitle: true, - longtitle: true, - description: true, - alias: true, - uri: true, - content: true, + const query = knex.from(function (this: typeof knex) { + const companiesQuery = this.from( + 'bani684_site_content as company' + ) + .select({ + company_id: 'company.id', + company_uri: 'company.uri', + company_pagetitle: 'company.pagetitle', + company_createdby: 'company.createdby', + company_createdon: 'company.createdon', + company_description: 'company.description', + company_longtitle: 'company.longtitle', + company_published: 'company.published', + company_searchable: 'company.searchable', + company_template: 'company.template', + }) + + /** + * Картинка компании + */ + .leftJoin( + 'bani684_site_tmplvar_contentvalues as tvs_image', + { + 'tvs_image.tmplvarid': TemplateVarIDs.image, + 'tvs_image.contentid': 'company.id', + } + ) + .select('tvs_image.id as company_image_id') + .select('tvs_image.value as company_image') + + /** + * Галерея компании + */ + .leftJoin( + 'bani684_site_tmplvar_contentvalues as tvs_gallery', + { + 'tvs_gallery.tmplvarid': TemplateVarIDs.gallery, + 'tvs_gallery.contentid': 'company.id', + } + ) + .select('tvs_gallery.id as company_gallery_id') + .select('tvs_gallery.value as company_gallery') + + /** + * Координаты + */ + .leftJoin( + 'bani684_site_tmplvar_contentvalues as tvs_coords', + { + 'tvs_coords.tmplvarid': TemplateVarIDs.coords, + 'tvs_coords.contentid': 'company.id', + } + ) + .select('tvs_coords.id as company_coords_id') + .select('tvs_coords.value as company_coords') + + .where({ + template: 27, + deleted: false, published: true, - createdby: true, - createdon: true, - editedby: true, - editedon: true, - template: true, - searchable: true, - TemplateVarValues: { - select: { - id: true, - contentid: true, - tmplvarid: true, - value: true, - }, - }, - }, + hidemenu: false, + }) + + .as('t') + + /** + * Если сортировка по координатам, то берем компании только с координатами + */ + if (orderByCoords) { + companiesQuery.whereNotNull('tvs_coords.id') + } + + return companiesQuery + }) + + // if (limit) { + // query.limit(limit) + // } + + // if (skip) { + // query.offset(skip) + // } + + // console.log('query.toQuery()\n', query.toQuery()) + + return query.then((r) => { + // console.log("r.length", r.length); + + let companies = r.map((n): NexusGenObjects['Company'] => { + const { + // type, + // target_id, + // voteValueAvg, + // voteValueAvg, + + company_id, + company_uri, + company_pagetitle, + company_createdby, + company_createdon, + company_published, + company_searchable, + company_template, + company_description, + company_longtitle, + company_image_id, + company_image, + company_gallery_id, + company_gallery, + company_coords_id, + company_coords, + } = n + + const TemplateVarValues: NexusGenObjects['Company']['TemplateVarValues'] = [] + + if (company_image_id && company_image) { + TemplateVarValues.push({ + id: company_image_id, + tmplvarid: TemplateVarIDs.image, + value: company_image, + contentid: company_id, + }) + } + + if (company_gallery_id && company_gallery) { + TemplateVarValues.push({ + id: company_gallery_id, + tmplvarid: TemplateVarIDs.gallery, + value: company_gallery, + contentid: company_id, + }) + } + + if (company_coords_id && company_coords) { + TemplateVarValues.push({ + id: company_coords_id, + tmplvarid: TemplateVarIDs.coords, + value: company_coords, + contentid: company_id, + }) + } + + return { + id: company_id, + uri: company_uri, + pagetitle: company_pagetitle, + createdby: company_createdby, + createdon: company_createdon, + published: company_published, + searchable: company_searchable, + template: company_template, + description: company_description, + longtitle: company_longtitle, + // image: company_image, + TemplateVarValues, + // type, + // target_id, + // avg: { + // voteValueAvg, + // }, + // Company: { + // }, + } }) - .then((resources) => { - return resources.map((resource) => { - const image = - resource.TemplateVarValues?.find( - (n) => n.tmplvarid === TemplateVarIDs.image - )?.value || null - - return { - ...resource, - image, + + // TODO Надо перенести координаты в отдельные колонки, чтобы можно было + // сортировать на уровне SQL + /** + * Сортировка по координатам + */ + if (orderByCoords) { + const { lat, lng } = orderByCoords + + companies = companies.sort((a, b) => { + const aCoords = coordsResolver(a) + const bCoords = coordsResolver(b) + + if (!aCoords || !bCoords) { + return -1 } + + const { lat: aLat, lng: aLng } = aCoords + + const { lat: bLat, lng: bLng } = bCoords + + const aLatDiff = Math.abs(lat - aLat) + const aLngDiff = Math.abs(lng - aLng) + + const bLatDiff = Math.abs(lat - bLat) + const bLngDiff = Math.abs(lng - bLng) + + const aDiff = Math.sqrt(aLatDiff * aLatDiff + aLngDiff * aLngDiff) + + const bDiff = Math.sqrt(bLatDiff * bLatDiff + bLngDiff * bLngDiff) + + if (aDiff > bDiff) { + return 1 + } else if (bDiff > aDiff) { + return -1 + } + + return 0 }) - }) + } + + // TODO так как сортировка сейчас на уровне JS выполняется, лимиты тоже пока придется здесь делать + if (skip) { + companies = companies.slice(skip) + } + + if (limit) { + companies = companies.slice(0, limit) + } + + return companies + }) } +const CompaniesOrderByCoordsInput = inputObjectType({ + name: 'CompaniesOrderByCoordsInput', + description: 'Сортировка по удаленности от координаты', + definition(t) { + t.nonNull.float('lat') + t.nonNull.float('lng') + }, +}) + +const CompaniesOrderByInput = inputObjectType({ + name: 'CompaniesOrderByInput', + definition(t) { + t.field('coords', { + type: CompaniesOrderByCoordsInput, + }) + }, +}) + export const companies = (t: ObjectDefinitionBlock<'Query'>) => { - // t.nonNull.list.nonNull.field('companies', { - // // alias: 'companies', - // description: 'Компании', - // type: 'Company', - // // ordering: true, - // // filtering: true, - // args: { - // // where: 'bani684_site_contentWhereInput', - // take: 'Int', - // skip: 'Int', - // }, - - t.crud.bani684SiteContents({ - alias: 'companies', + t.nonNull.list.nonNull.field('companies', { description: 'Компании', type: 'Company', - ordering: true, - filtering: true, + args: { + take: intArg(), + skip: intArg(), + orderBy: arg({ + type: CompaniesOrderByInput, + }), + }, resolve: companiesResolver, - // resolve(_, args, ctx) { - // const variables = args as Pick< - // Prisma.bani684_site_contentFindManyArgs, - // 'where' - // > - - // const { deleted = false, published = true, hidemenu = false } = - // variables.where || {} - - // return ctx.prisma.bani684_site_content - // .findMany({ - // ...variables, - // where: { - // AND: [ - // { - // template: 27, - // deleted, - // published, - // hidemenu, - // }, - // { - // ...variables.where, - // }, - // ], - // }, - // select: { - // id: true, - // pagetitle: true, - // longtitle: true, - // description: true, - // alias: true, - // uri: true, - // published: true, - // createdby: true, - // createdon: true, - // editedby: true, - // editedon: true, - // TemplateVarValues: { - // select: { - // id: true, - // contentid: true, - // tmplvarid: true, - // value: true, - // }, - // }, - // }, - // }) - // // .then((records) => - // // records.map((n) => { - // // const { TemplateVarValues } = n - - // // /** - // // * Координаты - // // */ - // // // const coordsTV = TemplateVarValues.find( - // // // (tv) => tv.tmplvarid === 27 - // // // ) - - // // // let coords: NexusGenObjects['Coordinates'] | null = null - - // // // if (coordsTV) { - // // // const arr = coordsTV.value.split(',') - // // // if (arr.length === 2) { - // // // const lat = parseFloat(arr[0]) - // // // const lng = parseFloat(arr[1]) - - // // // if (isFinite(lat) && isFinite(lng)) { - // // // coords = { - // // // lat, - // // // lng, - // // // } - // // // } - // // // } - // // // } - - // // /** - // // * Картинка - // // */ - // // const image = TemplateVarValues.find((tv) => tv.id === 3)?.value - - // // return { - // // ...n, - // // // coords, - // // image, - // // } - // // }) - // // ) - // }, }) } diff --git a/server/nexus/types/Query/definitions/society/Vote/index.ts b/server/nexus/types/Query/definitions/society/Vote/index.ts index f9794fc..07df871 100644 --- a/server/nexus/types/Query/definitions/society/Vote/index.ts +++ b/server/nexus/types/Query/definitions/society/Vote/index.ts @@ -9,6 +9,7 @@ import { ObjectDefinitionBlock } from 'nexus/dist/core' import { TemplateVarIDs } from '../../../../../constants' import { NexusGenObjects } from 'server/nexus/generated/nexus' import { userSelect } from '../../User' +import { CompaniesResult } from '../../Resource/Company' export const votes = (t: ObjectDefinitionBlock<'Query'>) => { t.crud.bani684SocietyVotess({ @@ -81,23 +82,6 @@ export const votes = (t: ObjectDefinitionBlock<'Query'>) => { voteValueAvg: number } - type CompaniesResult = { - company_id: NexusGenObjects['Company']['id'] - company_uri: NexusGenObjects['Company']['uri'] - company_pagetitle: NexusGenObjects['Company']['pagetitle'] - company_createdby: NexusGenObjects['Company']['createdby'] - company_createdon: NexusGenObjects['Company']['createdon'] - company_description: NexusGenObjects['Company']['description'] - company_longtitle: NexusGenObjects['Company']['longtitle'] - company_published: NexusGenObjects['Company']['published'] - company_searchable: NexusGenObjects['Company']['searchable'] - company_template: NexusGenObjects['Company']['template'] - company_image_id: number | undefined - company_image: string | undefined - company_gallery_id: number | undefined - company_gallery: string | undefined - } - const query = knex .from( knex diff --git a/server/nexus/types/Query/resolvers/coords.ts b/server/nexus/types/Query/resolvers/coords.ts index 64d7343..ef64404 100644 --- a/server/nexus/types/Query/resolvers/coords.ts +++ b/server/nexus/types/Query/resolvers/coords.ts @@ -7,7 +7,7 @@ import { TemplateVarIDs } from '../../../constants' */ export const coordsResolver = (parent: SourceValue<'City' | 'Company'>) => { const coordsTV = parent.TemplateVarValues?.find( - (tv) => tv.tmplvarid === TemplateVarIDs.coors + (tv) => tv.tmplvarid === TemplateVarIDs.coords ) let coords: NexusGenObjects['Coordinates'] | null = null diff --git a/src/gql/Query/company.graphql b/src/gql/Query/company.graphql index 731f241..487ee63 100644 --- a/src/gql/Query/company.graphql +++ b/src/gql/Query/company.graphql @@ -6,8 +6,9 @@ query companies( # $companiesCenter: InputCoordsType $skip: Int $take: Int - $where: bani684_site_contentWhereInput - $orderBy: [bani684_site_contentOrderByInput!] + # $where: bani684_site_contentWhereInput + # $orderBy: [bani684_site_contentOrderByInput!] + $orderBy: CompaniesOrderByInput $withContent: Boolean = false ) { # companiesList( @@ -26,7 +27,7 @@ query companies( # ...ListCompany # } # } - companies(skip: $skip, take: $take, where: $where, orderBy: $orderBy) { + companies(skip: $skip, take: $take, orderBy: $orderBy) { ...Company_ } } diff --git a/src/modules/gql/generated/companies.ts b/src/modules/gql/generated/companies.ts index c28bb75..f5ac8ff 100644 --- a/src/modules/gql/generated/companies.ts +++ b/src/modules/gql/generated/companies.ts @@ -17,8 +17,7 @@ const defaultOptions = {} export type CompaniesQueryVariables = Types.Exact<{ skip?: Types.Maybe; take?: Types.Maybe; - where?: Types.Maybe; - orderBy?: Types.Maybe | Types.Bani684SiteContentOrderByInput>; + orderBy?: Types.Maybe; withContent?: Types.Maybe; }>; @@ -30,8 +29,8 @@ export type CompaniesQuery = { __typename?: 'Query', companies: Array<( export const CompaniesDocument = gql` - query companies($skip: Int, $take: Int, $where: bani684_site_contentWhereInput, $orderBy: [bani684_site_contentOrderByInput!], $withContent: Boolean = false) { - companies(skip: $skip, take: $take, where: $where, orderBy: $orderBy) { + query companies($skip: Int, $take: Int, $orderBy: CompaniesOrderByInput, $withContent: Boolean = false) { + companies(skip: $skip, take: $take, orderBy: $orderBy) { ...Company_ } } @@ -51,7 +50,6 @@ export const CompaniesDocument = gql` * variables: { * skip: // value for 'skip' * take: // value for 'take' - * where: // value for 'where' * orderBy: // value for 'orderBy' * withContent: // value for 'withContent' * }, diff --git a/src/modules/gql/generated/schema.json b/src/modules/gql/generated/schema.json index de841bb..4d03791 100644 --- a/src/modules/gql/generated/schema.json +++ b/src/modules/gql/generated/schema.json @@ -639,6 +639,82 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "INPUT_OBJECT", + "name": "CompaniesOrderByCoordsInput", + "description": "Сортировка по удаленности от координаты", + "fields": null, + "inputFields": [ + { + "name": "lat", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Float", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "lng", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Float", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Float", + "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "CompaniesOrderByInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "coords", + "description": null, + "type": { + "kind": "INPUT_OBJECT", + "name": "CompaniesOrderByCoordsInput", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "Company", @@ -1055,16 +1131,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, { "kind": "SCALAR", "name": "DateTime", @@ -2942,37 +3008,17 @@ "description": "Компании", "args": [ { - "name": "cursor", + "name": "orderBy", "description": null, "type": { "kind": "INPUT_OBJECT", - "name": "bani684_site_contentWhereUniqueInput", + "name": "CompaniesOrderByInput", "ofType": null }, "defaultValue": null, "isDeprecated": false, "deprecationReason": null }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "bani684_site_contentOrderByInput", - "ofType": null - } - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "skip", "description": null, @@ -2996,18 +3042,6 @@ "defaultValue": null, "isDeprecated": false, "deprecationReason": null - }, - { - "name": "where", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "bani684_site_contentWhereInput", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null } ], "type": { diff --git a/src/modules/gql/generated/types.ts b/src/modules/gql/generated/types.ts index 4901a7c..562524b 100644 --- a/src/modules/gql/generated/types.ts +++ b/src/modules/gql/generated/types.ts @@ -89,6 +89,16 @@ export interface Comment { text?: Maybe; } +/** Сортировка по удаленности от координаты */ +export interface CompaniesOrderByCoordsInput { + lat: Scalars['Float']; + lng: Scalars['Float']; +} + +export interface CompaniesOrderByInput { + coords?: Maybe; +} + /** Компания */ export interface Company extends ResourceInterface { __typename?: 'Company'; @@ -338,11 +348,9 @@ export type QueryCommentsCountArgs = { export type QueryCompaniesArgs = { - cursor?: Maybe; - orderBy?: Maybe>; + orderBy?: Maybe; skip?: Maybe; take?: Maybe; - where?: Maybe; };