diff --git a/cynic-parser/src/errors/report.rs b/cynic-parser/src/errors/report.rs index e5939b11..fb12ebea 100644 --- a/cynic-parser/src/errors/report.rs +++ b/cynic-parser/src/errors/report.rs @@ -45,7 +45,7 @@ impl Error { expected, } => ( format!("unexpected {}", token), - Label::new(*start..*end).with_message("didn't expect to see this"), + Label::new(*dbg!(start)..*dbg!(end)).with_message("didn't expect to see this"), Some(format!("expected one of {}", expected.join(", "))), ), Error::ExtraToken { diff --git a/cynic-parser/src/printer.rs b/cynic-parser/src/printer.rs index 771ab795..bb459aed 100644 --- a/cynic-parser/src/printer.rs +++ b/cynic-parser/src/printer.rs @@ -460,16 +460,17 @@ impl<'a> Pretty<'a, BoxAllocator> for NodeDisplay> { .parens() .flat_alt(arguments.parens()); - builder = builder.append(arguments).append(allocator.space()) + builder = builder.append(arguments) } if self.0.is_repeatable() { builder = builder - .append(allocator.text("repeatable")) .append(allocator.space()) + .append(allocator.text("repeatable")) } builder + .append(allocator.space()) .append(allocator.text("on")) .append(allocator.space()) .append(allocator.intersperse( diff --git a/cynic-parser/tests/actual_schemas.rs b/cynic-parser/tests/actual_schemas.rs new file mode 100644 index 00000000..e1b19ae5 --- /dev/null +++ b/cynic-parser/tests/actual_schemas.rs @@ -0,0 +1,46 @@ +macro_rules! schema_tests { + ($name: ident, $path: literal) => { + mod $name { + use similar_asserts::assert_eq; + + #[allow(non_upper_case_globals)] + const SCHEMA: &str = include_str!($path); + + #[test] + fn snapshot() { + let parsed = cynic_parser::parse_type_system_document(SCHEMA) + .map_err(|error| error.to_report(SCHEMA)) + .unwrap(); + insta::assert_snapshot!(parsed.to_sdl()); + } + + #[test] + fn double_roundtrip() { + let parsed = cynic_parser::parse_type_system_document(SCHEMA) + .map_err(|error| error.to_report(SCHEMA)) + .unwrap(); + let sdl = parsed.to_sdl(); + + let reparsed = cynic_parser::parse_type_system_document(&sdl) + .map_err(|error| error.to_report(&sdl)) + .unwrap(); + + assert_eq!(sdl, reparsed.to_sdl()); + } + } + }; +} + +schema_tests!(github, "../../schemas/github.graphql"); + +schema_tests!(books, "../../schemas/books.graphql"); + +schema_tests!(graphql_jobs, "../../schemas/graphql.jobs.graphql"); + +schema_tests!(raindancer, "../../schemas/raindancer.graphql"); + +schema_tests!(simple, "../../schemas/simple.graphql"); + +schema_tests!(starwars, "../../schemas/starwars.schema.graphql"); + +schema_tests!(test_cases, "../../schemas/test_cases.graphql"); diff --git a/cynic-parser/tests/github.rs b/cynic-parser/tests/github.rs deleted file mode 100644 index 41731a8a..00000000 --- a/cynic-parser/tests/github.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[test] -fn roundtrip_github() { - const GITHUB_SCHEMA: &str = include_str!("../../schemas/github.graphql"); - - let parsed = cynic_parser::parse_type_system_document(GITHUB_SCHEMA).unwrap(); - insta::assert_snapshot!(parsed.to_sdl()); -} diff --git a/cynic-parser/tests/snapshots/actual_schemas__books__snapshot.snap b/cynic-parser/tests/snapshots/actual_schemas__books__snapshot.snap new file mode 100644 index 00000000..82c3560e --- /dev/null +++ b/cynic-parser/tests/snapshots/actual_schemas__books__snapshot.snap @@ -0,0 +1,43 @@ +--- +source: cynic-parser/tests/actual_schemas.rs +expression: parsed.to_sdl() +--- +schema { + query: QueryRoot + mutation: MutationRoot + subscription: SubscriptionRoot +} + +directive @ifdef on FIELD + +type Book { + id: String! + name: String! + author: String! +} + +type BookChanged { + mutationType: MutationType! + id: ID! + book: Book +} + +type MutationRoot { + createBook(name: String!, author: String!): ID! + deleteBook(id: ID!): Boolean! +} + +enum MutationType { + CREATED + DELETED +} + +type QueryRoot { + books: [Book!]! +} + +type SubscriptionRoot { + interval(n: Int! = 1): Int! + books(mutationType: MutationType): BookChanged! +} + diff --git a/cynic-parser/tests/snapshots/github__roundtrip_github.snap b/cynic-parser/tests/snapshots/actual_schemas__github__snapshot.snap similarity index 100% rename from cynic-parser/tests/snapshots/github__roundtrip_github.snap rename to cynic-parser/tests/snapshots/actual_schemas__github__snapshot.snap diff --git a/cynic-parser/tests/snapshots/actual_schemas__graphql_jobs__snapshot.snap b/cynic-parser/tests/snapshots/actual_schemas__graphql_jobs__snapshot.snap new file mode 100644 index 00000000..423f408a --- /dev/null +++ b/cynic-parser/tests/snapshots/actual_schemas__graphql_jobs__snapshot.snap @@ -0,0 +1,987 @@ +--- +source: cynic-parser/tests/actual_schemas.rs +expression: parsed.to_sdl() +--- +type City { + id: ID! + name: String! + slug: String! + country: Country! + type: String! + jobs(where: JobWhereInput + orderBy: JobOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [Job!] + createdAt: DateTime! + updatedAt: DateTime! +} + +enum CityOrderByInput { + id_ASC + id_DESC + name_ASC + name_DESC + slug_ASC + slug_DESC + type_ASC + type_DESC + createdAt_ASC + createdAt_DESC + updatedAt_ASC + updatedAt_DESC +} + +input CityWhereInput { + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + id_lt: ID + id_lte: ID + id_gt: ID + id_gte: ID + id_contains: ID + id_not_contains: ID + id_starts_with: ID + id_not_starts_with: ID + id_ends_with: ID + id_not_ends_with: ID + name: String + name_not: String + name_in: [String!] + name_not_in: [String!] + name_lt: String + name_lte: String + name_gt: String + name_gte: String + name_contains: String + name_not_contains: String + name_starts_with: String + name_not_starts_with: String + name_ends_with: String + name_not_ends_with: String + slug: String + slug_not: String + slug_in: [String!] + slug_not_in: [String!] + slug_lt: String + slug_lte: String + slug_gt: String + slug_gte: String + slug_contains: String + slug_not_contains: String + slug_starts_with: String + slug_not_starts_with: String + slug_ends_with: String + slug_not_ends_with: String + country: CountryWhereInput + type: String + type_not: String + type_in: [String!] + type_not_in: [String!] + type_lt: String + type_lte: String + type_gt: String + type_gte: String + type_contains: String + type_not_contains: String + type_starts_with: String + type_not_starts_with: String + type_ends_with: String + type_not_ends_with: String + jobs_every: JobWhereInput + jobs_some: JobWhereInput + jobs_none: JobWhereInput + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + AND: [CityWhereInput!] + OR: [CityWhereInput!] + NOT: [CityWhereInput!] +} + +type Commitment { + id: ID! + title: String! + slug: String! + jobs(where: JobWhereInput + orderBy: JobOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [Job!] + createdAt: DateTime! + updatedAt: DateTime! +} + +input CommitmentWhereInput { + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + id_lt: ID + id_lte: ID + id_gt: ID + id_gte: ID + id_contains: ID + id_not_contains: ID + id_starts_with: ID + id_not_starts_with: ID + id_ends_with: ID + id_not_ends_with: ID + title: String + title_not: String + title_in: [String!] + title_not_in: [String!] + title_lt: String + title_lte: String + title_gt: String + title_gte: String + title_contains: String + title_not_contains: String + title_starts_with: String + title_not_starts_with: String + title_ends_with: String + title_not_ends_with: String + slug: String + slug_not: String + slug_in: [String!] + slug_not_in: [String!] + slug_lt: String + slug_lte: String + slug_gt: String + slug_gte: String + slug_contains: String + slug_not_contains: String + slug_starts_with: String + slug_not_starts_with: String + slug_ends_with: String + slug_not_ends_with: String + jobs_every: JobWhereInput + jobs_some: JobWhereInput + jobs_none: JobWhereInput + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + AND: [CommitmentWhereInput!] + OR: [CommitmentWhereInput!] + NOT: [CommitmentWhereInput!] +} + +type Company { + id: ID! + name: String! + slug: String! + websiteUrl: String! + logoUrl: String + jobs(where: JobWhereInput + orderBy: JobOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [Job!] + twitter: String + emailed: Boolean + createdAt: DateTime! + updatedAt: DateTime! +} + +input CompanyWhereInput { + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + id_lt: ID + id_lte: ID + id_gt: ID + id_gte: ID + id_contains: ID + id_not_contains: ID + id_starts_with: ID + id_not_starts_with: ID + id_ends_with: ID + id_not_ends_with: ID + name: String + name_not: String + name_in: [String!] + name_not_in: [String!] + name_lt: String + name_lte: String + name_gt: String + name_gte: String + name_contains: String + name_not_contains: String + name_starts_with: String + name_not_starts_with: String + name_ends_with: String + name_not_ends_with: String + slug: String + slug_not: String + slug_in: [String!] + slug_not_in: [String!] + slug_lt: String + slug_lte: String + slug_gt: String + slug_gte: String + slug_contains: String + slug_not_contains: String + slug_starts_with: String + slug_not_starts_with: String + slug_ends_with: String + slug_not_ends_with: String + websiteUrl: String + websiteUrl_not: String + websiteUrl_in: [String!] + websiteUrl_not_in: [String!] + websiteUrl_lt: String + websiteUrl_lte: String + websiteUrl_gt: String + websiteUrl_gte: String + websiteUrl_contains: String + websiteUrl_not_contains: String + websiteUrl_starts_with: String + websiteUrl_not_starts_with: String + websiteUrl_ends_with: String + websiteUrl_not_ends_with: String + logoUrl: String + logoUrl_not: String + logoUrl_in: [String!] + logoUrl_not_in: [String!] + logoUrl_lt: String + logoUrl_lte: String + logoUrl_gt: String + logoUrl_gte: String + logoUrl_contains: String + logoUrl_not_contains: String + logoUrl_starts_with: String + logoUrl_not_starts_with: String + logoUrl_ends_with: String + logoUrl_not_ends_with: String + jobs_every: JobWhereInput + jobs_some: JobWhereInput + jobs_none: JobWhereInput + twitter: String + twitter_not: String + twitter_in: [String!] + twitter_not_in: [String!] + twitter_lt: String + twitter_lte: String + twitter_gt: String + twitter_gte: String + twitter_contains: String + twitter_not_contains: String + twitter_starts_with: String + twitter_not_starts_with: String + twitter_ends_with: String + twitter_not_ends_with: String + emailed: Boolean + emailed_not: Boolean + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + AND: [CompanyWhereInput!] + OR: [CompanyWhereInput!] + NOT: [CompanyWhereInput!] +} + +type Country { + id: ID! + name: String! + slug: String! + type: String! + isoCode: String + cities(where: CityWhereInput + orderBy: CityOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [City!] + jobs(where: JobWhereInput + orderBy: JobOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [Job!] + createdAt: DateTime! + updatedAt: DateTime! +} + +enum CountryOrderByInput { + id_ASC + id_DESC + name_ASC + name_DESC + slug_ASC + slug_DESC + type_ASC + type_DESC + isoCode_ASC + isoCode_DESC + createdAt_ASC + createdAt_DESC + updatedAt_ASC + updatedAt_DESC +} + +input CountryWhereInput { + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + id_lt: ID + id_lte: ID + id_gt: ID + id_gte: ID + id_contains: ID + id_not_contains: ID + id_starts_with: ID + id_not_starts_with: ID + id_ends_with: ID + id_not_ends_with: ID + name: String + name_not: String + name_in: [String!] + name_not_in: [String!] + name_lt: String + name_lte: String + name_gt: String + name_gte: String + name_contains: String + name_not_contains: String + name_starts_with: String + name_not_starts_with: String + name_ends_with: String + name_not_ends_with: String + slug: String + slug_not: String + slug_in: [String!] + slug_not_in: [String!] + slug_lt: String + slug_lte: String + slug_gt: String + slug_gte: String + slug_contains: String + slug_not_contains: String + slug_starts_with: String + slug_not_starts_with: String + slug_ends_with: String + slug_not_ends_with: String + type: String + type_not: String + type_in: [String!] + type_not_in: [String!] + type_lt: String + type_lte: String + type_gt: String + type_gte: String + type_contains: String + type_not_contains: String + type_starts_with: String + type_not_starts_with: String + type_ends_with: String + type_not_ends_with: String + isoCode: String + isoCode_not: String + isoCode_in: [String!] + isoCode_not_in: [String!] + isoCode_lt: String + isoCode_lte: String + isoCode_gt: String + isoCode_gte: String + isoCode_contains: String + isoCode_not_contains: String + isoCode_starts_with: String + isoCode_not_starts_with: String + isoCode_ends_with: String + isoCode_not_ends_with: String + cities_every: CityWhereInput + cities_some: CityWhereInput + cities_none: CityWhereInput + jobs_every: JobWhereInput + jobs_some: JobWhereInput + jobs_none: JobWhereInput + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + AND: [CountryWhereInput!] + OR: [CountryWhereInput!] + NOT: [CountryWhereInput!] +} + +scalar DateTime + +type Job { + id: ID! + title: String! + slug: String! + commitment: Commitment! + cities(where: CityWhereInput + orderBy: CityOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [City!] + countries(where: CountryWhereInput + orderBy: CountryOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [Country!] + remotes(where: RemoteWhereInput + orderBy: RemoteOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [Remote!] + description: String + applyUrl: String + company: Company + tags(where: TagWhereInput + orderBy: TagOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [Tag!] + isPublished: Boolean + isFeatured: Boolean + locationNames: String + userEmail: String + postedAt: DateTime! + createdAt: DateTime! + updatedAt: DateTime! +} + +input JobInput { + companySlug: String! + jobSlug: String! +} + +enum JobOrderByInput { + id_ASC + id_DESC + title_ASC + title_DESC + slug_ASC + slug_DESC + description_ASC + description_DESC + applyUrl_ASC + applyUrl_DESC + isPublished_ASC + isPublished_DESC + isFeatured_ASC + isFeatured_DESC + locationNames_ASC + locationNames_DESC + userEmail_ASC + userEmail_DESC + postedAt_ASC + postedAt_DESC + createdAt_ASC + createdAt_DESC + updatedAt_ASC + updatedAt_DESC +} + +input JobsInput { + type: String + slug: String +} + +input JobWhereInput { + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + id_lt: ID + id_lte: ID + id_gt: ID + id_gte: ID + id_contains: ID + id_not_contains: ID + id_starts_with: ID + id_not_starts_with: ID + id_ends_with: ID + id_not_ends_with: ID + title: String + title_not: String + title_in: [String!] + title_not_in: [String!] + title_lt: String + title_lte: String + title_gt: String + title_gte: String + title_contains: String + title_not_contains: String + title_starts_with: String + title_not_starts_with: String + title_ends_with: String + title_not_ends_with: String + slug: String + slug_not: String + slug_in: [String!] + slug_not_in: [String!] + slug_lt: String + slug_lte: String + slug_gt: String + slug_gte: String + slug_contains: String + slug_not_contains: String + slug_starts_with: String + slug_not_starts_with: String + slug_ends_with: String + slug_not_ends_with: String + commitment: CommitmentWhereInput + cities_every: CityWhereInput + cities_some: CityWhereInput + cities_none: CityWhereInput + countries_every: CountryWhereInput + countries_some: CountryWhereInput + countries_none: CountryWhereInput + remotes_every: RemoteWhereInput + remotes_some: RemoteWhereInput + remotes_none: RemoteWhereInput + description: String + description_not: String + description_in: [String!] + description_not_in: [String!] + description_lt: String + description_lte: String + description_gt: String + description_gte: String + description_contains: String + description_not_contains: String + description_starts_with: String + description_not_starts_with: String + description_ends_with: String + description_not_ends_with: String + applyUrl: String + applyUrl_not: String + applyUrl_in: [String!] + applyUrl_not_in: [String!] + applyUrl_lt: String + applyUrl_lte: String + applyUrl_gt: String + applyUrl_gte: String + applyUrl_contains: String + applyUrl_not_contains: String + applyUrl_starts_with: String + applyUrl_not_starts_with: String + applyUrl_ends_with: String + applyUrl_not_ends_with: String + company: CompanyWhereInput + tags_every: TagWhereInput + tags_some: TagWhereInput + tags_none: TagWhereInput + isPublished: Boolean + isPublished_not: Boolean + isFeatured: Boolean + isFeatured_not: Boolean + locationNames: String + locationNames_not: String + locationNames_in: [String!] + locationNames_not_in: [String!] + locationNames_lt: String + locationNames_lte: String + locationNames_gt: String + locationNames_gte: String + locationNames_contains: String + locationNames_not_contains: String + locationNames_starts_with: String + locationNames_not_starts_with: String + locationNames_ends_with: String + locationNames_not_ends_with: String + userEmail: String + userEmail_not: String + userEmail_in: [String!] + userEmail_not_in: [String!] + userEmail_lt: String + userEmail_lte: String + userEmail_gt: String + userEmail_gte: String + userEmail_contains: String + userEmail_not_contains: String + userEmail_starts_with: String + userEmail_not_starts_with: String + userEmail_ends_with: String + userEmail_not_ends_with: String + postedAt: DateTime + postedAt_not: DateTime + postedAt_in: [DateTime!] + postedAt_not_in: [DateTime!] + postedAt_lt: DateTime + postedAt_lte: DateTime + postedAt_gt: DateTime + postedAt_gte: DateTime + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + AND: [JobWhereInput!] + OR: [JobWhereInput!] + NOT: [JobWhereInput!] +} + +type Location { + id: ID! + slug: String! + name: String! + type: String! +} + +input LocationInput { + slug: String! +} + +input LocationsInput { + value: String! +} + +type Mutation { + subscribe(input: SubscribeInput!): User! + postJob(input: PostJobInput!): Job! + updateJob(input: UpdateJobInput!, adminSecret: String!): Job! + updateCompany(input: UpdateCompanyInput!, adminSecret: String!): Company! +} + +input PostJobInput { + title: String! + commitmentId: ID! + companyName: String! + locationNames: String! + userEmail: String! + description: String! + applyUrl: String! +} + +type Query { + jobs(input: JobsInput): [Job!]! + job(input: JobInput!): Job! + locations(input: LocationsInput!): [Location!]! + city(input: LocationInput!): City! + country(input: LocationInput!): Country! + remote(input: LocationInput!): Remote! + commitments: [Commitment!]! + cities: [City!]! + countries: [Country!]! + remotes: [Remote!]! + companies: [Company!]! +} + +type Remote { + id: ID! + name: String! + slug: String! + type: String! + jobs(where: JobWhereInput + orderBy: JobOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [Job!] + createdAt: DateTime! + updatedAt: DateTime! +} + +enum RemoteOrderByInput { + id_ASC + id_DESC + name_ASC + name_DESC + slug_ASC + slug_DESC + type_ASC + type_DESC + createdAt_ASC + createdAt_DESC + updatedAt_ASC + updatedAt_DESC +} + +input RemoteWhereInput { + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + id_lt: ID + id_lte: ID + id_gt: ID + id_gte: ID + id_contains: ID + id_not_contains: ID + id_starts_with: ID + id_not_starts_with: ID + id_ends_with: ID + id_not_ends_with: ID + name: String + name_not: String + name_in: [String!] + name_not_in: [String!] + name_lt: String + name_lte: String + name_gt: String + name_gte: String + name_contains: String + name_not_contains: String + name_starts_with: String + name_not_starts_with: String + name_ends_with: String + name_not_ends_with: String + slug: String + slug_not: String + slug_in: [String!] + slug_not_in: [String!] + slug_lt: String + slug_lte: String + slug_gt: String + slug_gte: String + slug_contains: String + slug_not_contains: String + slug_starts_with: String + slug_not_starts_with: String + slug_ends_with: String + slug_not_ends_with: String + type: String + type_not: String + type_in: [String!] + type_not_in: [String!] + type_lt: String + type_lte: String + type_gt: String + type_gte: String + type_contains: String + type_not_contains: String + type_starts_with: String + type_not_starts_with: String + type_ends_with: String + type_not_ends_with: String + jobs_every: JobWhereInput + jobs_some: JobWhereInput + jobs_none: JobWhereInput + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + AND: [RemoteWhereInput!] + OR: [RemoteWhereInput!] + NOT: [RemoteWhereInput!] +} + +input SubscribeInput { + name: String! + email: String! +} + +type Tag { + id: ID! + name: String! + slug: String! + jobs(where: JobWhereInput + orderBy: JobOrderByInput + skip: Int + after: String + before: String + first: Int + last: Int + ): [Job!] + createdAt: DateTime! + updatedAt: DateTime! +} + +enum TagOrderByInput { + id_ASC + id_DESC + name_ASC + name_DESC + slug_ASC + slug_DESC + createdAt_ASC + createdAt_DESC + updatedAt_ASC + updatedAt_DESC +} + +input TagWhereInput { + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + id_lt: ID + id_lte: ID + id_gt: ID + id_gte: ID + id_contains: ID + id_not_contains: ID + id_starts_with: ID + id_not_starts_with: ID + id_ends_with: ID + id_not_ends_with: ID + name: String + name_not: String + name_in: [String!] + name_not_in: [String!] + name_lt: String + name_lte: String + name_gt: String + name_gte: String + name_contains: String + name_not_contains: String + name_starts_with: String + name_not_starts_with: String + name_ends_with: String + name_not_ends_with: String + slug: String + slug_not: String + slug_in: [String!] + slug_not_in: [String!] + slug_lt: String + slug_lte: String + slug_gt: String + slug_gte: String + slug_contains: String + slug_not_contains: String + slug_starts_with: String + slug_not_starts_with: String + slug_ends_with: String + slug_not_ends_with: String + jobs_every: JobWhereInput + jobs_some: JobWhereInput + jobs_none: JobWhereInput + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + AND: [TagWhereInput!] + OR: [TagWhereInput!] + NOT: [TagWhereInput!] +} + +input UpdateCompanyInput { + id: ID! + logoUrl: String! +} + +input UpdateJobInput { + id: ID! + description: String! +} + +type User { + id: ID! + name: String + email: String! + subscribe: Boolean! + createdAt: DateTime! + updatedAt: DateTime! +} + diff --git a/cynic-parser/tests/snapshots/actual_schemas__raindancer__snapshot.snap b/cynic-parser/tests/snapshots/actual_schemas__raindancer__snapshot.snap new file mode 100644 index 00000000..023822dd --- /dev/null +++ b/cynic-parser/tests/snapshots/actual_schemas__raindancer__snapshot.snap @@ -0,0 +1,40 @@ +--- +source: cynic-parser/tests/actual_schemas.rs +expression: parsed.to_sdl() +--- +type Device { + id: Int! + name: String! +} + +type MutationRoot { + createDevice(name: String!): Int + signIn(input: SignInInput!): String! + refresh(token: String!): String! + create(input: UserData!): ID +} + +type QueryRoot { + user(id: Int!): Device +} + +input SignInInput { + username: String! + password: String! +} + +type SubscriptionRoot { + interval(n: Int! = 1): Int! +} + +input UserData { + username: String! + password: String! +} + +schema { + query: QueryRoot + mutation: MutationRoot + subscription: SubscriptionRoot +} + diff --git a/cynic-parser/tests/snapshots/actual_schemas__simple__snapshot.snap b/cynic-parser/tests/snapshots/actual_schemas__simple__snapshot.snap new file mode 100644 index 00000000..5305cec7 --- /dev/null +++ b/cynic-parser/tests/snapshots/actual_schemas__simple__snapshot.snap @@ -0,0 +1,37 @@ +--- +source: cynic-parser/tests/actual_schemas.rs +expression: parsed.to_sdl() +--- +scalar JSON + +type Query { + testStruct: TestStruct + myUnion: MyUnionType +} + +type TestStruct { + fieldOne(x: Int, y: String): String! + tastyCakes(first: Dessert!, second: Dessert): Dessert! + fieldWithInput(input: AnInputType!): Dessert! + nested: Nested! + optNested: Nested + dessert: Dessert + json: JSON +} + +union MyUnionType = Nested | TestStruct + +type Nested { + aString: String! + optString: String +} + +enum Dessert { + CHEESECAKE + ICE_CREAM +} + +input AnInputType { + favouriteDessert: Dessert +} + diff --git a/cynic-parser/tests/snapshots/actual_schemas__starwars__snapshot.snap b/cynic-parser/tests/snapshots/actual_schemas__starwars__snapshot.snap new file mode 100644 index 00000000..34d8ff6a --- /dev/null +++ b/cynic-parser/tests/snapshots/actual_schemas__starwars__snapshot.snap @@ -0,0 +1,660 @@ +--- +source: cynic-parser/tests/actual_schemas.rs +expression: parsed.to_sdl() +--- +schema { + query: Root +} + +type Root { + allFilms(after: String + first: Int + before: String + last: Int + ): FilmsConnection + film(id: ID, filmID: ID): Film + allPeople(after: String + first: Int + before: String + last: Int + ): PeopleConnection + person(id: ID, personID: ID): Person + allPlanets(after: String + first: Int + before: String + last: Int + ): PlanetsConnection + planet(id: ID, planetID: ID): Planet + allSpecies(after: String + first: Int + before: String + last: Int + ): SpeciesConnection + species(id: ID, speciesID: ID): Species + allStarships(after: String + first: Int + before: String + last: Int + ): StarshipsConnection + starship(id: ID, starshipID: ID): Starship + allVehicles(after: String + first: Int + before: String + last: Int + ): VehiclesConnection + vehicle(id: ID, vehicleID: ID): Vehicle + node( + """ + The ID of an object + """ + id: ID! + ): Node +} + +""" +A connection to a list of items. +""" +type FilmsConnection { + pageInfo: PageInfo! + edges: [FilmsEdge] + totalCount: Int + films: [Film] +} + +""" +Information about pagination in a connection. +""" +type PageInfo { + hasNextPage: Boolean! + hasPreviousPage: Boolean! + startCursor: String + endCursor: String +} + +""" +An edge in a connection. +""" +type FilmsEdge { + node: Film + cursor: String! +} + +""" +A single film. +""" +type Film implements Node { + title: String + episodeID: Int + openingCrawl: String + director: String + producers: [String] + releaseDate: String + speciesConnection(after: String + first: Int + before: String + last: Int + ): FilmSpeciesConnection + starshipConnection(after: String + first: Int + before: String + last: Int + ): FilmStarshipsConnection + vehicleConnection(after: String + first: Int + before: String + last: Int + ): FilmVehiclesConnection + characterConnection(after: String + first: Int + before: String + last: Int + ): FilmCharactersConnection + planetConnection(after: String + first: Int + before: String + last: Int + ): FilmPlanetsConnection + created: String + edited: String + id: ID! +} + +""" +An object with an ID +""" +interface Node { + id: ID! +} + +""" +A connection to a list of items. +""" +type FilmSpeciesConnection { + pageInfo: PageInfo! + edges: [FilmSpeciesEdge] + totalCount: Int + species: [Species] +} + +""" +An edge in a connection. +""" +type FilmSpeciesEdge { + node: Species + cursor: String! +} + +""" +A type of person or character within the Star Wars Universe. +""" +type Species implements Node { + name: String + classification: String + designation: String + averageHeight: Float + averageLifespan: Int + eyeColors: [String] + hairColors: [String] + skinColors: [String] + language: String + homeworld: Planet + personConnection(after: String + first: Int + before: String + last: Int + ): SpeciesPeopleConnection + filmConnection(after: String + first: Int + before: String + last: Int + ): SpeciesFilmsConnection + created: String + edited: String + id: ID! +} + +""" +A large mass, planet or planetoid in the Star Wars Universe, at the time of +0 ABY. +""" +type Planet implements Node { + name: String + diameter: Int + rotationPeriod: Int + orbitalPeriod: Int + gravity: String + population: Float + climates: [String] + terrains: [String] + surfaceWater: Float + residentConnection(after: String + first: Int + before: String + last: Int + ): PlanetResidentsConnection + filmConnection(after: String + first: Int + before: String + last: Int + ): PlanetFilmsConnection + created: String + edited: String + id: ID! +} + +""" +A connection to a list of items. +""" +type PlanetResidentsConnection { + pageInfo: PageInfo! + edges: [PlanetResidentsEdge] + totalCount: Int + residents: [Person] +} + +""" +An edge in a connection. +""" +type PlanetResidentsEdge { + node: Person + cursor: String! +} + +""" +An individual person or character within the Star Wars universe. +""" +type Person implements Node { + name: String + birthYear: String + eyeColor: String + gender: String + hairColor: String + height: Int + mass: Float + skinColor: String + homeworld: Planet + filmConnection(after: String + first: Int + before: String + last: Int + ): PersonFilmsConnection + species: Species + starshipConnection(after: String + first: Int + before: String + last: Int + ): PersonStarshipsConnection + vehicleConnection(after: String + first: Int + before: String + last: Int + ): PersonVehiclesConnection + created: String + edited: String + id: ID! +} + +""" +A connection to a list of items. +""" +type PersonFilmsConnection { + pageInfo: PageInfo! + edges: [PersonFilmsEdge] + totalCount: Int + films: [Film] +} + +""" +An edge in a connection. +""" +type PersonFilmsEdge { + node: Film + cursor: String! +} + +""" +A connection to a list of items. +""" +type PersonStarshipsConnection { + pageInfo: PageInfo! + edges: [PersonStarshipsEdge] + totalCount: Int + starships: [Starship] +} + +""" +An edge in a connection. +""" +type PersonStarshipsEdge { + node: Starship + cursor: String! +} + +""" +A single transport craft that has hyperdrive capability. +""" +type Starship implements Node { + name: String + model: String + starshipClass: String + manufacturers: [String] + costInCredits: Float + length: Float + crew: String + passengers: String + maxAtmospheringSpeed: Int + hyperdriveRating: Float + MGLT: Int + cargoCapacity: Float + consumables: String + pilotConnection(after: String + first: Int + before: String + last: Int + ): StarshipPilotsConnection + filmConnection(after: String + first: Int + before: String + last: Int + ): StarshipFilmsConnection + created: String + edited: String + id: ID! +} + +""" +A connection to a list of items. +""" +type StarshipPilotsConnection { + pageInfo: PageInfo! + edges: [StarshipPilotsEdge] + totalCount: Int + pilots: [Person] +} + +""" +An edge in a connection. +""" +type StarshipPilotsEdge { + node: Person + cursor: String! +} + +""" +A connection to a list of items. +""" +type StarshipFilmsConnection { + pageInfo: PageInfo! + edges: [StarshipFilmsEdge] + totalCount: Int + films: [Film] +} + +""" +An edge in a connection. +""" +type StarshipFilmsEdge { + node: Film + cursor: String! +} + +""" +A connection to a list of items. +""" +type PersonVehiclesConnection { + pageInfo: PageInfo! + edges: [PersonVehiclesEdge] + totalCount: Int + vehicles: [Vehicle] +} + +""" +An edge in a connection. +""" +type PersonVehiclesEdge { + node: Vehicle + cursor: String! +} + +""" +A single transport craft that does not have hyperdrive capability +""" +type Vehicle implements Node { + name: String + model: String + vehicleClass: String + manufacturers: [String] + costInCredits: Float + length: Float + crew: String + passengers: String + maxAtmospheringSpeed: Int + cargoCapacity: Float + consumables: String + pilotConnection(after: String + first: Int + before: String + last: Int + ): VehiclePilotsConnection + filmConnection(after: String + first: Int + before: String + last: Int + ): VehicleFilmsConnection + created: String + edited: String + id: ID! +} + +""" +A connection to a list of items. +""" +type VehiclePilotsConnection { + pageInfo: PageInfo! + edges: [VehiclePilotsEdge] + totalCount: Int + pilots: [Person] +} + +""" +An edge in a connection. +""" +type VehiclePilotsEdge { + node: Person + cursor: String! +} + +""" +A connection to a list of items. +""" +type VehicleFilmsConnection { + pageInfo: PageInfo! + edges: [VehicleFilmsEdge] + totalCount: Int + films: [Film] +} + +""" +An edge in a connection. +""" +type VehicleFilmsEdge { + node: Film + cursor: String! +} + +""" +A connection to a list of items. +""" +type PlanetFilmsConnection { + pageInfo: PageInfo! + edges: [PlanetFilmsEdge] + totalCount: Int + films: [Film] +} + +""" +An edge in a connection. +""" +type PlanetFilmsEdge { + node: Film + cursor: String! +} + +""" +A connection to a list of items. +""" +type SpeciesPeopleConnection { + pageInfo: PageInfo! + edges: [SpeciesPeopleEdge] + totalCount: Int + people: [Person] +} + +""" +An edge in a connection. +""" +type SpeciesPeopleEdge { + node: Person + cursor: String! +} + +""" +A connection to a list of items. +""" +type SpeciesFilmsConnection { + pageInfo: PageInfo! + edges: [SpeciesFilmsEdge] + totalCount: Int + films: [Film] +} + +""" +An edge in a connection. +""" +type SpeciesFilmsEdge { + node: Film + cursor: String! +} + +""" +A connection to a list of items. +""" +type FilmStarshipsConnection { + pageInfo: PageInfo! + edges: [FilmStarshipsEdge] + totalCount: Int + starships: [Starship] +} + +""" +An edge in a connection. +""" +type FilmStarshipsEdge { + node: Starship + cursor: String! +} + +""" +A connection to a list of items. +""" +type FilmVehiclesConnection { + pageInfo: PageInfo! + edges: [FilmVehiclesEdge] + totalCount: Int + vehicles: [Vehicle] +} + +""" +An edge in a connection. +""" +type FilmVehiclesEdge { + node: Vehicle + cursor: String! +} + +""" +A connection to a list of items. +""" +type FilmCharactersConnection { + pageInfo: PageInfo! + edges: [FilmCharactersEdge] + totalCount: Int + characters: [Person] +} + +""" +An edge in a connection. +""" +type FilmCharactersEdge { + node: Person + cursor: String! +} + +""" +A connection to a list of items. +""" +type FilmPlanetsConnection { + pageInfo: PageInfo! + edges: [FilmPlanetsEdge] + totalCount: Int + planets: [Planet] +} + +""" +An edge in a connection. +""" +type FilmPlanetsEdge { + node: Planet + cursor: String! +} + +""" +A connection to a list of items. +""" +type PeopleConnection { + pageInfo: PageInfo! + edges: [PeopleEdge] + totalCount: Int + people: [Person] +} + +""" +An edge in a connection. +""" +type PeopleEdge { + node: Person + cursor: String! +} + +""" +A connection to a list of items. +""" +type PlanetsConnection { + pageInfo: PageInfo! + edges: [PlanetsEdge] + totalCount: Int + planets: [Planet] +} + +""" +An edge in a connection. +""" +type PlanetsEdge { + node: Planet + cursor: String! +} + +""" +A connection to a list of items. +""" +type SpeciesConnection { + pageInfo: PageInfo! + edges: [SpeciesEdge] + totalCount: Int + species: [Species] +} + +""" +An edge in a connection. +""" +type SpeciesEdge { + node: Species + cursor: String! +} + +""" +A connection to a list of items. +""" +type StarshipsConnection { + pageInfo: PageInfo! + edges: [StarshipsEdge] + totalCount: Int + starships: [Starship] +} + +""" +An edge in a connection. +""" +type StarshipsEdge { + node: Starship + cursor: String! +} + +""" +A connection to a list of items. +""" +type VehiclesConnection { + pageInfo: PageInfo! + edges: [VehiclesEdge] + totalCount: Int + vehicles: [Vehicle] +} + +""" +An edge in a connection. +""" +type VehiclesEdge { + node: Vehicle + cursor: String! +} + diff --git a/cynic-parser/tests/snapshots/actual_schemas__test_cases__snapshot.snap b/cynic-parser/tests/snapshots/actual_schemas__test_cases__snapshot.snap new file mode 100644 index 00000000..99a500b9 --- /dev/null +++ b/cynic-parser/tests/snapshots/actual_schemas__test_cases__snapshot.snap @@ -0,0 +1,51 @@ +--- +source: cynic-parser/tests/actual_schemas.rs +expression: parsed.to_sdl() +--- +schema { + query: Foo +} + +type Foo { + _: Boolean + self: Boolean + super: Boolean + crate: Boolean + async: Boolean + bar(id: UUID!): Bar + fieldWithKeywordArg(where: Int): [Int!]! + recursiveInputField(recursive: SelfRecursiveInput + recursive2: RecursiveInputParent + ): Boolean + fieldWithStringArg(input: String!): Int +} + +type Bar { + id: UUID! + name: String +} + +scalar UUID + +enum States { + OPEN + CLOSED + DELETED +} + +input SelfRecursiveInput { + recurse: SelfRecursiveInput +} + +input RecursiveInputParent { + recurse: RecursiveInputChild +} + +input RecursiveInputChild { + recurse: RecursiveInputParent +} + +type FlattenableEnums { + states: [States] +} +