@gqloom/core 0.6.0 → 0.7.1

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/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) Modevol https://www.modevol.com/
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -2,18 +2,13 @@
2
2
 
3
3
  # GQLoom
4
4
 
5
- GQLoom is a GraphQL weaver for TypeScript/JavaScript that weaves GraphQL Schema using Valibot, Zod, or Yup, and supports sophisticated type inference to provide the best development experience.
5
+ GQLoom is a **Code First** GraphQL Schema Loom used to weave **runtime types** in the **TypeScript/JavaScript** ecosystem into a GraphQL Schema.
6
6
 
7
- The design of GQLoom is inspired by [tRPC](https://trpc.io/), [TypeGraphQL](https://typegraphql.com/), [Pothos](https://pothos-graphql.dev/).
7
+ Runtime validation libraries such as [Zod](https://zod.dev/), [Valibot](https://valibot.dev/), and [Yup](https://github.com/jquense/yup) have been widely used in backend application development. Meanwhile, when using ORM libraries like [Prisma](https://www.prisma.io/), [MikroORM](https://mikro-orm.io/), and [Drizzle](https://orm.drizzle.team/), we also pre - define database table structures or entity models that contain runtime types.
8
+ The responsibility of GQLoom is to weave these runtime types into a GraphQL Schema.
8
9
 
9
- ## Features
10
-
11
- * 🚀 GraphQL: flexible and efficient, reducing redundant data transfers;
12
- * 🔒 Robust type safety: enjoy intelligent hints at development time to detect potential problems at compile time;
13
- * 🔋 Ready to go: middleware, contexts, subscriptions, federated graphs are ready to go;
14
- * 🔮 No extra magic: no decorators, no metadata and reflection, no code generation, you just need JavaScript/TypeScript;
15
- * 🧩 Familiar schema libraries: use the schema libraries you already know (Zod, Yup, Valibot) to build GraphQL Schema and validate inputs;
16
- * 🧑‍💻 Develop happily: highly readable and semantic APIs designed to keep your code tidy;
10
+ When developing backend applications with GQLoom, you only need to write types using the Schema libraries you're familiar with. Modern Schema libraries will infer TypeScript types for you, and GQLoom will weave GraphQL types for you.
11
+ In addition, the **resolver factory** of GQLoom can create CRUD interfaces for `Prisma`, `MikroORM`, and `Drizzle`, and supports custom input and adding middleware.
17
12
 
18
13
  ## Hello World
19
14
 
@@ -22,14 +17,23 @@ import { resolver, query, ValibotWeaver } from "@gqloom/valibot"
22
17
  import * as v from "valibot"
23
18
 
24
19
  const helloResolver = resolver({
25
- hello: query(v.string(), () => "world"),
20
+ hello: query(v.string())
21
+ .input({ name: v.nullish(v.string(), "World") })
22
+ .resolve(({ name }) => `Hello, ${name}!`),
26
23
  })
27
24
 
28
25
  export const schema = ValibotWeaver.weave(helloResolver)
29
26
  ```
30
27
 
31
- Read [Introduction](https://gqloom.dev/guide/introduction.html) to learn more about GQLoom.
28
+ ## Highlights you should not miss
29
+
30
+ - 🧑‍💻 **Development Experience**: Fewer boilerplate codes, semantic API design, and extensive ecosystem integration make development enjoyable.
31
+ - 🔒 **Type Safety**: Automatically infer types from the Schema, enjoy intelligent code completion during development, and detect potential problems during compilation.
32
+ - 🎯 **Interface Factory**: Ordinary CRUD interfaces are too simple yet too cumbersome. Let the resolver factory create them quickly.
33
+ - 🔋 **Fully Prepared**: Middleware, context, subscriptions, and federated graphs are ready.
34
+ - 🔮 **No Magic**: Without decorators, metadata, reflection, or code generation, it can run anywhere with just JavaScript/TypeScript.
35
+ - 🧩 **Rich Integration**: Use your most familiar validation libraries and ORMs to build your next GraphQL application.
32
36
 
33
37
  ## Getting Started
34
38
 
35
- See [Getting Started](https://gqloom.dev/guide/getting-started.html) to learn how to use GQLoom.
39
+ See [Getting Started](https://gqloom.devgetting-started.html) to learn how to use GQLoom.
package/dist/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  ContextMemoization: () => ContextMemoization,
24
+ EasyDataLoader: () => EasyDataLoader,
24
25
  GraphQLSchemaLoom: () => GraphQLSchemaLoom,
25
26
  LoomObjectType: () => LoomObjectType,
26
27
  OPERATION_OBJECT_NAMES: () => OPERATION_OBJECT_NAMES,
@@ -28,16 +29,21 @@ __export(src_exports, {
28
29
  SYMBOLS: () => symbols_exports,
29
30
  applyMiddlewares: () => applyMiddlewares,
30
31
  baseResolver: () => baseResolver,
32
+ capitalize: () => capitalize,
31
33
  collectName: () => collectName,
32
34
  collectNames: () => collectNames,
33
35
  compose: () => compose,
36
+ createField: () => createField,
34
37
  createFieldFactory: () => createFieldFactory,
35
38
  createInputParser: () => createInputParser,
36
39
  createLoom: () => createLoom,
37
40
  createMemoization: () => createMemoization,
41
+ createMutation: () => createMutation,
38
42
  createMutationFactory: () => createMutationFactory,
43
+ createQuery: () => createQuery,
39
44
  createQueryFactory: () => createQueryFactory,
40
45
  createResolverFactory: () => createResolverFactory,
46
+ createSubscription: () => createSubscription,
41
47
  createSubscriptionFactory: () => createSubscriptionFactory,
42
48
  deepMerge: () => deepMerge,
43
49
  defaultSubscriptionResolve: () => defaultSubscriptionResolve,
@@ -265,7 +271,7 @@ function listSilk(origin) {
265
271
  [GET_GRAPHQL_TYPE]: () => {
266
272
  let originType = getGraphQLType(origin);
267
273
  if (originType instanceof import_graphql2.GraphQLNonNull && originType.ofType instanceof import_graphql2.GraphQLList) {
268
- originType = originType.ofType;
274
+ originType = originType.ofType.ofType;
269
275
  }
270
276
  if (originType instanceof import_graphql2.GraphQLList) {
271
277
  originType = originType.ofType;
@@ -505,6 +511,9 @@ function pascalCase(str) {
505
511
  (word, index) => index === 0 ? word.charAt(0).toUpperCase() + word.slice(1) : word.charAt(0).toUpperCase() + word.slice(1)
506
512
  ).join("");
507
513
  }
514
+ function capitalize(str) {
515
+ return str.slice(0, 1).toUpperCase() + str.slice(1);
516
+ }
508
517
 
509
518
  // src/utils/error.ts
510
519
  function markErrorLocation(error, ...locations) {
@@ -534,6 +543,72 @@ function markLocation(message, ...locations) {
534
543
  return `[${combinedLocation}] ${newMessage}`;
535
544
  }
536
545
 
546
+ // src/utils/loader.ts
547
+ var EasyDataLoader = class _EasyDataLoader {
548
+ constructor(batchLoadFn) {
549
+ this.batchLoadFn = batchLoadFn;
550
+ this.queue = [];
551
+ this.cache = /* @__PURE__ */ new Map();
552
+ this.resolvers = /* @__PURE__ */ new Map();
553
+ }
554
+ queue;
555
+ cache;
556
+ resolvers;
557
+ load(key) {
558
+ const existing = this.cache.get(key);
559
+ if (existing) return existing;
560
+ const promise = new Promise((resolve, reject) => {
561
+ this.queue.push(key);
562
+ this.resolvers.set(key, [resolve, reject]);
563
+ this.nextTickBatchLoad();
564
+ });
565
+ this.cache.set(key, promise);
566
+ return promise;
567
+ }
568
+ clear() {
569
+ this.queue = [];
570
+ this.cache = /* @__PURE__ */ new Map();
571
+ this.resolvers = /* @__PURE__ */ new Map();
572
+ }
573
+ clearByKey(key) {
574
+ this.queue = this.queue.filter((k) => k !== key);
575
+ this.cache.delete(key);
576
+ this.resolvers.delete(key);
577
+ }
578
+ async executeBatchLoad() {
579
+ if (this.queue.length === 0) return;
580
+ const [keys, resolvers] = [this.queue, this.resolvers];
581
+ this.queue = [];
582
+ this.resolvers = /* @__PURE__ */ new Map();
583
+ try {
584
+ const list = await this.batchLoadFn(keys);
585
+ for (let i = 0; i < list.length; i++) {
586
+ const data = list[i];
587
+ const resolve = resolvers.get(keys[i])?.[0];
588
+ const reject = resolvers.get(keys[i])?.[1];
589
+ if (data instanceof Error) {
590
+ reject?.(data);
591
+ } else {
592
+ resolve?.(data);
593
+ }
594
+ }
595
+ } catch (error) {
596
+ for (const key of keys) {
597
+ const reject = resolvers.get(key)?.[1];
598
+ reject?.(error);
599
+ }
600
+ }
601
+ }
602
+ nextTickPromise;
603
+ nextTickBatchLoad() {
604
+ this.nextTickPromise ??= _EasyDataLoader.nextTick().then(() => this.executeBatchLoad()).finally(() => this.nextTickPromise = void 0);
605
+ return this.nextTickPromise;
606
+ }
607
+ static nextTick() {
608
+ return new Promise((resolve) => setTimeout(resolve));
609
+ }
610
+ };
611
+
537
612
  // src/resolver/input.ts
538
613
  var import_graphql3 = require("graphql");
539
614
  function createInputParser(schema, value) {
@@ -587,8 +662,168 @@ function getStandardValue(result) {
587
662
  else throw new import_graphql3.GraphQLError("Invalid input");
588
663
  }
589
664
 
665
+ // src/resolver/resolver-chain-factory.ts
666
+ var BaseChainFactory = class _BaseChainFactory {
667
+ constructor(options) {
668
+ this.options = options;
669
+ }
670
+ static methods() {
671
+ return {
672
+ description: _BaseChainFactory.prototype.description,
673
+ deprecationReason: _BaseChainFactory.prototype.deprecationReason,
674
+ extensions: _BaseChainFactory.prototype.extensions
675
+ };
676
+ }
677
+ description(description) {
678
+ return this.clone({ description });
679
+ }
680
+ deprecationReason(deprecationReason) {
681
+ return this.clone({ deprecationReason });
682
+ }
683
+ extensions(extensions) {
684
+ return this.clone({ extensions });
685
+ }
686
+ use(...middlewares) {
687
+ return this.clone({
688
+ middlewares: [...this.options?.middlewares ?? [], ...middlewares]
689
+ });
690
+ }
691
+ };
692
+ var FieldChainFactory = class _FieldChainFactory extends BaseChainFactory {
693
+ static methods() {
694
+ return {
695
+ ...BaseChainFactory.methods(),
696
+ output: _FieldChainFactory.prototype.output,
697
+ input: _FieldChainFactory.prototype.input,
698
+ resolve: _FieldChainFactory.prototype.resolve,
699
+ clone: _FieldChainFactory.prototype.clone
700
+ };
701
+ }
702
+ clone(options) {
703
+ return new _FieldChainFactory({ ...this.options, ...options });
704
+ }
705
+ use(...middlewares) {
706
+ return super.use(...middlewares);
707
+ }
708
+ output(output) {
709
+ return new _FieldChainFactory({ ...this.options, output });
710
+ }
711
+ input(input) {
712
+ return new _FieldChainFactory({ ...this.options, input });
713
+ }
714
+ resolve(resolve) {
715
+ return createField(this.options?.output, {
716
+ ...this.options,
717
+ resolve
718
+ });
719
+ }
720
+ };
721
+ var QueryChainFactory = class _QueryChainFactory extends BaseChainFactory {
722
+ static methods() {
723
+ return {
724
+ ...BaseChainFactory.methods(),
725
+ output: _QueryChainFactory.prototype.output,
726
+ input: _QueryChainFactory.prototype.input,
727
+ resolve: _QueryChainFactory.prototype.resolve,
728
+ clone: _QueryChainFactory.prototype.clone
729
+ };
730
+ }
731
+ clone(options) {
732
+ return new _QueryChainFactory({ ...this.options, ...options });
733
+ }
734
+ use(...middlewares) {
735
+ return super.use(...middlewares);
736
+ }
737
+ output(output) {
738
+ return new _QueryChainFactory({ ...this.options, output });
739
+ }
740
+ input(input) {
741
+ return new _QueryChainFactory({ ...this.options, input });
742
+ }
743
+ resolve(resolve) {
744
+ return createQuery(this.options?.output, {
745
+ ...this.options,
746
+ resolve
747
+ });
748
+ }
749
+ };
750
+ var MutationChainFactory = class _MutationChainFactory extends BaseChainFactory {
751
+ static methods() {
752
+ return {
753
+ ...BaseChainFactory.methods(),
754
+ output: _MutationChainFactory.prototype.output,
755
+ input: _MutationChainFactory.prototype.input,
756
+ resolve: _MutationChainFactory.prototype.resolve,
757
+ clone: _MutationChainFactory.prototype.clone
758
+ };
759
+ }
760
+ clone(options) {
761
+ return new _MutationChainFactory({ ...this.options, ...options });
762
+ }
763
+ use(...middlewares) {
764
+ return super.use(...middlewares);
765
+ }
766
+ output(output) {
767
+ return new _MutationChainFactory({ ...this.options, output });
768
+ }
769
+ input(input) {
770
+ return new _MutationChainFactory({ ...this.options, input });
771
+ }
772
+ resolve(resolve) {
773
+ return createMutation(this.options?.output, {
774
+ ...this.options,
775
+ resolve
776
+ });
777
+ }
778
+ };
779
+ var SubscriptionChainFactory = class _SubscriptionChainFactory extends BaseChainFactory {
780
+ static methods() {
781
+ return {
782
+ ...BaseChainFactory.methods(),
783
+ output: _SubscriptionChainFactory.prototype.output,
784
+ input: _SubscriptionChainFactory.prototype.input,
785
+ subscribe: _SubscriptionChainFactory.prototype.subscribe,
786
+ clone: _SubscriptionChainFactory.prototype.clone
787
+ };
788
+ }
789
+ clone(options) {
790
+ return new _SubscriptionChainFactory({ ...this.options, ...options });
791
+ }
792
+ use(...middlewares) {
793
+ return super.use(...middlewares);
794
+ }
795
+ output(output) {
796
+ return new _SubscriptionChainFactory({ ...this.options, output });
797
+ }
798
+ input(input) {
799
+ return new _SubscriptionChainFactory({ ...this.options, input });
800
+ }
801
+ subscribe(subscribe) {
802
+ const options = this.options;
803
+ const subscription2 = createSubscription(options?.output, {
804
+ ...options,
805
+ subscribe
806
+ });
807
+ const subscriptionResolve = subscription2.resolve;
808
+ const resolve = (...args) => {
809
+ if (args.length === 1 && typeof args[0] === "function") {
810
+ return createSubscription(options?.output, {
811
+ ...options,
812
+ resolve: args[0],
813
+ subscribe
814
+ });
815
+ }
816
+ return subscriptionResolve(...args);
817
+ };
818
+ return Object.assign(subscription2, { resolve });
819
+ }
820
+ };
821
+
590
822
  // src/resolver/resolver.ts
591
- var query = (output, resolveOrOptions) => {
823
+ var createQuery = (output, resolveOrOptions) => {
824
+ if (resolveOrOptions == null) {
825
+ return new QueryChainFactory({ output });
826
+ }
592
827
  const options = getOperationOptions(resolveOrOptions);
593
828
  const type = "query";
594
829
  return {
@@ -606,7 +841,14 @@ var query = (output, resolveOrOptions) => {
606
841
  type
607
842
  };
608
843
  };
609
- var mutation = (output, resolveOrOptions) => {
844
+ var query = Object.assign(
845
+ createQuery,
846
+ QueryChainFactory.methods()
847
+ );
848
+ var createMutation = (output, resolveOrOptions) => {
849
+ if (resolveOrOptions == null) {
850
+ return new MutationChainFactory({ output });
851
+ }
610
852
  const options = getOperationOptions(resolveOrOptions);
611
853
  const type = "mutation";
612
854
  return {
@@ -624,7 +866,14 @@ var mutation = (output, resolveOrOptions) => {
624
866
  type
625
867
  };
626
868
  };
627
- var baseSilkField = (output, resolveOrOptions) => {
869
+ var mutation = Object.assign(
870
+ createMutation,
871
+ MutationChainFactory.methods()
872
+ );
873
+ var createField = (output, resolveOrOptions) => {
874
+ if (resolveOrOptions == null) {
875
+ return new FieldChainFactory({ output });
876
+ }
628
877
  const options = getOperationOptions(resolveOrOptions);
629
878
  const type = "field";
630
879
  return {
@@ -643,13 +892,15 @@ var baseSilkField = (output, resolveOrOptions) => {
643
892
  };
644
893
  };
645
894
  var field = Object.assign(
646
- baseSilkField,
647
- {
648
- hidden: FIELD_HIDDEN
649
- }
895
+ createField,
896
+ { hidden: FIELD_HIDDEN },
897
+ FieldChainFactory.methods()
650
898
  );
651
899
  var defaultSubscriptionResolve = (source) => source;
652
- var subscription = (output, subscribeOrOptions) => {
900
+ var createSubscription = (output, subscribeOrOptions) => {
901
+ if (subscribeOrOptions == null) {
902
+ return new SubscriptionChainFactory({ output });
903
+ }
653
904
  const options = getSubscriptionOptions(subscribeOrOptions);
654
905
  const type = "subscription";
655
906
  return {
@@ -671,6 +922,10 @@ var subscription = (output, subscribeOrOptions) => {
671
922
  type
672
923
  };
673
924
  };
925
+ var subscription = Object.assign(
926
+ createSubscription,
927
+ SubscriptionChainFactory.methods()
928
+ );
674
929
  var ResolverOptionsMap = /* @__PURE__ */ new WeakMap();
675
930
  function baseResolver(operations, options) {
676
931
  const record = {};
@@ -751,6 +1006,9 @@ function createResolverFactory(toSilk) {
751
1006
  }
752
1007
  function createFieldFactory(toSilk, isSchema) {
753
1008
  const baseFieldFunc = (output, resolveOrOptions) => {
1009
+ if (resolveOrOptions == null) {
1010
+ return new FieldChainFactory({ output: toSilk(output) });
1011
+ }
754
1012
  const options = getOperationOptions(
755
1013
  resolveOrOptions
756
1014
  );
@@ -759,12 +1017,17 @@ function createFieldFactory(toSilk, isSchema) {
759
1017
  input: toSilkInput(options.input, toSilk, isSchema)
760
1018
  });
761
1019
  };
762
- return Object.assign(baseFieldFunc, {
763
- hidden: FIELD_HIDDEN
764
- });
1020
+ return Object.assign(
1021
+ baseFieldFunc,
1022
+ { hidden: FIELD_HIDDEN },
1023
+ FieldChainFactory.methods()
1024
+ );
765
1025
  }
766
1026
  function createQueryFactory(toSilk, isSchema) {
767
1027
  return (output, resolveOrOptions) => {
1028
+ if (resolveOrOptions == null) {
1029
+ return new QueryChainFactory({ output: toSilk(output) });
1030
+ }
768
1031
  const options = getOperationOptions(resolveOrOptions);
769
1032
  return query(toSilk(output), {
770
1033
  ...options,
@@ -774,6 +1037,9 @@ function createQueryFactory(toSilk, isSchema) {
774
1037
  }
775
1038
  function createMutationFactory(toSilk, isSchema) {
776
1039
  return (output, resolveOrOptions) => {
1040
+ if (resolveOrOptions == null) {
1041
+ return new MutationChainFactory({ output: toSilk(output) });
1042
+ }
777
1043
  const options = getOperationOptions(resolveOrOptions);
778
1044
  return mutation(toSilk(output), {
779
1045
  ...options,
@@ -783,6 +1049,9 @@ function createMutationFactory(toSilk, isSchema) {
783
1049
  }
784
1050
  function createSubscriptionFactory(toSilk, isSchema) {
785
1051
  return (output, resolveOrOptions) => {
1052
+ if (resolveOrOptions == null) {
1053
+ return new SubscriptionChainFactory({ output: toSilk(output) });
1054
+ }
786
1055
  const options = getSubscriptionOptions(resolveOrOptions);
787
1056
  return subscription(toSilk(output), {
788
1057
  ...options,
@@ -1333,6 +1602,7 @@ function ensureInterfaceType(gqlType, interfaceConfig) {
1333
1602
  // Annotate the CommonJS export names for ESM import in node:
1334
1603
  0 && (module.exports = {
1335
1604
  ContextMemoization,
1605
+ EasyDataLoader,
1336
1606
  GraphQLSchemaLoom,
1337
1607
  LoomObjectType,
1338
1608
  OPERATION_OBJECT_NAMES,
@@ -1340,16 +1610,21 @@ function ensureInterfaceType(gqlType, interfaceConfig) {
1340
1610
  SYMBOLS,
1341
1611
  applyMiddlewares,
1342
1612
  baseResolver,
1613
+ capitalize,
1343
1614
  collectName,
1344
1615
  collectNames,
1345
1616
  compose,
1617
+ createField,
1346
1618
  createFieldFactory,
1347
1619
  createInputParser,
1348
1620
  createLoom,
1349
1621
  createMemoization,
1622
+ createMutation,
1350
1623
  createMutationFactory,
1624
+ createQuery,
1351
1625
  createQueryFactory,
1352
1626
  createResolverFactory,
1627
+ createSubscription,
1353
1628
  createSubscriptionFactory,
1354
1629
  deepMerge,
1355
1630
  defaultSubscriptionResolve,