| giolekva | 0defd60 | 2020-04-27 16:48:16 +0400 | [diff] [blame] | 1 | package tests |
| 2 | |
| 3 | import ( |
| giolekva | 26a8b5f | 2020-05-01 20:01:13 +0400 | [diff] [blame] | 4 | "fmt" |
| 5 | "io" |
| 6 | "os" |
| 7 | "strings" |
| giolekva | 0defd60 | 2020-04-27 16:48:16 +0400 | [diff] [blame] | 8 | "testing" |
| 9 | |
| 10 | "github.com/vektah/gqlparser" |
| 11 | "github.com/vektah/gqlparser/ast" |
| giolekva | 26a8b5f | 2020-05-01 20:01:13 +0400 | [diff] [blame] | 12 | |
| 13 | "github.com/bradleyjkemp/memviz" |
| giolekva | 0defd60 | 2020-04-27 16:48:16 +0400 | [diff] [blame] | 14 | ) |
| 15 | |
| 16 | var gqlSchema = `#######################\n# Input Schema\n#######################\n\ntype Image {\n\tid: ID!\n\tobjectPath: String! @search(by: [exact])\n\tsegments(filter: ImageSegmentFilter, order: ImageSegmentOrder, first: Int, offset: Int): [ImageSegment] @hasInverse(field: sourceImage)\n}\n\ntype ImageSegment {\n\tid: ID!\n\tupperLeftX: Float!\n\tupperLeftY: Float!\n\tlowerRightX: Float!\n\tlowerRightY: Float!\n\tsourceImage(filter: ImageFilter): Image! @hasInverse(field: segments)\n\tobjectPath: String\n}\n\n#######################\n# Extended Definitions\n#######################\n\nscalar DateTime\n\nenum DgraphIndex {\n\tint\n\tfloat\n\tbool\n\thash\n\texact\n\tterm\n\tfulltext\n\ttrigram\n\tregexp\n\tyear\n\tmonth\n\tday\n\thour\n}\n\ndirective @hasInverse(field: String!) on FIELD_DEFINITION\ndirective @search(by: [DgraphIndex!]) on FIELD_DEFINITION\ndirective @dgraph(type: String, pred: String) on OBJECT | INTERFACE | FIELD_DEFINITION\ndirective @id on FIELD_DEFINITION\ndirective @secret(field: String!, pred: String) on OBJECT | INTERFACE\n\ninput IntFilter {\n\teq: Int\n\tle: Int\n\tlt: Int\n\tge: Int\n\tgt: Int\n}\n\ninput FloatFilter {\n\teq: Float\n\tle: Float\n\tlt: Float\n\tge: Float\n\tgt: Float\n}\n\ninput DateTimeFilter {\n\teq: DateTime\n\tle: DateTime\n\tlt: DateTime\n\tge: DateTime\n\tgt: DateTime\n}\n\ninput StringTermFilter {\n\tallofterms: String\n\tanyofterms: String\n}\n\ninput StringRegExpFilter {\n\tregexp: String\n}\n\ninput StringFullTextFilter {\n\talloftext: String\n\tanyoftext: String\n}\n\ninput StringExactFilter {\n\teq: String\n\tle: String\n\tlt: String\n\tge: String\n\tgt: String\n}\n\ninput StringHashFilter {\n\teq: String\n}\n\n#######################\n# Generated Types\n#######################\n\ntype AddImagePayload {\n\timage(filter: ImageFilter, order: ImageOrder, first: Int, offset: Int): [Image]\n\tnumUids: Int\n}\n\ntype AddImageSegmentPayload {\n\timagesegment(filter: ImageSegmentFilter, order: ImageSegmentOrder, first: Int, offset: Int): [ImageSegment]\n\tnumUids: Int\n}\n\ntype DeleteImagePayload {\n\tmsg: String\n\tnumUids: Int\n}\n\ntype DeleteImageSegmentPayload {\n\tmsg: String\n\tnumUids: Int\n}\n\ntype UpdateImagePayload {\n\timage(filter: ImageFilter, order: ImageOrder, first: Int, offset: Int): [Image]\n\tnumUids: Int\n}\n\ntype UpdateImageSegmentPayload {\n\timagesegment(filter: ImageSegmentFilter, order: ImageSegmentOrder, first: Int, offset: Int): [ImageSegment]\n\tnumUids: Int\n}\n\n#######################\n# Generated Enums\n#######################\n\nenum ImageOrderable {\n\tobjectPath\n}\n\nenum ImageSegmentOrderable {\n\tupperLeftX\n\tupperLeftY\n\tlowerRightX\n\tlowerRightY\n\tobjectPath\n}\n\n#######################\n# Generated Inputs\n#######################\n\ninput AddImageInput {\n\tobjectPath: String!\n\tsegments: [ImageSegmentRef]\n}\n\ninput AddImageSegmentInput {\n\tupperLeftX: Float!\n\tupperLeftY: Float!\n\tlowerRightX: Float!\n\tlowerRightY: Float!\n\tsourceImage: ImageRef!\n\tobjectPath: String\n}\n\ninput ImageFilter {\n\tid: [ID!]\n\tobjectPath: StringExactFilter\n\tand: ImageFilter\n\tor: ImageFilter\n\tnot: ImageFilter\n}\n\ninput ImageOrder {\n\tasc: ImageOrderable\n\tdesc: ImageOrderable\n\tthen: ImageOrder\n}\n\ninput ImagePatch {\n\tobjectPath: String\n\tsegments: [ImageSegmentRef]\n}\n\ninput ImageRef {\n\tid: ID\n\tobjectPath: String\n\tsegments: [ImageSegmentRef]\n}\n\ninput ImageSegmentFilter {\n\tid: [ID!]\n\tnot: ImageSegmentFilter\n}\n\ninput ImageSegmentOrder {\n\tasc: ImageSegmentOrderable\n\tdesc: ImageSegmentOrderable\n\tthen: ImageSegmentOrder\n}\n\ninput ImageSegmentPatch {\n\tupperLeftX: Float\n\tupperLeftY: Float\n\tlowerRightX: Float\n\tlowerRightY: Float\n\tsourceImage: ImageRef\n\tobjectPath: String\n}\n\ninput ImageSegmentRef {\n\tid: ID\n\tupperLeftX: Float\n\tupperLeftY: Float\n\tlowerRightX: Float\n\tlowerRightY: Float\n\tsourceImage: ImageRef\n\tobjectPath: String\n}\n\ninput UpdateImageInput {\n\tfilter: ImageFilter!\n\tset: ImagePatch\n\tremove: ImagePatch\n}\n\ninput UpdateImageSegmentInput {\n\tfilter: ImageSegmentFilter!\n\tset: ImageSegmentPatch\n\tremove: ImageSegmentPatch\n}\n\n#######################\n# Generated Query\n#######################\n\ntype Query {\n\tgetImage(id: ID!): Image\n\tqueryImage(filter: ImageFilter, order: ImageOrder, first: Int, offset: Int): [Image]\n\tgetImageSegment(id: ID!): ImageSegment\n\tqueryImageSegment(filter: ImageSegmentFilter, order: ImageSegmentOrder, first: Int, offset: Int): [ImageSegment]\n}\n\n#######################\n# Generated Mutations\n#######################\n\ntype Mutation {\n\taddImage(input: [AddImageInput!]!): AddImagePayload\n\tupdateImage(input: UpdateImageInput!): UpdateImagePayload\n\tdeleteImage(filter: ImageFilter!): DeleteImagePayload\n\taddImageSegment(input: [AddImageSegmentInput!]!): AddImageSegmentPayload\n\tupdateImageSegment(input: UpdateImageSegmentInput!): UpdateImageSegmentPayload\n\tdeleteImageSegment(filter: ImageSegmentFilter!): DeleteImageSegmentPayload\n}\n` |
| 17 | |
| giolekva | 26a8b5f | 2020-05-01 20:01:13 +0400 | [diff] [blame] | 18 | var simpleSchema = ` |
| 19 | type ABC { |
| 20 | id: ID! |
| 21 | x: Int |
| 22 | } |
| 23 | |
| 24 | input ABCInput { |
| 25 | x: Int |
| 26 | } |
| 27 | |
| 28 | extend type ABC { |
| 29 | event: ID |
| 30 | } |
| 31 | ` |
| 32 | |
| 33 | var enumSchema = ` |
| 34 | enum EventState { |
| 35 | NEW |
| 36 | PROCESSING |
| 37 | DONE |
| 38 | } |
| 39 | |
| 40 | input Event { |
| 41 | id: ID |
| 42 | state: EventState! |
| 43 | } |
| 44 | |
| 45 | type E { |
| 46 | foo: String |
| 47 | } |
| 48 | |
| 49 | type Mutation { |
| 50 | addEvent(input: Event!): E |
| 51 | } |
| 52 | ` |
| 53 | |
| 54 | // TODO(giolekva): will be safer to use directive instead |
| 55 | func shouldIgnoreDefinition(d *ast.Definition) bool { |
| 56 | return d.Kind != ast.Object || |
| 57 | d.Name == "Query" || |
| 58 | d.Name == "Mutation" || |
| 59 | strings.HasPrefix(d.Name, "__") || |
| 60 | strings.HasSuffix(d.Name, "Payload") |
| 61 | } |
| 62 | |
| 63 | func checkErr(err error) { |
| 64 | if err != nil { |
| 65 | panic(err) |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | func TestParseSchema(t *testing.T) { |
| 70 | schema := getSchema(gqlSchema) |
| 71 | var extended strings.Builder |
| 72 | _, err := io.WriteString(&extended, gqlSchema) |
| 73 | checkErr(err) |
| 74 | for _, n := range schema.Types { |
| 75 | if shouldIgnoreDefinition(n) { |
| 76 | continue |
| 77 | } |
| 78 | _, err := fmt.Fprintf(&extended, "\nextend type %s {\n event: ID\n}", n.Name) |
| 79 | checkErr(err) |
| 80 | } |
| 81 | fmt.Print(&extended) |
| 82 | f, _ := os.Create("schema.dot") |
| 83 | memviz.Map(f, schema) |
| 84 | f.Close() |
| 85 | } |
| 86 | |
| giolekva | 0defd60 | 2020-04-27 16:48:16 +0400 | [diff] [blame] | 87 | func TestParseQuery(t *testing.T) { |
| giolekva | 26a8b5f | 2020-05-01 20:01:13 +0400 | [diff] [blame] | 88 | schema := getSchema(enumSchema) |
| 89 | query, err := gqlparser.LoadQuery(schema, `mutation { |
| 90 | addEvent(input: { |
| 91 | state: NEW |
| 92 | }) { |
| 93 | foo |
| giolekva | 0defd60 | 2020-04-27 16:48:16 +0400 | [diff] [blame] | 94 | } |
| 95 | }`) |
| 96 | if err != nil { |
| 97 | panic(err) |
| 98 | } |
| giolekva | 26a8b5f | 2020-05-01 20:01:13 +0400 | [diff] [blame] | 99 | f, _ := os.Create("query.dot") |
| 100 | memviz.Map(f, query) |
| 101 | f.Close() |
| giolekva | 0defd60 | 2020-04-27 16:48:16 +0400 | [diff] [blame] | 102 | } |
| 103 | |
| giolekva | 26a8b5f | 2020-05-01 20:01:13 +0400 | [diff] [blame] | 104 | func getSchema(schema string) *ast.Schema { |
| 105 | s, err := gqlparser.LoadSchema(&ast.Source{ |
| 106 | Input: strings.ReplaceAll(strings.ReplaceAll(schema, "\\n", "\n"), "\\t", "\t")}) |
| giolekva | 0defd60 | 2020-04-27 16:48:16 +0400 | [diff] [blame] | 107 | if err != nil { |
| 108 | panic(err) |
| 109 | } |
| giolekva | 26a8b5f | 2020-05-01 20:01:13 +0400 | [diff] [blame] | 110 | return s |
| giolekva | 0defd60 | 2020-04-27 16:48:16 +0400 | [diff] [blame] | 111 | } |