@simtlix/simfinity-core 3.9.0 → 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/types/index.d.ts CHANGED
@@ -21,10 +21,22 @@ export const QLValue: GraphQLScalarType<unknown, unknown>;
21
21
  * and `IENDS_WITH` as a suffix, respecting or ignoring case, and `IEQ` as the whole value ignoring
22
22
  * case. An empty value matches every non-null string, except for `IEQ`, where it matches only the
23
23
  * empty string. On a list, some element must match.
24
+ *
25
+ * `IS_EMPTY` and `IS_NOT_EMPTY` take no value (omitted or null; any other value fails with
26
+ * `INVALID_FILTER_VALUE`), and every record matches exactly one of them. `IS_EMPTY` holds for a
27
+ * missing, null or `""` String (`" "` is not empty), a missing or null value of any other scalar or
28
+ * enum, a missing, null or `[]` list (`[null]` and `[""]` are not empty), and a missing or null
29
+ * embedded object or one whose stored members are all empty by these rules; the record identity is
30
+ * never empty. They apply to the queried record's own fields: a path that continues inside an
31
+ * embedded list or a collection fails with `INVALID_FILTER_PATH`, and a path that crosses or ends
32
+ * at a reference, a path that ends at a collection, and an embedded object with a reference or
33
+ * collection member fail with `UNSUPPORTED_QUERY` until reference emptiness arrives. A term or
34
+ * group condition without a path tests the field itself.
24
35
  */
25
36
  export type QueryOperator =
26
37
  | 'EQ' | 'NE' | 'LT' | 'LTE' | 'GT' | 'GTE' | 'BTW' | 'IN' | 'NIN' | 'LIKE'
27
- | 'ILIKE' | 'STARTS_WITH' | 'ISTARTS_WITH' | 'ENDS_WITH' | 'IENDS_WITH' | 'IEQ';
38
+ | 'ILIKE' | 'STARTS_WITH' | 'ISTARTS_WITH' | 'ENDS_WITH' | 'IENDS_WITH' | 'IEQ'
39
+ | 'IS_EMPTY' | 'IS_NOT_EMPTY';
28
40
 
