mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Improving SDK types (#19286)
Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch>
This commit is contained in:
5
.changeset/polite-buckets-raise.md
Normal file
5
.changeset/polite-buckets-raise.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@directus/sdk": patch
|
||||
---
|
||||
|
||||
Added missing filter operators, removed the reliance on `@directus/types`, fixed content-type regression on graphql
|
||||
4
pnpm-lock.yaml
generated
4
pnpm-lock.yaml
generated
@@ -1833,10 +1833,6 @@ importers:
|
||||
version: 0.31.1(happy-dom@9.18.3)(sass@1.62.1)
|
||||
|
||||
sdk:
|
||||
dependencies:
|
||||
'@directus/types':
|
||||
specifier: workspace:*
|
||||
version: link:../packages/types
|
||||
devDependencies:
|
||||
'@directus/tsconfig':
|
||||
specifier: workspace:*
|
||||
|
||||
@@ -54,9 +54,6 @@
|
||||
"typescript": "5.0.4",
|
||||
"vitest": "0.31.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@directus/types": "workspace:*"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
|
||||
@@ -20,18 +20,23 @@ export const graphql = () => {
|
||||
const options: RequestInit = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ query, variables }),
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
if ('getToken' in this) {
|
||||
const token = await (this.getToken as AuthenticationClient<Schema>['getToken'])();
|
||||
|
||||
if (token) {
|
||||
if (!options.headers) options.headers = {};
|
||||
options.headers = { Authorization: `Bearer ${token}` };
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
}
|
||||
|
||||
if ('Content-Type' in headers === false) {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
|
||||
options.headers = headers;
|
||||
const requestPath = scope === 'items' ? '/graphql' : '/graphql/system';
|
||||
const requestUrl = getRequestUrl(client.url, requestPath);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { PrimaryKey } from '@directus/types';
|
||||
import type { Query } from '../types/query.js';
|
||||
import type { ApplyQueryFields, CollectionType } from '../index.js';
|
||||
|
||||
@@ -73,5 +72,5 @@ export type SubscriptionPayload<Item> = {
|
||||
init: Item[];
|
||||
create: Item[];
|
||||
update: Item[];
|
||||
delete: PrimaryKey[];
|
||||
delete: string[] | number[];
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { PrimaryKey } from '@directus/types';
|
||||
import type { Query } from '../../../types/index.js';
|
||||
import type { RestCommand } from '../../types.js';
|
||||
|
||||
@@ -13,7 +12,7 @@ import type { RestCommand } from '../../types.js';
|
||||
export const deleteItems =
|
||||
<Schema extends object, Collection extends keyof Schema, const TQuery extends Query<Schema, Schema[Collection]>>(
|
||||
collection: Collection,
|
||||
keysOrQuery: PrimaryKey[] | TQuery
|
||||
keysOrQuery: string[] | number[] | TQuery
|
||||
): RestCommand<void, Schema> =>
|
||||
() => {
|
||||
const _collection = String(collection);
|
||||
@@ -39,7 +38,7 @@ export const deleteItems =
|
||||
export const deleteItem =
|
||||
<Schema extends object, Collection extends keyof Schema>(
|
||||
collection: Collection,
|
||||
key: PrimaryKey
|
||||
key: string | number
|
||||
): RestCommand<void, Schema> =>
|
||||
() => {
|
||||
const _collection = String(collection);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { PrimaryKey } from '@directus/types';
|
||||
import type { ApplyQueryFields, CollectionType, Query, RegularCollections } from '../../../types/index.js';
|
||||
import type { RestCommand } from '../../types.js';
|
||||
|
||||
@@ -55,7 +54,7 @@ export const readItem =
|
||||
const TQuery extends Query<Schema, CollectionType<Schema, Collection>>
|
||||
>(
|
||||
collection: Collection,
|
||||
key: PrimaryKey,
|
||||
key: string | number,
|
||||
query?: TQuery
|
||||
): RestCommand<ReadItemOutput<Schema, Collection, TQuery>, Schema> =>
|
||||
() => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { PrimaryKey } from '@directus/types';
|
||||
import type { ApplyQueryFields, CollectionType, Query, UnpackList } from '../../../types/index.js';
|
||||
import type { RestCommand } from '../../types.js';
|
||||
|
||||
@@ -21,7 +20,7 @@ export type UpdateItemOutput<
|
||||
export const updateItems =
|
||||
<Schema extends object, Collection extends keyof Schema, const TQuery extends Query<Schema, Schema[Collection]>>(
|
||||
collection: Collection,
|
||||
keys: PrimaryKey[],
|
||||
keys: string[] | number[],
|
||||
item: Partial<UnpackList<Schema[Collection]>>,
|
||||
query?: TQuery
|
||||
): RestCommand<UpdateItemOutput<Schema, Collection, TQuery>[], Schema> =>
|
||||
@@ -54,7 +53,7 @@ export const updateItem =
|
||||
Item = UnpackList<Schema[Collection]>
|
||||
>(
|
||||
collection: Collection,
|
||||
key: PrimaryKey,
|
||||
key: string | number,
|
||||
item: Partial<Item>,
|
||||
query?: TQuery
|
||||
): RestCommand<UpdateItemOutput<Schema, Collection, TQuery>, Schema> =>
|
||||
|
||||
27
sdk/src/types/deep.ts
Normal file
27
sdk/src/types/deep.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { MergeObjects, Query } from './query.js';
|
||||
import type { ItemType, RelationalFields } from './schema.js';
|
||||
import type { UnpackList } from './utils.js';
|
||||
|
||||
/**
|
||||
* Deep filter object
|
||||
*/
|
||||
export type QueryDeep<Schema extends object, Item> = UnpackList<Item> extends infer FlatItem
|
||||
? RelationalFields<Schema, FlatItem> extends never
|
||||
? never
|
||||
: {
|
||||
[Field in RelationalFields<Schema, FlatItem> as ExtractCollection<Schema, FlatItem[Field]> extends any[]
|
||||
? Field
|
||||
: never]?: ExtractCollection<Schema, FlatItem[Field]> extends infer CollectionItem
|
||||
? Query<Schema, CollectionItem> extends infer TQuery
|
||||
? MergeObjects<
|
||||
QueryDeep<Schema, CollectionItem>,
|
||||
{
|
||||
[Key in keyof Omit<TQuery, 'deep' | 'alias' | 'fields'> as `_${string & Key}`]: TQuery[Key];
|
||||
}
|
||||
>
|
||||
: never
|
||||
: never;
|
||||
}
|
||||
: never;
|
||||
|
||||
type ExtractCollection<Schema extends object, Item> = Extract<Item, ItemType<Schema>>;
|
||||
79
sdk/src/types/filters.ts
Normal file
79
sdk/src/types/filters.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import type { RelationalFields } from './schema.js';
|
||||
import type { UnpackList } from './utils.js';
|
||||
|
||||
/**
|
||||
* Filters
|
||||
*/
|
||||
export type QueryFilter<Schema extends object, Item> = WrapLogicalFilters<NestedQueryFilter<Schema, Item>>;
|
||||
|
||||
/**
|
||||
* Query filters without logical filters
|
||||
*/
|
||||
export type NestedQueryFilter<Schema extends object, Item> = UnpackList<Item> extends infer FlatItem
|
||||
? {
|
||||
[Field in keyof FlatItem]?:
|
||||
| (Field extends RelationalFields<Schema, FlatItem>
|
||||
? WrapRelationalFilters<NestedQueryFilter<Schema, FlatItem[Field]>>
|
||||
: never)
|
||||
| FilterOperators<FlatItem[Field]>;
|
||||
}
|
||||
: never;
|
||||
|
||||
/**
|
||||
* All regular filter operators
|
||||
*
|
||||
* TODO would love to filter this based on field type but thats not accurate enough in the schema atm
|
||||
*/
|
||||
export type FilterOperators<T> = {
|
||||
_eq?: T;
|
||||
_neq?: T;
|
||||
_gt?: T;
|
||||
_gte?: T;
|
||||
_lt?: T;
|
||||
_lte?: T;
|
||||
_in?: T[];
|
||||
_nin?: T[];
|
||||
_between?: [T, T];
|
||||
_nbetween?: [T, T];
|
||||
_contains?: T;
|
||||
_ncontains?: T;
|
||||
_starts_with?: T;
|
||||
_istarts_with?: T;
|
||||
_nstarts_with?: T;
|
||||
_nistarts_with?: T;
|
||||
_ends_with?: T;
|
||||
_iends_with?: T;
|
||||
_nends_with?: T;
|
||||
_niends_with?: T;
|
||||
_empty?: boolean;
|
||||
_nempty?: boolean;
|
||||
_nnull?: boolean;
|
||||
_null?: boolean;
|
||||
_intersects?: T;
|
||||
_nintersects?: T;
|
||||
_intersects_bbox?: T;
|
||||
_nintersects_bbox?: T;
|
||||
_regex?: T;
|
||||
};
|
||||
|
||||
/**
|
||||
* Relational filter operators
|
||||
*/
|
||||
export type RelationalFilterOperators = '_some' | '_none';
|
||||
|
||||
export type WrapRelationalFilters<Filters> =
|
||||
| {
|
||||
[Operator in RelationalFilterOperators]?: Filters;
|
||||
}
|
||||
| Filters;
|
||||
|
||||
/**
|
||||
* Logical filter operations
|
||||
*/
|
||||
export type LogicalFilterOperators = '_or' | '_and';
|
||||
|
||||
export type WrapLogicalFilters<Filters> =
|
||||
| {
|
||||
[Operator in LogicalFilterOperators]?: WrapLogicalFilters<Filters>[];
|
||||
}
|
||||
| Filters;
|
||||
@@ -1,6 +1,8 @@
|
||||
export * from './aggregate.js';
|
||||
export * from './client.js';
|
||||
export * from './deep.js';
|
||||
export * from './fields.js';
|
||||
export * from './filters.js';
|
||||
export * from './output.js';
|
||||
export * from './query.js';
|
||||
export * from './request.js';
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { QueryDeep } from './deep.js';
|
||||
import type { HasNestedFields, QueryFields } from './fields.js';
|
||||
import type { ItemType, RelationalFields } from './schema.js';
|
||||
import type { QueryFilter } from './filters.js';
|
||||
import type { ItemType } from './schema.js';
|
||||
import type { IfAny, UnpackList } from './utils.js';
|
||||
|
||||
/**
|
||||
@@ -45,52 +47,6 @@ export type MergeFields<FieldList> = HasNestedFields<FieldList> extends never
|
||||
? Extract<UnpackList<FieldList>, string>
|
||||
: Extract<UnpackList<FieldList>, string> | MergeRelationalFields<FieldList>;
|
||||
|
||||
/**
|
||||
* Filters
|
||||
*/
|
||||
export type QueryFilter<Schema extends object, Item> = UnpackList<Item> extends infer FlatItem
|
||||
? {
|
||||
[Field in keyof FlatItem]?:
|
||||
| (Field extends RelationalFields<Schema, FlatItem> ? QueryFilter<Schema, FlatItem[Field]> : never)
|
||||
| FilterOperatorsByType<FlatItem[Field]>;
|
||||
}
|
||||
: never;
|
||||
|
||||
/**
|
||||
* All available filter operators
|
||||
* TODO would love to filter this based on field type but thats not accurate enough in the schema atm
|
||||
*/
|
||||
export type FilterOperatorsByType<T> = {
|
||||
_eq?: T;
|
||||
_neq?: T;
|
||||
_gt?: T;
|
||||
_gte?: T;
|
||||
_lt?: T;
|
||||
_lte?: T;
|
||||
_in?: T[];
|
||||
_nin?: T[];
|
||||
_between?: [T, T];
|
||||
_nbetween?: [T, T];
|
||||
_contains?: T;
|
||||
_ncontains?: T;
|
||||
_starts_with?: T;
|
||||
_istarts_with?: T;
|
||||
_nstarts_with?: T;
|
||||
_nistarts_with?: T;
|
||||
_ends_with?: T;
|
||||
_iends_with?: T;
|
||||
_nends_with?: T;
|
||||
_niends_with?: T;
|
||||
_empty?: boolean;
|
||||
_nempty?: boolean;
|
||||
_nnull?: boolean;
|
||||
_null?: boolean;
|
||||
_intersects?: T;
|
||||
_nintersects?: T;
|
||||
_intersects_bbox?: T;
|
||||
_nintersects_bbox?: T;
|
||||
};
|
||||
|
||||
/**
|
||||
* Query sort
|
||||
* TODO expand to relational sorting (same object notation as fields i guess)
|
||||
@@ -101,24 +57,6 @@ export type QuerySort<_Schema extends object, Item> = UnpackList<Item> extends i
|
||||
}[keyof FlatItem]
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Deep filter object
|
||||
*/
|
||||
export type QueryDeep<Schema extends object, Item> = UnpackList<Item> extends infer FlatItem
|
||||
? RelationalFields<Schema, FlatItem> extends never
|
||||
? never
|
||||
: {
|
||||
[Field in RelationalFields<Schema, FlatItem>]?: Query<Schema, FlatItem[Field]> extends infer TQuery
|
||||
? MergeObjects<
|
||||
QueryDeep<Schema, FlatItem[Field]>,
|
||||
{
|
||||
[Key in keyof Omit<TQuery, 'deep' | 'alias'> as `_${string & Key}`]: TQuery[Key];
|
||||
}
|
||||
>
|
||||
: never;
|
||||
}
|
||||
: never;
|
||||
|
||||
export type MergeObjects<A, B extends object> = A extends object ? A & B : never;
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user