Last active
February 12, 2020 08:19
-
-
Save h-michael/deb0052a00456709bcb2f557c94bf083 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ nvim --version | |
NVIM v0.5.0-366-g932949229 | |
$ ra_lsp_server | |
rust-analyzer 759100f | |
``` | |
[ INFO ] 2020-02-12T17:11:02Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:204 ] "Starting RPC client" { args = {}, cmd = "ra_lsp_server", extra = {}} | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] /home/h-michael/.local/share/nvim/runtime/lua/vim/lsp.lua:486 ] "LSP[rust_analyzer]" "initialize_params" { capabilities = { textDocument = { completion = { completionItem = { commitCharactersSupport = false, deprecatedSupport = false, documentationFormat = { "markdown", "plaintext" }, preselectSupport = false, snippetSupport = false }, completionItemKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 } }, contextSupport = false, dynamicRegistration = false }, documentHighlight = { dynamicRegistration = false }, documentSymbol = { dynamicRegistration = false, hierarchicalDocumentSymbolSupport = false, symbolKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 } } }, hover = { contentFormat = { "markdown", "plaintext" }, dynamicRegistration = false }, references = { dynamicRegistration = false }, signatureHelp = { dynamicRegistration = false, signatureInformation = { documentationFormat = { "markdown", "plaintext" } } }, synchronization = { didSave = true, dynamicRegistration = false, willSave = false, willSaveWaitUntil = false } }, workspace = { configuration = true } }, initializationOptions = {}, processId = 290032, rootPath = "/home/h-michael/go/src/github.com/h-michael/graphql-client/graphql_client", rootUri = "file:///home/h-michael/go/src/github.com/h-michael/graphql-client/graphql_client", trace = "off"} | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:271 ] "rpc.send.payload" { id = 1, jsonrpc = "2.0", method = "initialize", params = { capabilities = { textDocument = { completion = { completionItem = { commitCharactersSupport = false, deprecatedSupport = false, documentationFormat = { "markdown", "plaintext" }, preselectSupport = false, snippetSupport = false }, completionItemKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 } }, contextSupport = false, dynamicRegistration = false }, documentHighlight = { dynamicRegistration = false }, documentSymbol = { dynamicRegistration = false, hierarchicalDocumentSymbolSupport = false, symbolKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 } } }, hover = { contentFormat = { "markdown", "plaintext" }, dynamicRegistration = false }, references = { dynamicRegistration = false }, signatureHelp = { dynamicRegistration = false, signatureInformation = { documentationFormat = { "markdown", "plaintext" } } }, synchronization = { didSave = true, dynamicRegistration = false, willSave = false, willSaveWaitUntil = false } }, workspace = { configuration = true } }, initializationOptions = {}, processId = 290032, rootPath = "/home/h-michael/go/src/github.com/h-michael/graphql-client/graphql_client", rootUri = "file:///home/h-michael/go/src/github.com/h-michael/graphql-client/graphql_client", trace = "off" }} | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:351 ] "decoded" { id = 1, jsonrpc = "2.0", result = { capabilities = { callHierarchyProvider = true, codeActionProvider = true, codeLensProvider = { resolveProvider = true }, completionProvider = { triggerCharacters = { ":", "." } }, definitionProvider = true, documentFormattingProvider = true, documentHighlightProvider = true, documentOnTypeFormattingProvider = { firstTriggerCharacter = "=", moreTriggerCharacter = { ".", ">" } }, documentSymbolProvider = true, foldingRangeProvider = true, hoverProvider = true, implementationProvider = true, referencesProvider = true, renameProvider = { prepareProvider = true }, selectionRangeProvider = true, signatureHelpProvider = { triggerCharacters = { "(", "," } }, textDocumentSync = { change = 1, openClose = true, save = vim.empty_dict() }, typeDefinitionProvider = true, workspaceSymbolProvider = true } }} | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:282 ] "rpc.notify" "initialized" { [true] = 6} | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:271 ] "rpc.send.payload" { jsonrpc = "2.0", method = "initialized", params = { [true] = 6 }} | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] /home/h-michael/.local/share/nvim/runtime/lua/vim/lsp.lua:503 ] "LSP[rust_analyzer]" "server_capabilities" { callHierarchyProvider = true, codeActionProvider = true, codeLensProvider = { resolveProvider = true }, completionProvider = { triggerCharacters = { ":", "." } }, definitionProvider = true, documentFormattingProvider = true, documentHighlightProvider = true, documentOnTypeFormattingProvider = { firstTriggerCharacter = "=", moreTriggerCharacter = { ".", ">" } }, documentSymbolProvider = true, foldingRangeProvider = true, hoverProvider = true, implementationProvider = true, referencesProvider = true, renameProvider = { prepareProvider = true }, selectionRangeProvider = true, signatureHelpProvider = { triggerCharacters = { "(", "," } }, textDocumentSync = { change = 1, openClose = true, save = vim.empty_dict() }, typeDefinitionProvider = true, workspaceSymbolProvider = true} | |
[ INFO ] 2020-02-12T17:11:02Z+0900 ] /home/h-michael/.local/share/nvim/runtime/lua/vim/lsp.lua:504 ] "LSP[rust_analyzer]" "initialized" { resolved_capabilities = { code_action = true, document_formatting = true, document_highlight = true, document_range_formatting = false, document_symbol = true, find_references = true, goto_definition = true, hover = true, implementation = true, signature_help = true, signature_help_trigger_characters = { "(", "," }, text_document_did_change = 1, text_document_open_close = true, text_document_save = vim.empty_dict(), text_document_save_include_text = false, text_document_will_save = false, text_document_will_save_wait_until = false, workspace_symbol = true }} | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:282 ] "rpc.notify" "textDocument/didOpen" { textDocument = { languageId = "rust", text = "//! The top-level documentation resides on the [project README](https://github.com/graphql-rust/graphql-client) at the moment.\n//!\n//! The main interface to this library is the custom derive that generates modules from a GraphQL query and schema. See the docs for the [`GraphQLQuery`] trait for a full example.\n\n#![deny(missing_docs)]\n#![deny(rust_2018_idioms)]\n#![deny(warnings)]\n\n#[allow(unused_imports)]\n#[macro_use]\nextern crate graphql_query_derive;\n\n#[doc(hidden)]\npub use graphql_query_derive::*;\n\nuse serde::*;\n\n#[cfg(feature = \"web\")]\npub mod web;\n\nuse std::collections::HashMap;\nuse std::fmt::{self, Display};\n\ndoc_comment::doctest!(\"../../README.md\");\n\n/// A convenience trait that can be used to build a GraphQL request body.\n///\n/// This will be implemented for you by codegen in the normal case. It is implemented on the struct you place the derive on.\n///\n/// Example:\n///\n/// ```\n/// use graphql_client::*;\n/// use serde_json::json;\n///\n/// #[derive(GraphQLQuery)]\n/// #[graphql(\n/// query_path = \"../graphql_client_codegen/src/tests/star_wars_query.graphql\",\n/// schema_path = \"../graphql_client_codegen/src/tests/star_wars_schema.graphql\"\n/// )]\n/// struct StarWarsQuery;\n///\n/// fn main() -> Result<(), failure::Error> {\n/// use graphql_client::GraphQLQuery;\n///\n/// let variables = star_wars_query::Variables {\n/// episode_for_hero: star_wars_query::Episode::NEWHOPE,\n/// };\n///\n/// let expected_body = json!({\n/// \"operationName\": star_wars_query::OPERATION_NAME,\n/// \"query\": star_wars_query::QUERY,\n/// \"variables\": {\n/// \"episodeForHero\": \"NEWHOPE\"\n/// },\n/// });\n///\n/// let actual_body = serde_json::to_value(\n/// StarWarsQuery::build_query(variables)\n/// )?;\n///\n/// assert_eq!(actual_body, expected_body);\n///\n/// Ok(())\n/// }\n/// ```\npub trait GraphQLQuery {\n /// The shape of the variables expected by the query. This should be a generated struct most of the time.\n type Variables: serde::Serialize;\n /// The top-level shape of the response data (the `data` field in the GraphQL response). In practice this should be generated, since it is hard to write by hand without error.\n type ResponseData: for<'de> serde::Deserialize<'de>;\n\n /// Produce a GraphQL query struct that can be JSON serialized and sent to a GraphQL API.\n fn build_query(variables: Self::Variables) -> QueryBody<Self::Variables>;\n}\n\n/// The form in which queries are sent over HTTP in most implementations. This will be built using the [`GraphQLQuery`] trait normally.\n#[derive(Debug, Serialize, Deserialize)]\npub struct QueryBody<Variables> {\n /// The values for the variables. They must match those declared in the queries. This should be the `Variables` struct from the generated module corresponding to the query.\n pub variables: Variables,\n /// The GraphQL query, as a string.\n pub query: &'static str,\n /// The GraphQL operation name, as a string.\n #[serde(rename = \"operationName\")]\n pub operation_name: &'static str,\n}\n\n/// Represents a location inside a query string. Used in errors. See [`Error`].\n#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]\npub struct Location {\n /// The line number in the query string where the error originated (starting from 1).\n pub line: i32,\n /// The column number in the query string where the error originated (starting from 1).\n pub column: i32,\n}\n\n/// Part of a path in a query. It can be an object key or an array index. See [`Error`].\n#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]\n#[serde(untagged)]\npub enum PathFragment {\n /// A key inside an object\n Key(String),\n /// An index inside an array\n Index(i32),\n}\n\nimpl Display for PathFragment {\n fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n match *self {\n PathFragment::Key(ref key) => write!(f, \"{}\", key),\n PathFragment::Index(ref idx) => write!(f, \"{}\", idx),\n }\n }\n}\n\n/// An element in the top-level `errors` array of a response body.\n///\n/// This tries to be as close to the spec as possible.\n///\n/// [Spec](https://github.com/facebook/graphql/blob/master/spec/Section%207%20--%20Response.md)\n///\n///\n/// ```\n/// # use serde_json::json;\n/// # use serde::Deserialize;\n/// # use graphql_client::GraphQLQuery;\n/// #\n/// # #[derive(Debug, Deserialize, PartialEq)]\n/// # struct ResponseData {\n/// # something: i32\n/// # }\n/// #\n/// # fn main() -> Result<(), failure::Error> {\n/// use graphql_client::*;\n///\n/// let body: Response<ResponseData> = serde_json::from_value(json!({\n/// \"data\": null,\n/// \"errors\": [\n/// {\n/// \"message\": \"The server crashed. Sorry.\",\n/// \"locations\": [{ \"line\": 1, \"column\": 1 }]\n/// },\n/// {\n/// \"message\": \"Seismic activity detected\",\n/// \"path\": [\"underground\", 20]\n/// },\n/// ],\n/// }))?;\n///\n/// let expected: Response<ResponseData> = Response {\n/// data: None,\n/// errors: Some(vec![\n/// Error {\n/// message: \"The server crashed. Sorry.\".to_owned(),\n/// locations: Some(vec![\n/// Location {\n/// line: 1,\n/// column: 1,\n/// }\n/// ]),\n/// path: None,\n/// extensions: None,\n/// },\n/// Error {\n/// message: \"Seismic activity detected\".to_owned(),\n/// locations: None,\n/// path: Some(vec![\n/// PathFragment::Key(\"underground\".into()),\n/// PathFragment::Index(20),\n/// ]),\n/// extensions: None,\n/// },\n/// ]),\n/// };\n///\n/// assert_eq!(body, expected);\n///\n/// # Ok(())\n/// # }\n/// ```\n#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]\npub struct Error {\n /// The human-readable error message. This is the only required field.\n pub message: String,\n /// Which locations in the query the error applies to.\n pub locations: Option<Vec<Location>>,\n /// Which path in the query the error applies to, e.g. `[\"users\", 0, \"email\"]`.\n pub path: Option<Vec<PathFragment>>,\n /// Additional errors. Their exact format is defined by the server.\n pub extensions: Option<HashMap<String, serde_json::Value>>,\n}\n\nimpl Display for Error {\n fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n // Use `/` as a separator like JSON Pointer.\n let path = self\n .path\n .as_ref()\n .map(|fragments| {\n fragments\n .iter()\n .fold(String::new(), |mut acc, item| {\n acc.push_str(&format!(\"{}/\", item));\n acc\n })\n .trim_end_matches('/')\n .to_string()\n })\n .unwrap_or_else(|| \"<query>\".to_string());\n\n // Get the location of the error. We'll use just the first location for this.\n let loc = self\n .locations\n .as_ref()\n .and_then(|locations| locations.iter().next())\n .cloned()\n .unwrap_or_else(Location::default);\n\n write!(f, \"{}:{}:{}: {}\", path, loc.line, loc.column, self.message)\n }\n}\n\n/// The generic shape taken by the responses of GraphQL APIs.\n///\n/// This will generally be used with the `ResponseData` struct from a derived module.\n///\n/// [Spec](https://github.com/facebook/graphql/blob/master/spec/Section%207%20--%20Response.md)\n///\n/// ```\n/// # use serde_json::json;\n/// # use serde::Deserialize;\n/// # use graphql_client::GraphQLQuery;\n/// #\n/// # #[derive(Debug, Deserialize, PartialEq)]\n/// # struct User {\n/// # id: i32,\n/// # }\n/// #\n/// # #[derive(Debug, Deserialize, PartialEq)]\n/// # struct Dog {\n/// # name: String\n/// # }\n/// #\n/// # #[derive(Debug, Deserialize, PartialEq)]\n/// # struct ResponseData {\n/// # users: Vec<User>,\n/// # dogs: Vec<Dog>,\n/// # }\n/// #\n/// # fn main() -> Result<(), failure::Error> {\n/// use graphql_client::Response;\n///\n/// let body: Response<ResponseData> = serde_json::from_value(json!({\n/// \"data\": {\n/// \"users\": [{\"id\": 13}],\n/// \"dogs\": [{\"name\": \"Strelka\"}],\n/// },\n/// \"errors\": [],\n/// }))?;\n///\n/// let expected: Response<ResponseData> = Response {\n/// data: Some(ResponseData {\n/// users: vec![User { id: 13 }],\n/// dogs: vec![Dog { name: \"Strelka\".to_owned() }],\n/// }),\n/// errors: Some(vec![]),\n/// };\n///\n/// assert_eq!(body, expected);\n///\n/// # Ok(())\n/// # }\n/// ```\n#[derive(Debug, Serialize, Deserialize, PartialEq)]\npub struct Response<Data> {\n /// The absent, partial or complete response data.\n pub data: Option<Data>,\n /// The top-level errors returned by the server.\n pub errors: Option<Vec<Error>>,\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n use serde_json::json;\n\n #[test]\n fn graphql_error_works_with_just_message() {\n let err = json!({\n \"message\": \"I accidentally your whole query\"\n });\n\n let deserialized_error: Error = serde_json::from_value(err).unwrap();\n\n assert_eq!(\n deserialized_error,\n Error {\n message: \"I accidentally your whole query\".to_string(),\n locations: None,\n path: None,\n extensions: None,\n }\n )\n }\n\n #[test]\n fn full_graphql_error_deserialization() {\n let err = json!({\n \"message\": \"I accidentally your whole query\",\n \"locations\": [{ \"line\": 3, \"column\": 13}, {\"line\": 56, \"column\": 1}],\n \"path\": [\"home\", \"alone\", 3, \"rating\"]\n });\n\n let deserialized_error: Error = serde_json::from_value(err).unwrap();\n\n assert_eq!(\n deserialized_error,\n Error {\n message: \"I accidentally your whole query\".to_string(),\n locations: Some(vec![\n Location {\n line: 3,\n column: 13,\n },\n Location {\n line: 56,\n column: 1,\n },\n ]),\n path: Some(vec![\n PathFragment::Key(\"home\".to_owned()),\n PathFragment::Key(\"alone\".to_owned()),\n PathFragment::Index(3),\n PathFragment::Key(\"rating\".to_owned()),\n ]),\n extensions: None,\n }\n )\n }\n\n #[test]\n fn full_graphql_error_with_extensions_deserialization() {\n let err = json!({\n \"message\": \"I accidentally your whole query\",\n \"locations\": [{ \"line\": 3, \"column\": 13}, {\"line\": 56, \"column\": 1}],\n \"path\": [\"home\", \"alone\", 3, \"rating\"],\n \"extensions\": {\n \"code\": \"CAN_NOT_FETCH_BY_ID\",\n \"timestamp\": \"Fri Feb 9 14:33:09 UTC 2018\"\n }\n });\n\n let deserialized_error: Error = serde_json::from_value(err).unwrap();\n\n let mut expected_extensions = HashMap::new();\n expected_extensions.insert(\"code\".to_owned(), json!(\"CAN_NOT_FETCH_BY_ID\"));\n expected_extensions.insert(\"timestamp\".to_owned(), json!(\"Fri Feb 9 14:33:09 UTC 2018\"));\n let expected_extensions = Some(expected_extensions);\n\n assert_eq!(\n deserialized_error,\n Error {\n message: \"I accidentally your whole query\".to_string(),\n locations: Some(vec![\n Location {\n line: 3,\n column: 13,\n },\n Location {\n line: 56,\n column: 1,\n },\n ]),\n path: Some(vec![\n PathFragment::Key(\"home\".to_owned()),\n PathFragment::Key(\"alone\".to_owned()),\n PathFragment::Index(3),\n PathFragment::Key(\"rating\".to_owned()),\n ]),\n extensions: expected_extensions,\n }\n )\n }\n}\n", uri = "file:///home/h-michael/go/src/github.com/h-michael/graphql-client/graphql_client/src/lib.rs", version = 0 }} | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:271 ] "rpc.send.payload" { jsonrpc = "2.0", method = "textDocument/didOpen", params = { textDocument = { languageId = "rust", text = "//! The top-level documentation resides on the [project README](https://github.com/graphql-rust/graphql-client) at the moment.\n//!\n//! The main interface to this library is the custom derive that generates modules from a GraphQL query and schema. See the docs for the [`GraphQLQuery`] trait for a full example.\n\n#![deny(missing_docs)]\n#![deny(rust_2018_idioms)]\n#![deny(warnings)]\n\n#[allow(unused_imports)]\n#[macro_use]\nextern crate graphql_query_derive;\n\n#[doc(hidden)]\npub use graphql_query_derive::*;\n\nuse serde::*;\n\n#[cfg(feature = \"web\")]\npub mod web;\n\nuse std::collections::HashMap;\nuse std::fmt::{self, Display};\n\ndoc_comment::doctest!(\"../../README.md\");\n\n/// A convenience trait that can be used to build a GraphQL request body.\n///\n/// This will be implemented for you by codegen in the normal case. It is implemented on the struct you place the derive on.\n///\n/// Example:\n///\n/// ```\n/// use graphql_client::*;\n/// use serde_json::json;\n///\n/// #[derive(GraphQLQuery)]\n/// #[graphql(\n/// query_path = \"../graphql_client_codegen/src/tests/star_wars_query.graphql\",\n/// schema_path = \"../graphql_client_codegen/src/tests/star_wars_schema.graphql\"\n/// )]\n/// struct StarWarsQuery;\n///\n/// fn main() -> Result<(), failure::Error> {\n/// use graphql_client::GraphQLQuery;\n///\n/// let variables = star_wars_query::Variables {\n/// episode_for_hero: star_wars_query::Episode::NEWHOPE,\n/// };\n///\n/// let expected_body = json!({\n/// \"operationName\": star_wars_query::OPERATION_NAME,\n/// \"query\": star_wars_query::QUERY,\n/// \"variables\": {\n/// \"episodeForHero\": \"NEWHOPE\"\n/// },\n/// });\n///\n/// let actual_body = serde_json::to_value(\n/// StarWarsQuery::build_query(variables)\n/// )?;\n///\n/// assert_eq!(actual_body, expected_body);\n///\n/// Ok(())\n/// }\n/// ```\npub trait GraphQLQuery {\n /// The shape of the variables expected by the query. This should be a generated struct most of the time.\n type Variables: serde::Serialize;\n /// The top-level shape of the response data (the `data` field in the GraphQL response). In practice this should be generated, since it is hard to write by hand without error.\n type ResponseData: for<'de> serde::Deserialize<'de>;\n\n /// Produce a GraphQL query struct that can be JSON serialized and sent to a GraphQL API.\n fn build_query(variables: Self::Variables) -> QueryBody<Self::Variables>;\n}\n\n/// The form in which queries are sent over HTTP in most implementations. This will be built using the [`GraphQLQuery`] trait normally.\n#[derive(Debug, Serialize, Deserialize)]\npub struct QueryBody<Variables> {\n /// The values for the variables. They must match those declared in the queries. This should be the `Variables` struct from the generated module corresponding to the query.\n pub variables: Variables,\n /// The GraphQL query, as a string.\n pub query: &'static str,\n /// The GraphQL operation name, as a string.\n #[serde(rename = \"operationName\")]\n pub operation_name: &'static str,\n}\n\n/// Represents a location inside a query string. Used in errors. See [`Error`].\n#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]\npub struct Location {\n /// The line number in the query string where the error originated (starting from 1).\n pub line: i32,\n /// The column number in the query string where the error originated (starting from 1).\n pub column: i32,\n}\n\n/// Part of a path in a query. It can be an object key or an array index. See [`Error`].\n#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]\n#[serde(untagged)]\npub enum PathFragment {\n /// A key inside an object\n Key(String),\n /// An index inside an array\n Index(i32),\n}\n\nimpl Display for PathFragment {\n fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n match *self {\n PathFragment::Key(ref key) => write!(f, \"{}\", key),\n PathFragment::Index(ref idx) => write!(f, \"{}\", idx),\n }\n }\n}\n\n/// An element in the top-level `errors` array of a response body.\n///\n/// This tries to be as close to the spec as possible.\n///\n/// [Spec](https://github.com/facebook/graphql/blob/master/spec/Section%207%20--%20Response.md)\n///\n///\n/// ```\n/// # use serde_json::json;\n/// # use serde::Deserialize;\n/// # use graphql_client::GraphQLQuery;\n/// #\n/// # #[derive(Debug, Deserialize, PartialEq)]\n/// # struct ResponseData {\n/// # something: i32\n/// # }\n/// #\n/// # fn main() -> Result<(), failure::Error> {\n/// use graphql_client::*;\n///\n/// let body: Response<ResponseData> = serde_json::from_value(json!({\n/// \"data\": null,\n/// \"errors\": [\n/// {\n/// \"message\": \"The server crashed. Sorry.\",\n/// \"locations\": [{ \"line\": 1, \"column\": 1 }]\n/// },\n/// {\n/// \"message\": \"Seismic activity detected\",\n/// \"path\": [\"underground\", 20]\n/// },\n/// ],\n/// }))?;\n///\n/// let expected: Response<ResponseData> = Response {\n/// data: None,\n/// errors: Some(vec![\n/// Error {\n/// message: \"The server crashed. Sorry.\".to_owned(),\n/// locations: Some(vec![\n/// Location {\n/// line: 1,\n/// column: 1,\n/// }\n/// ]),\n/// path: None,\n/// extensions: None,\n/// },\n/// Error {\n/// message: \"Seismic activity detected\".to_owned(),\n/// locations: None,\n/// path: Some(vec![\n/// PathFragment::Key(\"underground\".into()),\n/// PathFragment::Index(20),\n/// ]),\n/// extensions: None,\n/// },\n/// ]),\n/// };\n///\n/// assert_eq!(body, expected);\n///\n/// # Ok(())\n/// # }\n/// ```\n#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]\npub struct Error {\n /// The human-readable error message. This is the only required field.\n pub message: String,\n /// Which locations in the query the error applies to.\n pub locations: Option<Vec<Location>>,\n /// Which path in the query the error applies to, e.g. `[\"users\", 0, \"email\"]`.\n pub path: Option<Vec<PathFragment>>,\n /// Additional errors. Their exact format is defined by the server.\n pub extensions: Option<HashMap<String, serde_json::Value>>,\n}\n\nimpl Display for Error {\n fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n // Use `/` as a separator like JSON Pointer.\n let path = self\n .path\n .as_ref()\n .map(|fragments| {\n fragments\n .iter()\n .fold(String::new(), |mut acc, item| {\n acc.push_str(&format!(\"{}/\", item));\n acc\n })\n .trim_end_matches('/')\n .to_string()\n })\n .unwrap_or_else(|| \"<query>\".to_string());\n\n // Get the location of the error. We'll use just the first location for this.\n let loc = self\n .locations\n .as_ref()\n .and_then(|locations| locations.iter().next())\n .cloned()\n .unwrap_or_else(Location::default);\n\n write!(f, \"{}:{}:{}: {}\", path, loc.line, loc.column, self.message)\n }\n}\n\n/// The generic shape taken by the responses of GraphQL APIs.\n///\n/// This will generally be used with the `ResponseData` struct from a derived module.\n///\n/// [Spec](https://github.com/facebook/graphql/blob/master/spec/Section%207%20--%20Response.md)\n///\n/// ```\n/// # use serde_json::json;\n/// # use serde::Deserialize;\n/// # use graphql_client::GraphQLQuery;\n/// #\n/// # #[derive(Debug, Deserialize, PartialEq)]\n/// # struct User {\n/// # id: i32,\n/// # }\n/// #\n/// # #[derive(Debug, Deserialize, PartialEq)]\n/// # struct Dog {\n/// # name: String\n/// # }\n/// #\n/// # #[derive(Debug, Deserialize, PartialEq)]\n/// # struct ResponseData {\n/// # users: Vec<User>,\n/// # dogs: Vec<Dog>,\n/// # }\n/// #\n/// # fn main() -> Result<(), failure::Error> {\n/// use graphql_client::Response;\n///\n/// let body: Response<ResponseData> = serde_json::from_value(json!({\n/// \"data\": {\n/// \"users\": [{\"id\": 13}],\n/// \"dogs\": [{\"name\": \"Strelka\"}],\n/// },\n/// \"errors\": [],\n/// }))?;\n///\n/// let expected: Response<ResponseData> = Response {\n/// data: Some(ResponseData {\n/// users: vec![User { id: 13 }],\n/// dogs: vec![Dog { name: \"Strelka\".to_owned() }],\n/// }),\n/// errors: Some(vec![]),\n/// };\n///\n/// assert_eq!(body, expected);\n///\n/// # Ok(())\n/// # }\n/// ```\n#[derive(Debug, Serialize, Deserialize, PartialEq)]\npub struct Response<Data> {\n /// The absent, partial or complete response data.\n pub data: Option<Data>,\n /// The top-level errors returned by the server.\n pub errors: Option<Vec<Error>>,\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n use serde_json::json;\n\n #[test]\n fn graphql_error_works_with_just_message() {\n let err = json!({\n \"message\": \"I accidentally your whole query\"\n });\n\n let deserialized_error: Error = serde_json::from_value(err).unwrap();\n\n assert_eq!(\n deserialized_error,\n Error {\n message: \"I accidentally your whole query\".to_string(),\n locations: None,\n path: None,\n extensions: None,\n }\n )\n }\n\n #[test]\n fn full_graphql_error_deserialization() {\n let err = json!({\n \"message\": \"I accidentally your whole query\",\n \"locations\": [{ \"line\": 3, \"column\": 13}, {\"line\": 56, \"column\": 1}],\n \"path\": [\"home\", \"alone\", 3, \"rating\"]\n });\n\n let deserialized_error: Error = serde_json::from_value(err).unwrap();\n\n assert_eq!(\n deserialized_error,\n Error {\n message: \"I accidentally your whole query\".to_string(),\n locations: Some(vec![\n Location {\n line: 3,\n column: 13,\n },\n Location {\n line: 56,\n column: 1,\n },\n ]),\n path: Some(vec![\n PathFragment::Key(\"home\".to_owned()),\n PathFragment::Key(\"alone\".to_owned()),\n PathFragment::Index(3),\n PathFragment::Key(\"rating\".to_owned()),\n ]),\n extensions: None,\n }\n )\n }\n\n #[test]\n fn full_graphql_error_with_extensions_deserialization() {\n let err = json!({\n \"message\": \"I accidentally your whole query\",\n \"locations\": [{ \"line\": 3, \"column\": 13}, {\"line\": 56, \"column\": 1}],\n \"path\": [\"home\", \"alone\", 3, \"rating\"],\n \"extensions\": {\n \"code\": \"CAN_NOT_FETCH_BY_ID\",\n \"timestamp\": \"Fri Feb 9 14:33:09 UTC 2018\"\n }\n });\n\n let deserialized_error: Error = serde_json::from_value(err).unwrap();\n\n let mut expected_extensions = HashMap::new();\n expected_extensions.insert(\"code\".to_owned(), json!(\"CAN_NOT_FETCH_BY_ID\"));\n expected_extensions.insert(\"timestamp\".to_owned(), json!(\"Fri Feb 9 14:33:09 UTC 2018\"));\n let expected_extensions = Some(expected_extensions);\n\n assert_eq!(\n deserialized_error,\n Error {\n message: \"I accidentally your whole query\".to_string(),\n locations: Some(vec![\n Location {\n line: 3,\n column: 13,\n },\n Location {\n line: 56,\n column: 1,\n },\n ]),\n path: Some(vec![\n PathFragment::Key(\"home\".to_owned()),\n PathFragment::Key(\"alone\".to_owned()),\n PathFragment::Index(3),\n PathFragment::Key(\"rating\".to_owned()),\n ]),\n extensions: expected_extensions,\n }\n )\n }\n}\n", uri = "file:///home/h-michael/go/src/github.com/h-michael/graphql-client/graphql_client/src/lib.rs", version = 0 } }} | |
[ ERROR ] 2020-02-12T17:11:02Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:321 ] "rpc" "ra_lsp_server" "stderr" "[ERROR ra_lsp_server] Failed to deserialize config: invalid length 0, expected struct ServerConfig with 12 elements; []\n" | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:351 ] "decoded" { jsonrpc = "2.0", method = "window/showMessage", params = { message = "Failed to deserialize config: invalid length 0, expected struct ServerConfig with 12 elements; []", type = 1 }} | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] /home/h-michael/.local/share/nvim/runtime/lua/vim/lsp.lua:371 ] "notification" "window/showMessage" { message = "Failed to deserialize config: invalid length 0, expected struct ServerConfig with 12 elements; []", type = 1} | |
[ DEBUG ] 2020-02-12T17:11:02Z+0900 ] ...hael/.local/share/nvim/runtime/lua/vim/lsp/callbacks.lua:246 ] "default_callback" "window/showMessage" { client_id = 1, params = { message = "Failed to deserialize config: invalid length 0, expected struct ServerConfig with 12 elements; []", type = 1 }} | |
[ DEBUG ] 2020-02-12T17:11:06Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:351 ] "decoded" { jsonrpc = "2.0", method = "window/showMessage", params = { message = "workspace loaded, 281 rust packages", type = 3 }} | |
[ DEBUG ] 2020-02-12T17:11:06Z+0900 ] /home/h-michael/.local/share/nvim/runtime/lua/vim/lsp.lua:371 ] "notification" "window/showMessage" { message = "workspace loaded, 281 rust packages", type = 3} | |
[ DEBUG ] 2020-02-12T17:11:06Z+0900 ] ...hael/.local/share/nvim/runtime/lua/vim/lsp/callbacks.lua:246 ] "default_callback" "window/showMessage" { client_id = 1, params = { message = "workspace loaded, 281 rust packages", type = 3 }} | |
[ DEBUG ] 2020-02-12T17:11:06Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:351 ] "decoded" { jsonrpc = "2.0", method = "$/progress", params = { token = "rustAnalyzer/cargoWatcher", value = { cancellable = false, kind = "begin", title = "Running 'cargo check'" } }} | |
[ DEBUG ] 2020-02-12T17:11:06Z+0900 ] /home/h-michael/.local/share/nvim/runtime/lua/vim/lsp.lua:371 ] "notification" "$/progress" { token = "rustAnalyzer/cargoWatcher", value = { cancellable = false, kind = "begin", title = "Running 'cargo check'" }} | |
[ DEBUG ] 2020-02-12T17:11:06Z+0900 ] .../h-michael/.local/share/nvim/runtime/lua/vim/lsp/rpc.lua:351 ] "decoded" { jsonrpc = "2.0", method = "$/progress", params = { token = "rustAnalyzer/cargoWatcher", value = { kind = "end" } }} | |
[ DEBUG ] 2020-02-12T17:11:06Z+0900 ] /home/h-michael/.local/share/nvim/runtime/lua/vim/lsp.lua:371 ] "notification" "$/progress" { token = "rustAnalyzer/cargoWatcher", value = { kind = "end" }} | |
[ INFO ] 2020-02-12T17:12:35Z+0900 ] /home/h-michael/.local/share/nvim/runtime/lua/vim/lsp.lua:800 ] "exit_handler" {} | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment