Class: Agoo::GraphQL

Inherits:
Object
  • Object
show all
Defined in:
ext/agoo/rgraphql.c

Class Method Summary collapse

Class Method Details

.load(sdl) ⇒ Object

call-seq: load(sdl)

Load an SDL string. This should only be called in a block provided to a call to #schema.


661
662
663
664
665
666
667
668
669
670
671
672
673
# File 'ext/agoo/rgraphql.c', line 661

static VALUE
graphql_load(VALUE self, VALUE sdl) {
    struct _agooErr	err = AGOO_ERR_INIT;

    if (NULL == gql_root) {
	rb_raise(rb_eStandardError, "GraphQL root not set. Use Agoo::GraphQL.schema.");
    }
    rb_check_type(sdl, T_STRING);
    if (AGOO_ERR_OK != sdl_parse(&err, StringValuePtr(sdl), RSTRING_LEN(sdl))) {
	rb_raise(rb_eStandardError, "%s", err.msg);
    }
    return Qnil;
}

.load_file(path) ⇒ Object

call-seq: load_file(sdl_file)

Load an SDL file. This should only be called in a block provided to a call to #schema.


682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
# File 'ext/agoo/rgraphql.c', line 682

static VALUE
graphql_load_file(VALUE self, VALUE path) {
    struct _agooErr	err = AGOO_ERR_INIT;
    FILE		*f;
    long		len;
    char		*sdl;

    if (NULL == gql_root) {
	rb_raise(rb_eStandardError, "GraphQL root not set. Use Agoo::GraphQL.schema.");
    }
    rb_check_type(path, T_STRING);
    if (NULL == (f = fopen(StringValuePtr(path), "r"))) {
	rb_raise(rb_eIOError, "%s", strerror(errno));
    }
    if (0 != fseek(f, 0, SEEK_END)) {
	rb_raise(rb_eIOError, "%s", strerror(errno));
    }
    if (0 > (len = ftell(f))) {
	rb_raise(rb_eIOError, "%s", strerror(errno));
    }
    sdl = ALLOC_N(char, len + 1);
    if (0 != fseek(f, 0, SEEK_SET)) {
	rb_raise(rb_eIOError, "%s", strerror(errno));
    }
    if (len != (long)fread(sdl, 1, len, f)) {
	rb_raise(rb_eIOError, "%s", strerror(errno));
    } else {
	sdl[len] = '\0';
    }
    fclose(f);
    if (AGOO_ERR_OK != sdl_parse(&err, sdl, len)) {
	xfree(sdl);
	rb_raise(rb_eStandardError, "%s", err.msg);
    }
    xfree(sdl);

    return Qnil;
}

.publish(subject, event) ⇒ Object

call-seq: publish(subject, event)

Publish an event on the given subject. A subject must be a String while the event must be one of the objects represented by the the GraphQL schema. Generally the subjects are selected to identify which objects are being published and should match the value returned by the subscription methods.


774
775
776
777
778
779
780
781
782
783
784
785
786
# File 'ext/agoo/rgraphql.c', line 774

static VALUE
graphql_publish(VALUE self, VALUE subject, VALUE event) {
    const char		*subj;
    struct _agooErr	err = AGOO_ERR_INIT;

    rb_check_type(subject, T_STRING);
    subj = StringValuePtr(subject);

    if (AGOO_ERR_OK != agoo_server_gpublish(&err, subj, (gqlRef)event)) {
	rb_raise(rb_eStandardError, "%s", err.msg);
    }
    return Qnil;
}

.schema(root) ⇒ Object

call-seq: schema(root) { }

Start the GraphQL/Ruby integration by assigning a root Ruby object to the GraphQL environment. Within the block passed to the function SDL strings or files can be loaded. On exiting the block validation of the loaded schema is performed.

Note that the [email protected]_ directive is added to the schema type as well as the Query, Mutation, and Subscription types based on the root class. Any [email protected]_ directives on the object types in the SDL will also associate a GraphQL and Ruby class. The association will be used to validate the Ruby class as a way to verify the class implements the methods described by the GraphQL type. The association is also use for resolving


581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
# File 'ext/agoo/rgraphql.c', line 581

