From 6c45914b8ad769c8abeef13833d8d613fee362bd Mon Sep 17 00:00:00 2001 From: Nicola Krumschmidt Date: Mon, 9 Oct 2023 16:12:42 +0200 Subject: [PATCH] Split up related field node type in data abstraction layer (#19942) * Fix casing in file names * Refactor file structure * Split up related field node * formatter * renamed fields-node.ts to fields.ts * Small grammar fix in comment Co-authored-by: Jan Arends --------- Co-authored-by: Jan Arends Co-authored-by: Pascal Jufer --- .../data-driver-postgres/src/index.test.ts | 21 ++-- .../fields/create-join.test.ts | 23 +--- .../src/query-converter/fields/create-join.ts | 11 +- .../src/query-converter/fields/fields.test.ts | 25 ++-- .../src/query-converter/fields/fields.ts | 24 ++-- .../src/{index.test.ts => engine.test.ts} | 8 +- packages/data/src/engine.ts | 39 +++++++ packages/data/src/index.ts | 40 +------ .../{abstract-query => }/abstract-query.ts | 10 +- .../fields/{fieldNodes.ts => fields.ts} | 7 +- .../src/types/abstract-query/fields/index.ts | 5 + .../src/types/abstract-query/fields/nested.ts | 29 +++++ .../abstract-query/fields/nested/index.ts | 1 + .../fields/nested/relational.ts | 77 ++++++++++++ .../types/abstract-query/fields/related.ts | 110 ------------------ .../data/src/types/abstract-query/index.ts | 3 + .../src/types/abstract-query/modifiers.ts | 14 +++ .../types/abstract-query/modifiers/filters.ts | 5 + .../modifiers/filters/conditions.ts | 37 ++++++ .../filters/conditions/geo-condition-bbox.ts | 1 + .../filters/conditions/geo-condition.ts | 3 +- .../modifiers/filters/conditions/index.ts | 40 +------ .../abstract-query/modifiers/filters/index.ts | 8 +- .../modifiers/filters/logical.ts | 2 +- .../modifiers/filters/negate.ts | 2 +- .../modifiers/filters/quantifier.ts | 13 +++ .../types/abstract-query/modifiers/index.ts | 18 +-- packages/data/src/types/driver.ts | 3 +- packages/data/src/types/index.ts | 3 +- 29 files changed, 298 insertions(+), 284 deletions(-) rename packages/data/src/{index.test.ts => engine.test.ts} (91%) create mode 100644 packages/data/src/engine.ts rename packages/data/src/types/{abstract-query => }/abstract-query.ts (69%) rename packages/data/src/types/abstract-query/fields/{fieldNodes.ts => fields.ts} (57%) create mode 100644 packages/data/src/types/abstract-query/fields/index.ts create mode 100644 packages/data/src/types/abstract-query/fields/nested.ts create mode 100644 packages/data/src/types/abstract-query/fields/nested/index.ts create mode 100644 packages/data/src/types/abstract-query/fields/nested/relational.ts delete mode 100644 packages/data/src/types/abstract-query/fields/related.ts create mode 100644 packages/data/src/types/abstract-query/index.ts create mode 100644 packages/data/src/types/abstract-query/modifiers.ts create mode 100644 packages/data/src/types/abstract-query/modifiers/filters.ts create mode 100644 packages/data/src/types/abstract-query/modifiers/filters/conditions.ts create mode 100644 packages/data/src/types/abstract-query/modifiers/filters/quantifier.ts diff --git a/packages/data-driver-postgres/src/index.test.ts b/packages/data-driver-postgres/src/index.test.ts index d7fda9fd78..2030859378 100644 --- a/packages/data-driver-postgres/src/index.test.ts +++ b/packages/data-driver-postgres/src/index.test.ts @@ -125,7 +125,7 @@ describe('querying the driver', () => { alias: secondFieldAlias, }, { - type: 'm2o', + type: 'nested-one', fields: [ { type: 'primitive', @@ -137,14 +137,17 @@ describe('querying the driver', () => { field: joinField2, }, ], - join: { - current: { - fields: [fk], - }, - external: { - store: 'randomDataStore1', - collection: randomCollectionToJoin, - fields: [foreignPk], + meta: { + type: 'm2o', + join: { + current: { + fields: [fk], + }, + external: { + store: 'randomDataStore1', + collection: randomCollectionToJoin, + fields: [foreignPk], + }, }, }, alias: joinAlias, diff --git a/packages/data-sql/src/query-converter/fields/create-join.test.ts b/packages/data-sql/src/query-converter/fields/create-join.test.ts index 1e3f5f3439..bf18d9d954 100644 --- a/packages/data-sql/src/query-converter/fields/create-join.test.ts +++ b/packages/data-sql/src/query-converter/fields/create-join.test.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest'; import { randomIdentifier } from '@directus/random'; -import type { AbstractQueryFieldNodeRelatedManyToOne } from '@directus/data'; +import type { AbstractQueryFieldNodeRelationalManyToOne } from '@directus/data'; import { createJoin } from './create-join.js'; import type { AbstractSqlQueryJoinNode } from '../../types/clauses/joins/join.js'; @@ -10,10 +10,9 @@ test('Convert m2o relation on single field ', () => { const randomExternalCollection = randomIdentifier(); const randomExternalStore = randomIdentifier(); const randomExternalField = randomIdentifier(); - const randomExternalSelectField = randomIdentifier(); const randomAlias = randomIdentifier(); - const node: AbstractQueryFieldNodeRelatedManyToOne = { + const node: AbstractQueryFieldNodeRelationalManyToOne = { type: 'm2o', join: { current: { @@ -25,12 +24,6 @@ test('Convert m2o relation on single field ', () => { fields: [randomExternalField], }, }, - fields: [ - { - type: 'primitive', - field: randomExternalSelectField, - }, - ], }; const expected: AbstractSqlQueryJoinNode = { @@ -68,11 +61,10 @@ test('Convert m2o relation with composite keys', () => { const randomExternalStore = randomIdentifier(); const randomExternalField = randomIdentifier(); const randomExternalField2 = randomIdentifier(); - const randomExternalSelectField = randomIdentifier(); const randomGeneratedAlias = randomIdentifier(); const randomUserAlias = randomIdentifier(); - const node: AbstractQueryFieldNodeRelatedManyToOne = { + const node: AbstractQueryFieldNodeRelationalManyToOne = { type: 'm2o', join: { current: { @@ -84,13 +76,6 @@ test('Convert m2o relation with composite keys', () => { fields: [randomExternalField, randomExternalField2], }, }, - fields: [ - { - type: 'primitive', - field: randomExternalSelectField, - }, - ], - alias: randomUserAlias, }; const expected: AbstractSqlQueryJoinNode = { @@ -143,5 +128,5 @@ test('Convert m2o relation with composite keys', () => { alias: randomUserAlias, }; - expect(createJoin(randomCurrentCollection, node, randomGeneratedAlias)).toStrictEqual(expected); + expect(createJoin(randomCurrentCollection, node, randomGeneratedAlias, randomUserAlias)).toStrictEqual(expected); }); diff --git a/packages/data-sql/src/query-converter/fields/create-join.ts b/packages/data-sql/src/query-converter/fields/create-join.ts index b009e89787..6b283c55e6 100644 --- a/packages/data-sql/src/query-converter/fields/create-join.ts +++ b/packages/data-sql/src/query-converter/fields/create-join.ts @@ -1,11 +1,12 @@ -import type { AbstractQueryFieldNodeRelatedManyToOne } from '@directus/data'; +import type { AbstractQueryFieldNodeRelationalManyToOne } from '@directus/data'; import type { AbstractSqlQueryConditionNode, AbstractSqlQueryLogicalNode } from '../../types/index.js'; import type { AbstractSqlQueryJoinNode } from '../../types/index.js'; export const createJoin = ( currentCollection: string, - relationalField: AbstractQueryFieldNodeRelatedManyToOne, - externalCollectionAlias: string + relationalField: AbstractQueryFieldNodeRelationalManyToOne, + externalCollectionAlias: string, + fieldAlias?: string ): AbstractSqlQueryJoinNode => { let on: AbstractSqlQueryLogicalNode | AbstractSqlQueryConditionNode; @@ -40,8 +41,8 @@ export const createJoin = ( on, }; - if (relationalField.alias) { - result.alias = relationalField.alias; + if (fieldAlias) { + result.alias = fieldAlias; } return result; diff --git a/packages/data-sql/src/query-converter/fields/fields.test.ts b/packages/data-sql/src/query-converter/fields/fields.test.ts index 4ab8ef5f1e..4c0a7b0b3b 100644 --- a/packages/data-sql/src/query-converter/fields/fields.test.ts +++ b/packages/data-sql/src/query-converter/fields/fields.test.ts @@ -132,23 +132,26 @@ test('primitive, fn, m2o', () => { field: randomPrimitiveField1, }, { - type: 'm2o', - join: { - current: { - fields: [randomJoinCurrentField], - }, - external: { - store: randomExternalStore, - collection: randomExternalCollection, - fields: [randomExternalField], - }, - }, + type: 'nested-one', fields: [ { type: 'primitive', field: randomJoinNodeField, }, ], + meta: { + type: 'm2o', + join: { + current: { + fields: [randomJoinCurrentField], + }, + external: { + store: randomExternalStore, + collection: randomExternalCollection, + fields: [randomExternalField], + }, + }, + }, }, { type: 'fn', diff --git a/packages/data-sql/src/query-converter/fields/fields.ts b/packages/data-sql/src/query-converter/fields/fields.ts index 1939677be0..592f2a1427 100644 --- a/packages/data-sql/src/query-converter/fields/fields.ts +++ b/packages/data-sql/src/query-converter/fields/fields.ts @@ -50,7 +50,7 @@ export const convertFieldNodes = ( continue; } - if (abstractField.type === 'm2o') { + if (abstractField.type === 'nested-one') { /** * Always fetch the current context foreign key as well. We need it to check if the current * item has a related item so we don't expand `null` values in a nested object where every @@ -59,18 +59,20 @@ export const convertFieldNodes = ( * @TODO */ - const m2oField = abstractField; - const externalCollectionAlias = createUniqueAlias(m2oField.join.external.collection); - const sqlJoinNode = createJoin(collection, m2oField, externalCollectionAlias); + if (abstractField.meta.type === 'm2o') { + const externalCollectionAlias = createUniqueAlias(abstractField.meta.join.external.collection); + const sqlJoinNode = createJoin(collection, abstractField.meta, externalCollectionAlias, abstractField.alias); - const nestedOutput = convertFieldNodes(externalCollectionAlias, abstractField.fields, idxGenerator, [ - ...currentPath, - abstractField.join.external.collection, - ]); + const nestedOutput = convertFieldNodes(externalCollectionAlias, abstractField.fields, idxGenerator, [ + ...currentPath, + abstractField.meta.join.external.collection, + ]); + + nestedOutput.aliasMapping.forEach((value, key) => aliasRelationalMapping.set(key, value)); + joins.push(sqlJoinNode); + select.push(...nestedOutput.clauses.select); + } - nestedOutput.aliasMapping.forEach((value, key) => aliasRelationalMapping.set(key, value)); - joins.push(sqlJoinNode); - select.push(...nestedOutput.clauses.select); continue; } diff --git a/packages/data/src/index.test.ts b/packages/data/src/engine.test.ts similarity index 91% rename from packages/data/src/index.test.ts rename to packages/data/src/engine.test.ts index 80f760f7d0..e549fef8f5 100644 --- a/packages/data/src/index.test.ts +++ b/packages/data/src/engine.test.ts @@ -1,7 +1,9 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import type { AbstractQuery, DataDriver } from './index.js'; -import { DataEngine } from './index.js'; import { randomIdentifier } from '@directus/random'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; + +import { DataEngine } from './engine.js'; +import type { AbstractQuery } from './types/abstract-query.js'; +import type { DataDriver } from './types/driver.js'; let engine: DataEngine; diff --git a/packages/data/src/engine.ts b/packages/data/src/engine.ts new file mode 100644 index 0000000000..5805c5ad83 --- /dev/null +++ b/packages/data/src/engine.ts @@ -0,0 +1,39 @@ +import type { ReadableStream } from 'node:stream/web'; + +import type { AbstractQuery } from './types/abstract-query.js'; +import type { DataDriver } from './types/driver.js'; + +export class DataEngine { + #stores: Map; + + constructor() { + this.#stores = new Map(); + } + + /** Registers a new data store for use in queries */ + async registerStore(name: string, driver: DataDriver) { + await driver.register?.(); + this.#stores.set(name, driver); + } + + /** Access the driver of a given store. Errors if it hasn't been registered */ + store(name: string): DataDriver { + const store = this.#stores.get(name); + + if (!store) { + throw new Error(`Store "${name}" doesn't exist.`); + } + + return store; + } + + /** Execute a root abstract query */ + async query(query: AbstractQuery): Promise { + return this.store(query.store).query(query); + } + + /** Gracefully shutdown connected drivers */ + async destroy() { + await Promise.all(Array.from(this.#stores.values()).map((driver) => driver.destroy?.())); + } +} diff --git a/packages/data/src/index.ts b/packages/data/src/index.ts index 74a04c175e..1a554b9e17 100644 --- a/packages/data/src/index.ts +++ b/packages/data/src/index.ts @@ -1,40 +1,2 @@ -import type { ReadableStream } from 'node:stream/web'; -import type { AbstractQuery } from './types/abstract-query/abstract-query.js'; -import type { DataDriver } from './types/driver.js'; - -export class DataEngine { - #stores: Map; - - constructor() { - this.#stores = new Map(); - } - - /** Registers a new data store for use in queries */ - async registerStore(name: string, driver: DataDriver) { - await driver.register?.(); - this.#stores.set(name, driver); - } - - /** Access the driver of a given store. Errors if it hasn't been registered */ - store(name: string): DataDriver { - const store = this.#stores.get(name); - - if (!store) { - throw new Error(`Store "${name}" doesn't exist.`); - } - - return store; - } - - /** Execute a root abstract query */ - async query(query: AbstractQuery): Promise { - return this.store(query.store).query(query); - } - - /** Gracefully shutdown connected drivers */ - async destroy() { - await Promise.all(Array.from(this.#stores.values()).map((driver) => driver.destroy?.())); - } -} - +export type * from './engine.js'; export type * from './types/index.js'; diff --git a/packages/data/src/types/abstract-query/abstract-query.ts b/packages/data/src/types/abstract-query.ts similarity index 69% rename from packages/data/src/types/abstract-query/abstract-query.ts rename to packages/data/src/types/abstract-query.ts index e1f1613ddc..00ae7251be 100644 --- a/packages/data/src/types/abstract-query/abstract-query.ts +++ b/packages/data/src/types/abstract-query.ts @@ -4,8 +4,8 @@ * * @module abstract-query */ -import type { AbstractQueryModifiers } from './modifiers/index.js'; -import type { AbstractQueryFieldNode } from './fields/fieldNodes.js'; +import type { AbstractQueryFieldNode } from './abstract-query/fields/fields.js'; +import type { AbstractQueryModifiers } from './abstract-query/modifiers.js'; /** * The abstract root query @@ -34,9 +34,3 @@ export interface AbstractQuery { * @TODO * - Rethink every / some */ - -export * from './modifiers/index.js'; -export * from './fields/function.js'; -export * from './fields/primitive.js'; -export * from './fields/related.js'; -export * from './fields/fieldNodes.js'; diff --git a/packages/data/src/types/abstract-query/fields/fieldNodes.ts b/packages/data/src/types/abstract-query/fields/fields.ts similarity index 57% rename from packages/data/src/types/abstract-query/fields/fieldNodes.ts rename to packages/data/src/types/abstract-query/fields/fields.ts index 84d7805d74..68a0477937 100644 --- a/packages/data/src/types/abstract-query/fields/fieldNodes.ts +++ b/packages/data/src/types/abstract-query/fields/fields.ts @@ -1,8 +1,9 @@ -import type { AbstractQueryFieldNodePrimitive } from './primitive.js'; import type { AbstractQueryFieldNodeFn } from './function.js'; -import type { AbstractQueryFieldNodeRelated } from './related.js'; +import type { AbstractQueryFieldNodeNestedMany, AbstractQueryFieldNodeNestedOne } from './nested.js'; +import type { AbstractQueryFieldNodePrimitive } from './primitive.js'; export type AbstractQueryFieldNode = | AbstractQueryFieldNodePrimitive | AbstractQueryFieldNodeFn - | AbstractQueryFieldNodeRelated; + | AbstractQueryFieldNodeNestedMany + | AbstractQueryFieldNodeNestedOne; diff --git a/packages/data/src/types/abstract-query/fields/index.ts b/packages/data/src/types/abstract-query/fields/index.ts new file mode 100644 index 0000000000..55086c17ce --- /dev/null +++ b/packages/data/src/types/abstract-query/fields/index.ts @@ -0,0 +1,5 @@ +export * from './fields.js'; +export * from './function.js'; +export * from './nested.js'; +export * from './nested/index.js'; +export * from './primitive.js'; diff --git a/packages/data/src/types/abstract-query/fields/nested.ts b/packages/data/src/types/abstract-query/fields/nested.ts new file mode 100644 index 0000000000..0bc4f2bea4 --- /dev/null +++ b/packages/data/src/types/abstract-query/fields/nested.ts @@ -0,0 +1,29 @@ +import type { AbstractQueryModifiers } from '../modifiers.js'; +import type { AbstractQueryFieldNode } from './fields.js'; +import type { + AbstractQueryFieldNodeNestedRelationalMany, + AbstractQueryFieldNodeNestedRelationalOne, +} from './nested/relational.js'; + +export interface AbstractQueryFieldNodeNestedOne { + type: 'nested-one'; + + /* From the related collection the user can pick primitives, apply a function or add another nested node */ + fields: AbstractQueryFieldNode[]; + alias?: string; + + meta: AbstractQueryFieldNodeNestedRelationalOne; // AbstractQueryFieldNodeNestedObjectOne | AbstractQueryFieldNodeNestedJsonOne +} + +export interface AbstractQueryFieldNodeNestedMany { + type: 'nested-many'; + + /* From the related collection the user can pick primitives, apply a function or add another nested node */ + fields: AbstractQueryFieldNode[]; + alias?: string; + + /** For many, it's always possible to add modifiers to the foreign collection to adjust the results. */ + modifiers?: AbstractQueryModifiers; + + meta: AbstractQueryFieldNodeNestedRelationalMany; // AbstractQueryFieldNodeNestedObjectMany | AbstractQueryFieldNodeNestedJsonMany +} diff --git a/packages/data/src/types/abstract-query/fields/nested/index.ts b/packages/data/src/types/abstract-query/fields/nested/index.ts new file mode 100644 index 0000000000..e2850d3ec8 --- /dev/null +++ b/packages/data/src/types/abstract-query/fields/nested/index.ts @@ -0,0 +1 @@ +export * from './relational.js'; diff --git a/packages/data/src/types/abstract-query/fields/nested/relational.ts b/packages/data/src/types/abstract-query/fields/nested/relational.ts new file mode 100644 index 0000000000..f60dda2844 --- /dev/null +++ b/packages/data/src/types/abstract-query/fields/nested/relational.ts @@ -0,0 +1,77 @@ +/** + * Used to build a relational query for m2o and a2o relations. + */ +export type AbstractQueryFieldNodeNestedRelationalOne = + | AbstractQueryFieldNodeRelationalManyToOne + | AbstractQueryFieldNodeRelationalAnyToOne; + +/** + * Used to build a relational query for o2m and o2a relations. + */ +export type AbstractQueryFieldNodeNestedRelationalMany = + | AbstractQueryFieldNodeRelationalOneToMany + | AbstractQueryFieldNodeRelationalOneToAny; + +export interface AbstractQueryFieldNodeRelationalManyToOne { + type: 'm2o'; + + join: AbstractQueryFieldNodeRelationalJoinMany; +} + +export interface AbstractQueryFieldNodeRelationalOneToMany { + type: 'o2m'; + + join: AbstractQueryFieldNodeRelationalJoinMany; +} + +export interface AbstractQueryFieldNodeRelationalAnyToOne { + type: 'a2o'; + + join: AbstractQueryFieldNodeRelationalJoinAny; +} + +export interface AbstractQueryFieldNodeRelationalOneToAny { + type: 'o2a'; + + join: AbstractQueryFieldNodeRelationalJoinAny; +} + +/** + * Used to build a relational query for m2o and o2m relations. + * @example + * ``` + * const functionNode = { + * current: { + * fields: ['id'] + * }, + * external: { + * store: 'mongodb', + * collection: 'some-collection', + * } + * ``` + */ +export interface AbstractQueryFieldNodeRelationalJoinMany { + /** the fields of the current collection which have the relational value to an external collection or item */ + current: { + fields: [string, ...string[]]; + }; + + /** the external collection or item which should be pulled/joined/merged into the current collection */ + external: { + store?: string; + collection: string; + fields: [string, ...string[]]; + }; +} + +export interface AbstractQueryFieldNodeRelationalJoinAny { + current: { + collectionField: string; + fields: [string, ...string[]]; + }; + + external: { + store?: string; + fields: [string, ...string[]]; + }; +} diff --git a/packages/data/src/types/abstract-query/fields/related.ts b/packages/data/src/types/abstract-query/fields/related.ts deleted file mode 100644 index 70d84fbd60..0000000000 --- a/packages/data/src/types/abstract-query/fields/related.ts +++ /dev/null @@ -1,110 +0,0 @@ -/** - * This file will be split up into multiple files soon. - */ -import type { AbstractQueryModifiers } from '../modifiers/index.js'; -import type { AbstractQueryFieldNodePrimitive } from './primitive.js'; -import type { AbstractQueryFieldNodeFn } from './function.js'; - -/** - * This is a basic interface for all relational field types. - */ -export interface AbstractQueryFieldNodeRelatedBase { - /* From the related collection the user can pick primitives, apply a function or add another relational node */ - fields: (AbstractQueryFieldNodePrimitive | AbstractQueryFieldNodeFn | AbstractQueryFieldNodeRelated)[]; - - /** Regardless of the type of the relationship, it always possible to add modifiers to the foreign collection to adjust the results. */ - modifiers?: AbstractQueryModifiers; - - alias?: string; -} - -/** - * Used to build a relational query for m2o and o2m relations. - */ -export type AbstractQueryFieldNodeRelated = - | AbstractQueryFieldNodeRelatedManyToOne - | AbstractQueryFieldNodeRelatedOneToMany - | AbstractQueryFieldNodeRelatedAnyToOne - | AbstractQueryFieldNodeRelatedOneToAny; - -/** - * Used to build a relational query for m2o and o2m relations. - * @example - * ``` - * const functionNode = { - * current: { - * fields: ['id'] - * }, - * external: { - * store: 'mongodb', - * collection: 'some-collection', - * } - * ``` - */ -export interface AbstractQueryFieldNodeRelatedJoinMany { - /** the field of the current collection which has the relational value to an external collection or item */ - current: { - fields: [string, ...string[]]; - }; - - /** the external collection or item which should be pulled/joined/merged into the current collection */ - external: { - store?: string; - collection: string; - fields: [string, ...string[]]; - }; -} - -export interface AbstractQueryFieldNodeRelatedJoinAny { - current: { - collectionField: string; - fields: [string, ...string[]]; - }; - - external: { - store?: string; - fields: [string, ...string[]]; - }; -} - -export interface AbstractQueryFieldNodeRelatedManyToOne extends AbstractQueryFieldNodeRelatedBase { - type: 'm2o'; - - join: AbstractQueryFieldNodeRelatedJoinMany; -} - -export interface AbstractQueryFieldNodeRelatedOneToMany extends AbstractQueryFieldNodeRelatedBase { - type: 'o2m'; - // maybe every here - join: AbstractQueryFieldNodeRelatedJoinMany; -} - -export interface AbstractQueryFieldNodeRelatedAnyToOne extends AbstractQueryFieldNodeRelatedBase { - type: 'a2o'; - - join: AbstractQueryFieldNodeRelatedJoinAny; -} - -export interface AbstractQueryFieldNodeRelatedOneToAny extends AbstractQueryFieldNodeRelatedBase { - type: 'o2a'; - - join: AbstractQueryFieldNodeRelatedJoinAny; -} - -/** - * Continue on it after relationships - * @deprecated Those information will probably go within the o2m relational node - **/ -export interface AbstractQueryQuantifierNode { - type: 'quantifier'; - operator: 'every' | 'some'; - - /** The o2m field that the every/some should be applied on */ - target: AbstractQueryFieldNodeRelatedOneToMany | AbstractQueryFieldNodeRelatedOneToAny; - - /** An alias to reference the o2m item */ - alias: string; - - /** the values for the the operation. */ - // childNode: AbstractQueryConditionNode | AbstractQueryNodeLogical | AbstractQueryNodeNegate; -} diff --git a/packages/data/src/types/abstract-query/index.ts b/packages/data/src/types/abstract-query/index.ts new file mode 100644 index 0000000000..8a9703883d --- /dev/null +++ b/packages/data/src/types/abstract-query/index.ts @@ -0,0 +1,3 @@ +export * from './fields/index.js'; +export * from './modifiers.js'; +export * from './modifiers/index.js'; diff --git a/packages/data/src/types/abstract-query/modifiers.ts b/packages/data/src/types/abstract-query/modifiers.ts new file mode 100644 index 0000000000..73207f9d0e --- /dev/null +++ b/packages/data/src/types/abstract-query/modifiers.ts @@ -0,0 +1,14 @@ +import type { AbstractQueryFilterNode } from './modifiers/filters.js'; +import type { AbstractQueryNodeLimit } from './modifiers/limit.js'; +import type { AbstractQueryNodeOffset } from './modifiers/offset.js'; +import type { AbstractQueryNodeSort } from './modifiers/sort.js'; + +/** + * Optional attributes to customize the query results + */ +export interface AbstractQueryModifiers { + limit?: AbstractQueryNodeLimit; + offset?: AbstractQueryNodeOffset; + sort?: AbstractQueryNodeSort[]; + filter?: AbstractQueryFilterNode; +} diff --git a/packages/data/src/types/abstract-query/modifiers/filters.ts b/packages/data/src/types/abstract-query/modifiers/filters.ts new file mode 100644 index 0000000000..d76787e779 --- /dev/null +++ b/packages/data/src/types/abstract-query/modifiers/filters.ts @@ -0,0 +1,5 @@ +import type { AbstractQueryConditionNode } from './filters/conditions.js'; +import type { AbstractQueryNodeLogical } from './filters/logical.js'; +import type { AbstractQueryNodeNegate } from './filters/negate.js'; + +export type AbstractQueryFilterNode = AbstractQueryConditionNode | AbstractQueryNodeLogical | AbstractQueryNodeNegate; diff --git a/packages/data/src/types/abstract-query/modifiers/filters/conditions.ts b/packages/data/src/types/abstract-query/modifiers/filters/conditions.ts new file mode 100644 index 0000000000..6d6433e232 --- /dev/null +++ b/packages/data/src/types/abstract-query/modifiers/filters/conditions.ts @@ -0,0 +1,37 @@ +import type { ConditionFieldNode } from './conditions/field-condition.js'; +import type { ConditionGeoIntersectsBBoxNode } from './conditions/geo-condition-bbox.js'; +import type { ConditionGeoIntersectsNode } from './conditions/geo-condition.js'; +import type { ConditionNumberNode } from './conditions/number-condition.js'; +import type { ConditionSetNode } from './conditions/set-condition.js'; +import type { ConditionStringNode } from './conditions/string-condition.js'; + +/** + * Used to specify a condition on a query. + * Note: No explicit support to check for 'empty' (it's just an empty string) and null. + * + * @example + * ``` + * { + * type: 'condition', + * condition: {...} + * }, + * ``` + */ +export interface AbstractQueryConditionNode { + type: 'condition'; + condition: ActualConditionNodes; +} + +/** + * Possible nodes which specify the condition. + * + * @todo The API should make sure, that the type of the targeting column has the correct type, + * so that f.e. a condition-string will only be applied to a column of type string. + */ +export type ActualConditionNodes = + | ConditionStringNode + | ConditionNumberNode + | ConditionGeoIntersectsNode + | ConditionGeoIntersectsBBoxNode + | ConditionSetNode + | ConditionFieldNode; diff --git a/packages/data/src/types/abstract-query/modifiers/filters/conditions/geo-condition-bbox.ts b/packages/data/src/types/abstract-query/modifiers/filters/conditions/geo-condition-bbox.ts index 8f5f80c935..e2ecae21f2 100644 --- a/packages/data/src/types/abstract-query/modifiers/filters/conditions/geo-condition-bbox.ts +++ b/packages/data/src/types/abstract-query/modifiers/filters/conditions/geo-condition-bbox.ts @@ -1,4 +1,5 @@ import type { GeoJSONGeometryCollection, GeoJSONMultiPolygon, GeoJSONPolygon } from 'wellknown'; + import type { AbstractQueryFieldNodePrimitive } from '../../../fields/primitive.js'; /** diff --git a/packages/data/src/types/abstract-query/modifiers/filters/conditions/geo-condition.ts b/packages/data/src/types/abstract-query/modifiers/filters/conditions/geo-condition.ts index e13d867bc2..ee33f55cc6 100644 --- a/packages/data/src/types/abstract-query/modifiers/filters/conditions/geo-condition.ts +++ b/packages/data/src/types/abstract-query/modifiers/filters/conditions/geo-condition.ts @@ -1,4 +1,3 @@ -import type { AbstractQueryFieldNodePrimitive } from '../../../fields/primitive.js'; import type { GeoJSONGeometryCollection, GeoJSONLineString, @@ -7,6 +6,8 @@ import type { GeoJSONPoint, } from 'wellknown'; +import type { AbstractQueryFieldNodePrimitive } from '../../../fields/primitive.js'; + /** * Checks if a non box geo object intersects with another. * @example diff --git a/packages/data/src/types/abstract-query/modifiers/filters/conditions/index.ts b/packages/data/src/types/abstract-query/modifiers/filters/conditions/index.ts index b2dac3010c..cb942826cc 100644 --- a/packages/data/src/types/abstract-query/modifiers/filters/conditions/index.ts +++ b/packages/data/src/types/abstract-query/modifiers/filters/conditions/index.ts @@ -1,44 +1,6 @@ -import type { ConditionGeoIntersectsNode } from './geo-condition.js'; -import type { ConditionGeoIntersectsBBoxNode } from './geo-condition-bbox.js'; -import type { ConditionFieldNode } from './field-condition.js'; -import type { ConditionNumberNode } from './number-condition.js'; -import type { ConditionSetNode } from './set-condition.js'; -import type { ConditionStringNode } from './string-condition.js'; -/** - * Used to specify a condition on a query. - * Note: No explicit support to check for 'empty' (it's just an empty string) and null. - * - * @example - * ``` - * { - * type: 'condition', - * condition: {...} - * }, - * ``` - */ -export interface AbstractQueryConditionNode { - type: 'condition'; - condition: ActualConditionNodes; -} - -/** - * Possible nodes which specify the condition. - * - * @todo The API should make sure, that the type of the targeting column has the correct type, - * so that f.e. a condition-string will only be applied to a column of type string. - */ -export type ActualConditionNodes = - | ConditionStringNode - | ConditionNumberNode - | ConditionGeoIntersectsNode - | ConditionGeoIntersectsBBoxNode - | ConditionSetNode - | ConditionFieldNode; - -// Those need to be exported to be used solely in the corresponding converter export * from './field-condition.js'; export * from './geo-condition-bbox.js'; export * from './geo-condition.js'; export * from './number-condition.js'; -export * from './string-condition.js'; export * from './set-condition.js'; +export * from './string-condition.js'; diff --git a/packages/data/src/types/abstract-query/modifiers/filters/index.ts b/packages/data/src/types/abstract-query/modifiers/filters/index.ts index 7c04aad076..8b69b7c38d 100644 --- a/packages/data/src/types/abstract-query/modifiers/filters/index.ts +++ b/packages/data/src/types/abstract-query/modifiers/filters/index.ts @@ -1,9 +1,5 @@ -import type { AbstractQueryConditionNode } from './conditions/index.js'; -import type { AbstractQueryNodeLogical } from './logical.js'; -import type { AbstractQueryNodeNegate } from './negate.js'; - +export * from './conditions.js'; export * from './conditions/index.js'; +export * from './quantifier.js'; export * from './logical.js'; export * from './negate.js'; - -export type AbstractQueryFilterNode = AbstractQueryConditionNode | AbstractQueryNodeLogical | AbstractQueryNodeNegate; diff --git a/packages/data/src/types/abstract-query/modifiers/filters/logical.ts b/packages/data/src/types/abstract-query/modifiers/filters/logical.ts index 39800eed82..f2e326cc1e 100644 --- a/packages/data/src/types/abstract-query/modifiers/filters/logical.ts +++ b/packages/data/src/types/abstract-query/modifiers/filters/logical.ts @@ -1,4 +1,4 @@ -import type { AbstractQueryConditionNode } from './conditions/index.js'; +import type { AbstractQueryConditionNode } from './conditions.js'; import type { AbstractQueryNodeNegate } from './negate.js'; /** diff --git a/packages/data/src/types/abstract-query/modifiers/filters/negate.ts b/packages/data/src/types/abstract-query/modifiers/filters/negate.ts index 9f0b01fbe9..6bc0567f61 100644 --- a/packages/data/src/types/abstract-query/modifiers/filters/negate.ts +++ b/packages/data/src/types/abstract-query/modifiers/filters/negate.ts @@ -1,4 +1,4 @@ -import type { AbstractQueryFilterNode } from './index.js'; +import type { AbstractQueryFilterNode } from '../filters.js'; /** * Specifies that the wrapper filter should be negated. diff --git a/packages/data/src/types/abstract-query/modifiers/filters/quantifier.ts b/packages/data/src/types/abstract-query/modifiers/filters/quantifier.ts new file mode 100644 index 0000000000..a16f485cfc --- /dev/null +++ b/packages/data/src/types/abstract-query/modifiers/filters/quantifier.ts @@ -0,0 +1,13 @@ +export interface AbstractQueryQuantifierNode { + type: 'quantifier'; + operator: 'every' | 'some'; + + /** The o2m field that the every/some should be applied on */ + target: string; + + /** An alias to reference the o2m item */ + alias: string; + + /** the values for the the operation. */ + // childNode: AbstractQueryConditionNode | AbstractQueryNodeLogical | AbstractQueryNodeNegate; +} diff --git a/packages/data/src/types/abstract-query/modifiers/index.ts b/packages/data/src/types/abstract-query/modifiers/index.ts index beeb9a4934..13a3356e9c 100644 --- a/packages/data/src/types/abstract-query/modifiers/index.ts +++ b/packages/data/src/types/abstract-query/modifiers/index.ts @@ -1,19 +1,5 @@ -import type { AbstractQueryFilterNode } from './filters/index.js'; -import type { AbstractQueryNodeLimit } from './limit.js'; -import type { AbstractQueryNodeOffset } from './offset.js'; -import type { AbstractQueryNodeSort } from './sort.js'; - -/** - * Optional attributes to customize the query results - */ -export interface AbstractQueryModifiers { - limit?: AbstractQueryNodeLimit; - offset?: AbstractQueryNodeOffset; - sort?: AbstractQueryNodeSort[]; - filter?: AbstractQueryFilterNode; -} - +export * from './filters.js'; +export * from './filters/index.js'; export * from './limit.js'; export * from './offset.js'; export * from './sort.js'; -export * from './filters/index.js'; diff --git a/packages/data/src/types/driver.ts b/packages/data/src/types/driver.ts index af1fd6d5fa..9878090154 100644 --- a/packages/data/src/types/driver.ts +++ b/packages/data/src/types/driver.ts @@ -1,6 +1,7 @@ -import type { AbstractQuery } from './abstract-query/abstract-query.js'; import type { ReadableStream } from 'node:stream/web'; +import type { AbstractQuery } from './abstract-query.js'; + export abstract class DataDriver { abstract query: (query: AbstractQuery) => Promise; diff --git a/packages/data/src/types/index.ts b/packages/data/src/types/index.ts index fca2806e3c..5f2d9a04bb 100644 --- a/packages/data/src/types/index.ts +++ b/packages/data/src/types/index.ts @@ -1,2 +1,3 @@ -export * from './abstract-query/abstract-query.js'; +export * from './abstract-query.js'; +export * from './abstract-query/index.js'; export * from './driver.js';