feathersjs / feathers

The API and real-time application framework
https://feathersjs.com
MIT License
15.07k stars 751 forks source link

Typebox QuerySchema - Querying array mongoDB #3052

Closed martinfruehmorgen closed 1 year ago

martinfruehmorgen commented 1 year ago

My feathers version is 5.0.0-pre.37

My service schema is:

import { resolve } from '@feathersjs/schema'
import { Type, getValidator, querySyntax } from '@feathersjs/typebox'
import { dataValidator, queryValidator } from '../../validators.js'

// Main data model schema
export const contactsSchema = Type.Object(
  {
    _id: Type.String({ objectid: true }),
    contactTags: Type.Array(Type.Number(), { default: [] }),
    deletable: Type.Boolean({ default: true, description: 'is entry deletable' })
  },
  { $id: 'Contacts', additionalProperties: false }
)
export const contactsValidator = getValidator(contactsSchema, dataValidator)
export const contactsResolver = resolve({})

export const contactsExternalResolver = resolve({})

// Schema for creating new entries
export const contactsDataSchema = Type.Pick(contactsSchema, ['contactTags', 'deletable'], {
  $id: 'ContactsData'
})
export const contactsDataValidator = getValidator(contactsDataSchema, dataValidator)
export const contactsDataResolver = resolve({})

// Schema for updating existing entries
export const contactsPatchSchema = Type.Partial(contactsDataSchema, {
  $id: 'ContactsPatch'
})
export const contactsPatchValidator = getValidator(contactsPatchSchema, dataValidator)
export const contactsPatchResolver = resolve({})

// Schema for allowed query properties
export const contactsQueryProperties = Type.Pick(contactsSchema, ['contactTags', 'deletable'])
export const contactsQuerySchema = Type.Intersect(
  [
    querySyntax(contactsQueryProperties),
    // Add additional query properties here
    Type.Object(
      {
        contactTags: Type.Number()
      },
      { additionalProperties: false }
    )
  ],
  { additionalProperties: false }
)
export const contactsQueryValidator = getValidator(contactsQuerySchema, queryValidator)
export const contactsQueryResolver = resolve({})`

The query I want to perform is: http://localhost:3032/contacts?$or[1][contactTags]=1&$or[0][deletable]=true

query: {
          $or: [{ contactTags: 1 }, { deletable: true }]
        }

What works is http://localhost:3032/contacts?contactTags=1

query: {
          contactTags: 1
        }

But when using the query with $or, the contactTags: Type.Number() (which is necessary to have the query working without $or) seems not to be passed to the query validator.

The error is:

{
    "name": "BadRequest",
    "message": "validation failed",
    "code": 400,
    "className": "bad-request",
    "data": [
        {
            "instancePath": "/$or/1/contactTags",
            "schemaPath": "#/properties/%24or/items/properties/contactTags/anyOf/0/type",
            "keyword": "type",
            "params": {
                "type": "array"
            },
            "message": "must be array"
        },
        {
            "instancePath": "/$or/1/contactTags",
            "schemaPath": "#/properties/%24or/items/properties/contactTags/anyOf/1/type",
            "keyword": "type",
            "params": {
                "type": "object"
            },
            "message": "must be object"
        },
        {
            "instancePath": "/$or/1/contactTags",
            "schemaPath": "#/properties/%24or/items/properties/contactTags/anyOf",
            "keyword": "anyOf",
            "params": {},
            "message": "must match a schema in anyOf"
        }
    ]
}

Perhaps I need to adjust the querySyntax with expanding $or? But how?