static VALUE
graphql_schema(VALUE self, VALUE root) {
    struct _agooErr	err = AGOO_ERR_INIT;
    gqlDir		dir;
    gqlDirUse		use;
    gqlType		schema_type;
    bool		fresh = false;

    if (!rb_block_given_p()) {
	rb_raise(rb_eStandardError, "A block is required.");
    }
    if (AGOO_ERR_OK != gql_init(&err)) {
	printf("*-*-* %s\n", err.msg);
	exit(1);
    }
    if (NULL == (dir = gql_directive_create(&err, "ruby", "Associates a Ruby class with a GraphQL type.", 0))) {
	printf("*-*-* %s\n", err.msg);
	exit(2);
    }
    if (NULL == gql_dir_arg(&err, dir, "class", &gql_string_type, NULL, 0, NULL, true)) {
	printf("*-*-* %s\n", err.msg);
	exit(3);
    }
    if (AGOO_ERR_OK != gql_directive_on(&err, dir, "SCHEMA", 6) ||
	AGOO_ERR_OK != gql_directive_on(&err, dir, "OBJECT", 6)) {
	printf("*-*-* %s\n", err.msg);
	exit(4);
    }
    gql_root = (gqlRef)root;
    vroot = root;
    rb_gc_register_address(&vroot);

    gql_doc_eval_func = eval_wrap;
    gql_resolve_func = resolve;
    gql_type_func = ref_type;
    gql_root_op = root_op;

    if (NULL == (use = gql_dir_use_create(&err, "ruby"))) {
	printf("*-*-* %s\n", err.msg);
	exit(5);
    }
    if (AGOO_ERR_OK != gql_dir_use_arg(&err, use, "class", gql_string_create(&err, rb_obj_classname(root), 0))) {
	printf("*-*-* %s\n", err.msg);
	exit(6);
    }
    rb_rescue2(rescue_yield, Qnil, rescue_yield_error, (VALUE)&err, rb_eException, 0);
    if (AGOO_ERR_OK != err.code) {
	printf("*-*-* %s\n", err.msg);
	exit(7);
    }
    if (NULL == (schema_type = gql_type_get("schema"))) {
	if (NULL == (schema_type = gql_schema_create(&err, "The GraphQL root Object.", 0))) {
	    printf("*-*-* %s\n", err.msg);
	    exit(8);
	}
	fresh = true;
    }

    if (AGOO_ERR_OK != gql_type_directive_use(&err, schema_type, use) ||
	AGOO_ERR_OK != make_ruby_use(&err, root, "query", "Query", fresh, schema_type, "Root level query.") ||
	AGOO_ERR_OK != make_ruby_use(&err, root, "mutation", "Mutation", fresh, schema_type, "Root level mutation.") ||
	AGOO_ERR_OK != make_ruby_use(&err, root, "subscription", "Subscription", fresh, schema_type, "Root level subscription.")) {
	printf("*-*-* %s\n", err.msg);
	exit(9);
    }
    if (AGOO_ERR_OK != gql_validate(&err) ||
	AGOO_ERR_OK != build_type_class_map(&err)) {
	printf("*-*-* %s\n", err.msg);
	exit(10);
    }
    return Qnil;
}

.sdl_dump(options) ⇒ Object

call-seq: dump_sdl()

The preferred method of inspecting a GraphQL schema is to use introspection queries but for debugging and for reviewing the schema a dump of the schema as SDL can be helpful. The #dump_sdl method returns the schema as an SDL string.

  • options [Hash] server options

    • :with_description [true|false] if true the description strings are included. If false they are not included.

    • :all [true|false] if true all types and directives are included in the dump. If false only the user created types are include.


737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
# File 'ext/agoo/rgraphql.c', line 737

static VALUE
graphql_sdl_dump(VALUE self, VALUE options) {
    agooText		t = agoo_text_allocate(4096);
    volatile VALUE	dump;
    VALUE		v;
    bool		with_desc = true;
    bool		all = false;

    Check_Type(options, T_HASH);

    v = rb_hash_aref(options, ID2SYM(rb_intern("with_descriptions")));
    if (Qnil != v) {
	with_desc = (Qtrue == v);
    }
    v = rb_hash_aref(options, ID2SYM(rb_intern("all")));
    if (Qnil != v) {
	all = (Qtrue == v);
    }
    if (NULL == (t = gql_schema_sdl(t, with_desc, all))) {
	rb_raise(rb_eNoMemError, "Failed to allocate memory for a schema dump.");
    }
    dump = rb_str_new(t->text, t->len);
    agoo_text_release(t);

    return dump;
}