mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
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 <jan.arends@mailbox.org> --------- Co-authored-by: Jan Arends <jan.arends@mailbox.org> Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch>
This commit is contained in:
committed by
GitHub
parent
dfe7513f13
commit
6c45914b8a
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
39
packages/data/src/engine.ts
Normal file
39
packages/data/src/engine.ts
Normal file
@@ -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<string, DataDriver>;
|
||||
|
||||
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<ReadableStream> {
|
||||
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?.()));
|
||||
}
|
||||
}
|
||||
@@ -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<string, DataDriver>;
|
||||
|
||||
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<ReadableStream> {
|
||||
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';
|
||||
|
||||
@@ -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';
|
||||
@@ -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;
|
||||
5
packages/data/src/types/abstract-query/fields/index.ts
Normal file
5
packages/data/src/types/abstract-query/fields/index.ts
Normal file
@@ -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';
|
||||
29
packages/data/src/types/abstract-query/fields/nested.ts
Normal file
29
packages/data/src/types/abstract-query/fields/nested.ts
Normal file
@@ -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
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './relational.js';
|
||||
@@ -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[]];
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
3
packages/data/src/types/abstract-query/index.ts
Normal file
3
packages/data/src/types/abstract-query/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './fields/index.js';
|
||||
export * from './modifiers.js';
|
||||
export * from './modifiers/index.js';
|
||||
14
packages/data/src/types/abstract-query/modifiers.ts
Normal file
14
packages/data/src/types/abstract-query/modifiers.ts
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { GeoJSONGeometryCollection, GeoJSONMultiPolygon, GeoJSONPolygon } from 'wellknown';
|
||||
|
||||
import type { AbstractQueryFieldNodePrimitive } from '../../../fields/primitive.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { AbstractQueryConditionNode } from './conditions/index.js';
|
||||
import type { AbstractQueryConditionNode } from './conditions.js';
|
||||
import type { AbstractQueryNodeNegate } from './negate.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { AbstractQueryFilterNode } from './index.js';
|
||||
import type { AbstractQueryFilterNode } from '../filters.js';
|
||||
|
||||
/**
|
||||
* Specifies that the wrapper filter should be negated.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
@@ -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<ReadableStream>;
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user