29
41
  /**
30
42
  * The query language features a {@link DatabaseAdapter} compiles. Declare it so that the runtime
@@ -279,6 +291,18 @@ export interface MutationLimitsOptions {
279
291
  maxNestedOperations?: number | null;
280
292
  }
281
293
 
294
+ /**
295
+ * The fourth `createSchema()` argument. Any other key, or a value that is not a plain object,
296
+ * throws `INVALID_SCHEMA_OPTIONS` (500) before models are prepared.
297
+ */
298
+ export interface CreateSchemaOptions {
299
+ /**
300
+ * Custom queries to include, by name. `null` or omission includes every registered custom query,
301
+ * `[]` includes none, and names that are not registered are ignored.
302
+ */
303
+ includedCustomQueries?: string[] | null;
304
+ }
305
+
282
306
  export interface Runtime<Model = any, Session = any> {
283
307
  configureQueryLimits(options?: { maxPageSize?: number }): void;
284
308
  /**
@@ -312,7 +336,7 @@ export interface Runtime<Model = any, Session = any> {
312
336
  * not virtual, and is not a reference or collection, logs a `Configuration issue` warning once. The
313
337
  * first schema binds the types whose relation resolvers it generates to this runtime and
314
338
  * reserves reachable types that still have a
315
- * non-embedded relation field without a resolver, such as an unregistered custom mutation result.
339
+ * non-embedded relation field without a resolver, such as an unregistered custom operation result.
316
340
  * Every entity type resolves `id` to `_id ?? id`, whatever the allowlists include.
317
341
  *
318
342
  * A generated input that would have no fields is left out, with a `Configuration issue`
@@ -326,12 +350,16 @@ export interface Runtime<Model = any, Session = any> {
326
350
  * metadata types `SimfinityFieldExtensionsType` and `SimfinityRelationType` (numbered when
327
351
  * taken) for every later schema and logs a warning; once those names are fixed, a type with one
328
352
  * of them throws `RESERVED_TYPE_NAME` (500), before `adapter.prepare()` when it is an included
329
- * endpoint type, a registered mutation's input or output type, an output type they reach or a
353
+ * endpoint type, a registered custom operation's input or output type, an output type they reach or a
330
354
  * field argument's type, and when the schema is constructed otherwise, such as for a type inside
331
355
  * an input object's fields. The check before `adapter.prepare()` never reads an input object's
332
356
  * fields, so a registered input's `fields` function may call `getInputType()`.
357
+ *
358
+ * `options.includedCustomQueries` selects custom queries by name (see {@link CreateSchemaOptions});
359
+ * an included custom query named like an included generated query throws `QUERY_NAME_CONFLICT`
360
+ * (500). A schema without mutation fields has no `Mutation` root.
333
361
  */
334
- createSchema(includedQueryTypes?: GraphQLObjectType[] | null, includedMutationTypes?: GraphQLObjectType[] | null, includedCustomMutations?: string[] | null): GraphQLSchema;
362
+ createSchema(includedQueryTypes?: GraphQLObjectType[] | null, includedMutationTypes?: GraphQLObjectType[] | null, includedCustomMutations?: string[] | null, options?: CreateSchemaOptions): GraphQLSchema;
335
363
  getModel(type: GraphQLObjectType | { name: string }): Model | null | undefined;
336
364
  getType(name: string | { name: string }): GraphQLObjectType | null | undefined;
337
365
  /**
@@ -350,6 +378,13 @@ export interface Runtime<Model = any, Session = any> {
350
378
  */
351
379
  use(middleware: (params: MiddlewareContext, next: () => Promise<void>) => void | Promise<void>): void;
352
380
  registerMutation(name: string, description: string, input: GraphQLInputObjectType | null | undefined, output: GraphQLOutputType, callback: (args: any, session: Session, context: any) => any): void;
381
+ /**
382
+ * Register a custom query on `RootQueryType`, for a result that is not a stored record. The
383
+ * callback receives the input and the request context; no transaction or session wraps it.
384
+ * Throws `INVALID_QUERY_REGISTRATION` (500) for invalid arguments and `QUERY_NAME_CONFLICT`
385
+ * (500) for a name already registered.
386
+ */
387
+ registerCustomQuery(name: string, description: string, input: GraphQLInputObjectType | null | undefined, output: GraphQLOutputType, callback: (input: any, context: any) => any): void;
353
388
  /** Owns the full workflow transaction unless an active caller session is supplied. */
354
389
  saveObject(typeName: string, args: Record<string, any>, session?: Session, context?: any): Promise<any>;
355
390
  preventCreatingCollection(prevent: boolean): void;
@@ -366,7 +401,9 @@ export interface DatabaseAdapter<Model = any, Session = any> {
366
401
  * does not support fails with `UNSUPPORTED_QUERY` (400), before middleware runs for the client's
367
402
  * arguments and before `find`, `count`, `aggregate`, `findChildren` or `findChildrenBatch` for
368
403
  * conditions that middleware, scopes and joined scopes added. Operators outside `QLOperator` still
369
- * reach the adapter, which reports them as before.
404
+ * reach the adapter, which reports them as before. Declaring `IS_EMPTY` and `IS_NOT_EMPTY` means
405
+ * compiling their semantics on the record's own fields; it does not lift the `UNSUPPORTED_QUERY`
406
+ * that emptiness through references and collections gets in this release.
370
407
  */
371
408
  queryFeatures?: QueryFeatures | null | undefined;
372
409
  bind?(runtime: Pick<Runtime<Model, Session>, 'getModel' | 'getType' | 'getRegistrations'>): void;
@@ -486,7 +523,12 @@ export interface DatabaseAdapter<Model = any, Session = any> {
486
523
  }
487
524
  export function createRuntime<Model = any, Session = any>(adapter: DatabaseAdapter<Model, Session>): Runtime<Model, Session>;
488
525
 
489
- /** `operator` is a {@link QueryOperator}; the value of a text operator is a validated string. */
526
+ /**
527
+ * `operator` is a {@link QueryOperator}; the value of a text operator is a validated string. For
528
+ * `IS_EMPTY` and `IS_NOT_EMPTY` the value is null, and `path` may end at an embedded object, an
529
+ * embedded list or a scalar list as well as at a scalar; `IS_NOT_EMPTY` is the exact complement,
530
+ * which the compiler builds.
531
+ */
490
532
  export type QueryPredicate = { kind: 'predicate'; path: string[]; operator: string; value: any } | { kind: 'and' | 'or'; terms: QueryPredicate[] };
491
533
  export interface QueryPlan {
492
534
  entity: string;
@@ -502,6 +544,18 @@ export interface QueryPlan {
502
544
  * a string or contains U+0000. With `operators`, the names the caller compiles, any other
503
545
  * `QLOperator` value fails with `UNSUPPORTED_QUERY` (400); unknown operators fail with
504
546
  * `INVALID_FILTER_OPERATOR` (400) either way.
547
+ *
548
+ * An emptiness condition is checked in this order: its form, path and group depth
549
+ * (`MISSING_FILTER_PATH` for `IS_EMPTY` or `IS_NOT_EMPTY` on an object filter without terms or beside
550
+ * terms, `AMBIGUOUS_FILTER_FIELD`, `INVALID_FILTER_PATH`, `INVALID_FILTER_FIELD`,
551
+ * `FILTER_DEPTH_EXCEEDED`), then `operators` (`UNSUPPORTED_QUERY`), then `INVALID_FILTER_PATH` for a
552
+ * value inside an embedded list or a collection, `INVALID_FILTER_OPERATOR` for an embedded type that
553
+ * reaches itself through single embedded members, `INVALID_FILTER_VALUE` for a value that is not
554
+ * omitted or null, and `UNSUPPORTED_QUERY` for a reference or collection on the path or among the
555
+ * members. A term without a path (omitted, null or `""`) and a group condition without a path test
556
+ * the field itself. For other operators, a filter path of more than one segment that ends at an
557
+ * object fails with `INVALID_FILTER_PATH`, as on MongoDB; a bare object field keeps
558
+ * `MISSING_FILTER_PATH`.
505
559
  */
506
560
  export function createQueryPlan(models: ModelDescription, entityName: string, input?: Record<string, any>, options?: { mode?: QueryPlan['mode']; operators?: Iterable<string> }): QueryPlan;
507
561
  export function resolveModelPath(models: ModelDescription, entityName: string, path: string | string[]): FieldDescription[];