diff --git a/edgedb-protocol/Cargo.toml b/edgedb-protocol/Cargo.toml index e57b27e7..2d910893 100644 --- a/edgedb-protocol/Cargo.toml +++ b/edgedb-protocol/Cargo.toml @@ -22,6 +22,7 @@ chrono = {version="0.4.23", optional=true, features=["std"], default-features=fa edgedb-errors = {path = "../edgedb-errors", version = "0.4.0" } bitflags = "2.4.0" serde = {version="1.0.190", features = ["derive"], optional=true} +serde_json = {version="1", optional=true} [features] default = [] @@ -29,7 +30,7 @@ with-num-bigint = ["num-bigint", "num-traits"] with-bigdecimal = ["bigdecimal", "num-bigint", "num-traits"] with-chrono = ["chrono"] all-types = ["with-num-bigint", "with-bigdecimal", "with-chrono"] -with-serde = ["serde"] +with-serde = ["serde", "serde_json"] [dev-dependencies] rand = "0.8" diff --git a/edgedb-protocol/src/annotations.rs b/edgedb-protocol/src/annotations.rs new file mode 100644 index 00000000..d272fbb5 --- /dev/null +++ b/edgedb-protocol/src/annotations.rs @@ -0,0 +1,115 @@ +#[cfg(feature = "with-serde")] +use crate::encoding::Annotations; + +/// CommandDataDescription1 may contain "warnings" annotations, whose value is +/// a JSON array of this [Warning] type. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Warning { + /// User-friendly explanation of the problem + pub message: String, + + /// Name of the Python exception class + pub r#type: String, + + /// Machine-friendly exception id + pub code: u64, + + /// Name of the source file that caused the warning. + pub filename: Option, + + /// Additional user-friendly info + pub hint: Option, + + /// Developer-friendly explanation of why this problem occured + pub details: Option, + + /// Inclusive 0-based position within the source + #[cfg_attr( + feature = "with-serde", + serde(deserialize_with = "deserialize_usize_from_str") + )] + pub start: Option, + + /// Exclusive 0-based position within the source + #[cfg_attr( + feature = "with-serde", + serde(deserialize_with = "deserialize_usize_from_str") + )] + pub end: Option, + + /// 1-based index of the line of the start + #[cfg_attr( + feature = "with-serde", + serde(deserialize_with = "deserialize_usize_from_str") + )] + pub line: Option, + + /// 1-based index of the column of the start + #[cfg_attr( + feature = "with-serde", + serde(deserialize_with = "deserialize_usize_from_str") + )] + pub col: Option, +} + +impl std::fmt::Display for Warning { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Warning { + filename, + line, + col, + r#type, + message, + .. + } = self; + let filename = filename + .as_ref() + .map(|f| format!("{f}:")) + .unwrap_or_default(); + let line = line.clone().unwrap_or(1); + let col = col.clone().unwrap_or(1); + + write!(f, "{type} at {filename}{line}:{col} {message}") + } +} + +#[cfg(feature = "with-serde")] +pub fn decode_warnings(annotations: &Annotations) -> Result, edgedb_errors::Error> { + use edgedb_errors::{ErrorKind, ProtocolEncodingError}; + + const ANN_NAME: &str = "warnings"; + + if let Some(warnings) = annotations.get(ANN_NAME) { + serde_json::from_str::>(warnings).map_err(|e| { + ProtocolEncodingError::with_source(e) + .context("Invalid JSON while decoding 'warnings' annotation") + }) + } else { + Ok(vec![]) + } +} + +#[cfg(feature = "with-serde")] +fn deserialize_usize_from_str<'de, D: serde::Deserializer<'de>>( + deserializer: D, +) -> Result, D::Error> { + use serde::Deserialize; + + #[derive(Deserialize)] + #[serde(untagged)] + enum StringOrInt { + String(String), + Number(usize), + None, + } + + match StringOrInt::deserialize(deserializer)? { + StringOrInt::String(s) => s + .parse::() + .map_err(serde::de::Error::custom) + .map(Some), + StringOrInt::Number(i) => Ok(Some(i)), + StringOrInt::None => Ok(None), + } +} diff --git a/edgedb-protocol/src/errors.rs b/edgedb-protocol/src/errors.rs index 165e6e33..6d4a08f1 100644 --- a/edgedb-protocol/src/errors.rs +++ b/edgedb-protocol/src/errors.rs @@ -97,6 +97,11 @@ pub enum DecodeError { }, #[snafu(display("missing required link or property"))] MissingRequiredElement { backtrace: Backtrace }, + #[snafu(display("invalid format of {annotation} annotation"))] + InvalidAnnotationFormat { + backtrace: Backtrace, + annotation: &'static str, + }, } #[derive(Snafu, Debug)] diff --git a/edgedb-protocol/src/lib.rs b/edgedb-protocol/src/lib.rs index 743f618c..8062a608 100644 --- a/edgedb-protocol/src/lib.rs +++ b/edgedb-protocol/src/lib.rs @@ -73,6 +73,7 @@ pub mod server_message; pub mod value; #[macro_use] pub mod value_opt; +pub mod annotations; pub mod model; pub mod query_arg; diff --git a/edgedb-tokio/Cargo.toml b/edgedb-tokio/Cargo.toml index 2a50b4bf..e0e11db2 100644 --- a/edgedb-tokio/Cargo.toml +++ b/edgedb-tokio/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" rust-version.workspace = true [dependencies] -edgedb-protocol = { path = "../edgedb-protocol", version = "0.6.0" } +edgedb-protocol = { path = "../edgedb-protocol", version = "0.6.0", features = ["with-serde"] } edgedb-errors = { path = "../edgedb-errors", version = "0.4.1" } edgedb-derive = { path = "../edgedb-derive", version = "0.5.1", optional = true } tokio = { version = "1.15", features = ["net", "time", "sync", "macros"] } diff --git a/edgedb-tokio/src/client.rs b/edgedb-tokio/src/client.rs index 0d7a708f..934d2687 100644 --- a/edgedb-tokio/src/client.rs +++ b/edgedb-tokio/src/client.rs @@ -11,11 +11,12 @@ use crate::builder::Config; use crate::errors::NoDataError; use crate::errors::{Error, ErrorKind, SHOULD_RETRY}; use crate::options::{RetryOptions, TransactionOptions}; -use crate::raw::{Options, PoolState}; +use crate::raw::{Options, PoolState, Response}; use crate::raw::{Pool, QueryCapabilities}; use crate::state::{AliasesDelta, ConfigDelta, GlobalsDelta}; use crate::state::{AliasesModifier, ConfigModifier, Fn, GlobalsModifier}; use crate::transaction::{transaction, Transaction}; +use crate::ResultVerbose; /// The EdgeDB Client. /// @@ -56,13 +57,14 @@ impl Client { Ok(()) } - async fn query_and_retry( + /// Query with retry. + async fn query_helper( &self, query: impl AsRef, arguments: &A, io_format: IoFormat, cardinality: Cardinality, - ) -> Result, Error> + ) -> Result>, Error> where A: QueryArgs, R: QueryResult, @@ -85,7 +87,7 @@ impl Client { ) .await { - Ok(resp) => return Ok(resp.data), + Ok(resp) => return Ok(resp), Err(e) => { let allow_retry = match e.get::() { // Error from a weird source, or just a bug @@ -110,6 +112,31 @@ impl Client { } } + /// Execute a query and return a collection of results and warnings produced by the server. + /// + /// You will usually have to specify the return type for the query: + /// + /// ```rust,ignore + /// let greeting: (Vec, _) = conn.query_with_warnings("select 'hello'", &()).await?; + /// ``` + /// + /// This method can be used with both static arguments, like a tuple of + /// scalars, and with dynamic arguments [`edgedb_protocol::value::Value`]. + /// Similarly, dynamically typed results are also supported. + pub async fn query_verbose( + &self, + query: impl AsRef + Send, + arguments: &A, + ) -> Result>, Error> + where + A: QueryArgs, + R: QueryResult, + { + Client::query_helper(self, query, arguments, IoFormat::Binary, Cardinality::Many) + .await + .map(|Response { data, warnings, .. }| ResultVerbose { data, warnings }) + } + /// Execute a query and return a collection of results. /// /// You will usually have to specify the return type for the query: @@ -134,7 +161,9 @@ impl Client { A: QueryArgs, R: QueryResult, { - Client::query_and_retry(self, query, arguments, IoFormat::Binary, Cardinality::Many).await + Client::query_helper(self, query, arguments, IoFormat::Binary, Cardinality::Many) + .await + .map(|r| r.data) } /// Execute a query and return a single result @@ -162,7 +191,7 @@ impl Client { A: QueryArgs, R: QueryResult + Send, { - Client::query_and_retry( + Client::query_helper( self, query, arguments, @@ -170,7 +199,7 @@ impl Client { Cardinality::AtMostOne, ) .await - .map(|x| x.into_iter().next()) + .map(|x| x.data.into_iter().next()) } /// Execute a query and return a single result @@ -207,7 +236,7 @@ impl Client { A: QueryArgs, R: QueryResult + Send, { - Client::query_and_retry( + Client::query_helper( self, query, arguments, @@ -216,7 +245,8 @@ impl Client { ) .await .and_then(|x| { - x.into_iter() + x.data + .into_iter() .next() .ok_or_else(|| NoDataError::with_message("query row returned zero results")) }) @@ -229,10 +259,11 @@ impl Client { arguments: &impl QueryArgs, ) -> Result { let res = self - .query_and_retry::(query, arguments, IoFormat::Json, Cardinality::Many) + .query_helper::(query, arguments, IoFormat::Json, Cardinality::Many) .await?; let json = res + .data .into_iter() .next() .ok_or_else(|| NoDataError::with_message("query row returned zero results"))?; @@ -266,11 +297,11 @@ impl Client { arguments: &impl QueryArgs, ) -> Result, Error> { let res = self - .query_and_retry::(query, arguments, IoFormat::Json, Cardinality::AtMostOne) + .query_helper::(query, arguments, IoFormat::Json, Cardinality::AtMostOne) .await?; // we trust database to produce valid json - Ok(res.into_iter().next().map(Json::new_unchecked)) + Ok(res.data.into_iter().next().map(Json::new_unchecked)) } /// Execute a query and return a single result as JSON. diff --git a/edgedb-tokio/src/lib.rs b/edgedb-tokio/src/lib.rs index 4827270f..4f64b23b 100644 --- a/edgedb-tokio/src/lib.rs +++ b/edgedb-tokio/src/lib.rs @@ -146,7 +146,7 @@ pub use client::Client; pub use credentials::TlsSecurity; pub use errors::Error; pub use options::{RetryCondition, RetryOptions, TransactionOptions}; -pub use query_executor::QueryExecutor; +pub use query_executor::{QueryExecutor, ResultVerbose}; pub use state::{ConfigDelta, GlobalsDelta}; pub use transaction::Transaction; diff --git a/edgedb-tokio/src/query_executor.rs b/edgedb-tokio/src/query_executor.rs index ccf95e75..2f4b4933 100644 --- a/edgedb-tokio/src/query_executor.rs +++ b/edgedb-tokio/src/query_executor.rs @@ -1,10 +1,16 @@ -use edgedb_protocol::model::Json; use edgedb_protocol::query_arg::QueryArgs; use edgedb_protocol::QueryResult; +use edgedb_protocol::{annotations::Warning, model::Json}; use std::future::Future; use crate::{Client, Error, Transaction}; +#[non_exhaustive] +pub struct ResultVerbose { + pub data: R, + pub warnings: Vec, +} + /// Abstracts over different query executors /// In particular &Client and &mut Transaction pub trait QueryExecutor: Sized { @@ -18,6 +24,16 @@ pub trait QueryExecutor: Sized { A: QueryArgs, R: QueryResult + Send; + /// see [Client::query_with_warnings] + fn query_verbose( + self, + query: impl AsRef + Send, + arguments: &A, + ) -> impl Future>, Error>> + Send + where + A: QueryArgs, + R: QueryResult + Send; + /// see [Client::query_single] fn query_single( self, @@ -82,6 +98,18 @@ impl QueryExecutor for &Client { Client::query(self, query, arguments) } + fn query_verbose( + self, + query: impl AsRef + Send, + arguments: &A, + ) -> impl Future>, Error>> + Send + where + A: QueryArgs, + R: QueryResult + Send, + { + Client::query_verbose(self, query, arguments) + } + fn query_single( self, query: impl AsRef + Send, @@ -151,6 +179,18 @@ impl QueryExecutor for &mut Transaction { Transaction::query(self, query, arguments) } + fn query_verbose( + self, + query: impl AsRef + Send, + arguments: &A, + ) -> impl Future>, Error>> + Send + where + A: QueryArgs, + R: QueryResult + Send, + { + Transaction::query_verbose(self, query, arguments) + } + fn query_single( self, query: impl AsRef + Send, diff --git a/edgedb-tokio/src/raw/dumps.rs b/edgedb-tokio/src/raw/dumps.rs index ca47296e..c4c772f1 100644 --- a/edgedb-tokio/src/raw/dumps.rs +++ b/edgedb-tokio/src/raw/dumps.rs @@ -118,6 +118,7 @@ impl Connection { status_data: complete.status_data, new_state: None, data: (), + warnings: vec![], }); } ServerMessage::CommandComplete1(complete) => { @@ -127,6 +128,7 @@ impl Connection { status_data: complete.status_data, new_state: complete.state, data: (), + warnings: vec![], }); } ServerMessage::ErrorResponse(err) => { @@ -220,6 +222,7 @@ impl DumpStream<'_> { status_data: complete.status_data, new_state: None, data: (), + warnings: vec![], }); } None @@ -235,6 +238,7 @@ impl DumpStream<'_> { status_data: complete.status_data, new_state: complete.state, data: (), + warnings: vec![], }); } None diff --git a/edgedb-tokio/src/raw/mod.rs b/edgedb-tokio/src/raw/mod.rs index 7e33b2b3..a86b51fe 100644 --- a/edgedb-tokio/src/raw/mod.rs +++ b/edgedb-tokio/src/raw/mod.rs @@ -75,6 +75,7 @@ pub struct Response { pub status_data: Bytes, pub new_state: Option, pub data: T, + pub warnings: Vec, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -178,6 +179,13 @@ impl Response { status_data: self.status_data, new_state: self.new_state, data: f(self.data)?, + warnings: self.warnings, }) } + + fn log_warnings(&self) { + for w in &self.warnings { + log::warn!(target: "edgedb_tokio::warning", "{w}"); + } + } } diff --git a/edgedb-tokio/src/raw/queries.rs b/edgedb-tokio/src/raw/queries.rs index 03fb82af..d44e773f 100644 --- a/edgedb-tokio/src/raw/queries.rs +++ b/edgedb-tokio/src/raw/queries.rs @@ -248,12 +248,19 @@ impl Connection { let mut data = Vec::new(); let mut description = None; + let mut warnings: Vec = Vec::new(); loop { let msg = self.message().await?; match msg { ServerMessage::StateDataDescription(d) => { self.state_desc = d.typedesc; } + ServerMessage::CommandDataDescription1(desc) => { + warnings.extend(edgedb_protocol::annotations::decode_warnings( + &desc.annotations, + )?); + description = Some(desc); + } ServerMessage::Data(datum) => { data.push(datum); } @@ -263,11 +270,9 @@ impl Connection { status_data: complete.status_data, new_state: complete.state, data, + warnings, }); } - ServerMessage::CommandDataDescription1(desc) => { - description = Some(desc); - } ServerMessage::ErrorResponse(err) => { self.expect_ready_or_eos(guard) .await @@ -314,6 +319,7 @@ impl Connection { status_data: complete.status_data, new_state: None, data, + warnings: vec![], }); } ServerMessage::ErrorResponse(err) => { @@ -586,6 +592,7 @@ impl Connection { let response = self ._execute(&flags, query, state, &desc, &arg_buf.freeze()) .await?; + response.log_warnings(); let out_desc = desc.output().map_err(ProtocolEncodingError::with_source)?; match out_desc.root_pos() { @@ -639,10 +646,11 @@ impl Connection { return Err(e.set::(desc)); } - let res = self + let response = self ._execute(&flags, query, state, &desc, &arg_buf.freeze()) .await?; - res.map(|_| Ok::<_, Error>(())) + response.log_warnings(); + response.map(|_| Ok::<_, Error>(())) } .await; result.map_err(|e| e.set::(caps)) diff --git a/edgedb-tokio/src/raw/response.rs b/edgedb-tokio/src/raw/response.rs index 194c6fd3..84dfb95b 100644 --- a/edgedb-tokio/src/raw/response.rs +++ b/edgedb-tokio/src/raw/response.rs @@ -5,11 +5,12 @@ use bytes::Bytes; use edgedb_errors::ProtocolEncodingError; use edgedb_errors::{Error, ErrorKind}; use edgedb_errors::{ParameterTypeMismatchError, ProtocolOutOfOrderError}; +use edgedb_protocol::annotations::Warning; use edgedb_protocol::common::State; use edgedb_protocol::descriptors::Typedesc; use edgedb_protocol::server_message::CommandDataDescription1; use edgedb_protocol::server_message::{ErrorResponse, ServerMessage}; -use edgedb_protocol::QueryResult; +use edgedb_protocol::{annotations, QueryResult}; use crate::raw::queries::Guard; use crate::raw::{Connection, Description, Response}; @@ -34,6 +35,7 @@ where state: Option, guard: Option, description: Option, + warnings: Vec, } impl<'a, T: QueryResult> ResponseStream<'a, T> @@ -108,6 +110,11 @@ where } } } + let warnings = description + .as_ref() + .map(|d| annotations::decode_warnings(&d.annotations)) + .transpose()? + .unwrap_or_default(); let computed_desc = description .as_ref() .map(|d| d.output()) @@ -123,6 +130,7 @@ where state: Some(state), guard, description, + warnings, }) } else { Ok(ResponseStream { @@ -131,6 +139,7 @@ where state: None, guard, description, + warnings, }) } } @@ -268,6 +277,9 @@ where } } } + pub fn warnings(&self) -> &[Warning] { + &self.warnings + } pub async fn complete(mut self) -> Result, Error> { self.process_complete().await } @@ -282,11 +294,17 @@ where Complete { status_data, new_state, - } => Ok(Response { - status_data, - new_state, - data: (), - }), + } => { + let warnings = std::mem::take(&mut self.warnings); + let response = Response { + status_data, + new_state, + data: (), + warnings, + }; + response.log_warnings(); + Ok(response) + } Error(e) => Err(e), ErrorResponse(e) => { let mut err: edgedb_errors::Error = e.into(); diff --git a/edgedb-tokio/src/transaction.rs b/edgedb-tokio/src/transaction.rs index 19eee357..3ca645e2 100644 --- a/edgedb-tokio/src/transaction.rs +++ b/edgedb-tokio/src/transaction.rs @@ -13,7 +13,8 @@ use tokio::time::sleep; use crate::errors::ClientError; use crate::errors::{Error, ErrorKind, SHOULD_RETRY}; use crate::errors::{NoDataError, ProtocolEncodingError}; -use crate::raw::{Options, Pool, PoolConnection, PoolState}; +use crate::raw::{Options, Pool, PoolConnection, PoolState, Response}; +use crate::ResultVerbose; /// Transaction object passed to the closure via /// [`Client::transaction()`](crate::Client::transaction) method @@ -156,7 +157,7 @@ impl Transaction { arguments: &A, io_format: IoFormat, cardinality: Cardinality, - ) -> Result, Error> + ) -> Result>, Error> where A: QueryArgs, R: QueryResult, @@ -175,7 +176,6 @@ impl Transaction { cardinality, ) .await - .map(|x| x.data) } /// Execute a query and return a collection of results. @@ -183,9 +183,9 @@ impl Transaction { /// You will usually have to specify the return type for the query: /// /// ```rust,ignore - /// let greeting = pool.query::("SELECT 'hello'", &()); + /// let greeting = tran.query::("SELECT 'hello'", &()); /// // or - /// let greeting: Vec = pool.query("SELECT 'hello'", &()); + /// let greeting: Vec = tran.query("SELECT 'hello'", &()); /// ``` /// /// This method can be used with both static arguments, like a tuple of @@ -202,6 +202,32 @@ impl Transaction { { self.query_helper(query, arguments, IoFormat::Binary, Cardinality::Many) .await + .map(|x| x.data) + } + + /// Execute a query and return a collection of results and warnings produced by the server. + /// + /// You will usually have to specify the return type for the query: + /// + /// ```rust,ignore + /// let greeting: (Vec, _) = tran.query_with_warnings("select 'hello'", &()).await?; + /// ``` + /// + /// This method can be used with both static arguments, like a tuple of + /// scalars, and with dynamic arguments [`edgedb_protocol::value::Value`]. + /// Similarly, dynamically typed results are also supported. + pub async fn query_verbose( + &mut self, + query: impl AsRef + Send, + arguments: &A, + ) -> Result>, Error> + where + A: QueryArgs, + R: QueryResult, + { + self.query_helper(query, arguments, IoFormat::Binary, Cardinality::Many) + .await + .map(|Response { data, warnings, .. }| ResultVerbose { data, warnings }) } /// Execute a query and return a single result @@ -215,12 +241,12 @@ impl Transaction { /// You will usually have to specify the return type for the query: /// /// ```rust,ignore - /// let greeting = pool.query_required_single::( + /// let greeting = tran.query_required_single::( /// "SELECT 'hello'", /// &(), /// ); /// // or - /// let greeting: String = pool.query_required_single( + /// let greeting: String = tran.query_required_single( /// "SELECT 'hello'", /// &(), /// ); @@ -240,7 +266,7 @@ impl Transaction { { self.query_helper(query, arguments, IoFormat::Binary, Cardinality::AtMostOne) .await - .map(|x| x.into_iter().next()) + .map(|x| x.data.into_iter().next()) } /// Execute a query and return a single result @@ -254,12 +280,12 @@ impl Transaction { /// You will usually have to specify the return type for the query: /// /// ```rust,ignore - /// let greeting = pool.query_required_single::( + /// let greeting = tran.query_required_single::( /// "SELECT 'hello'", /// &(), /// ); /// // or - /// let greeting: String = pool.query_required_single( + /// let greeting: String = tran.query_required_single( /// "SELECT 'hello'", /// &(), /// ); @@ -280,7 +306,8 @@ impl Transaction { self.query_helper(query, arguments, IoFormat::Binary, Cardinality::AtMostOne) .await .and_then(|x| { - x.into_iter() + x.data + .into_iter() .next() .ok_or_else(|| NoDataError::with_message("query row returned zero results")) }) @@ -297,6 +324,7 @@ impl Transaction { .await?; let json = res + .data .into_iter() .next() .ok_or_else(|| NoDataError::with_message("query row returned zero results"))?; @@ -321,7 +349,7 @@ impl Transaction { .await?; // we trust database to produce valid json - Ok(res.into_iter().next().map(Json::new_unchecked)) + Ok(res.data.into_iter().next().map(Json::new_unchecked)) } /// Execute a query and return a single result as JSON. diff --git a/edgedb-tokio/tests/func/client.rs b/edgedb-tokio/tests/func/client.rs index 64d5a864..2c94330e 100644 --- a/edgedb-tokio/tests/func/client.rs +++ b/edgedb-tokio/tests/func/client.rs @@ -279,3 +279,19 @@ async fn wrong_field_number() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test] +async fn warnings() -> anyhow::Result<()> { + let client = Client::new(&SERVER.config); + client.ensure_connected().await?; + + let res = client + .query_verbose::("select std::_warn_on_call()", &()) + .await + .unwrap(); + assert_eq!(res.warnings.len(), 1); + + // TODO: test that the warning is logged + + Ok(()) +} diff --git a/flake.lock b/flake.lock index 44407eda..c99756ff 100644 --- a/flake.lock +++ b/flake.lock @@ -35,11 +35,11 @@ ] }, "locked": { - "lastModified": 1720422321, - "narHash": "sha256-6AOBQSP17xz0JjE5pI/ao/cFhMw6CiWJIE0NfxmAm34=", + "lastModified": 1728494477, + "narHash": "sha256-cbDdK/BlNmvqUXnUi2zWpR9bgHAWIjLr9en2ujLHMM0=", "owner": "edgedb", "repo": "packages-nix", - "rev": "ec9d4c9bbde1e95e5b087163e96ceb707b485530", + "rev": "eb1a1ac4f0f41b1b918baa3ce88baac7647b6a5b", "type": "github" }, "original": { @@ -56,11 +56,11 @@ "rust-analyzer-src": [] }, "locked": { - "lastModified": 1723012113, - "narHash": "sha256-AJGsmwDnheWMjZWUqgiGtBjbxMmvLvMp5WJhmTRhJ4w=", + "lastModified": 1728455642, + "narHash": "sha256-abYGwrL6ak5sBRqwPh+V3CPJ6Pa89p378t51b7BO1lE=", "owner": "nix-community", "repo": "fenix", - "rev": "3dab4ada5b0c5a22d56dbfd7e140c16f3df2e69a", + "rev": "3b47535a5c782e4f4ad59cd4bdb23636b6926e03", "type": "github" }, "original": { @@ -74,11 +74,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1722555600, - "narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=", + "lastModified": 1727826117, + "narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "8471fe90ad337a8074e957b69ca4d0089218391d", + "rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1", "type": "github" }, "original": { @@ -89,11 +89,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1723031421, - "narHash": "sha256-Q4iMzihS+4mzCadp+ADr782Jrd1Mgvr7lLZbkWx33Hw=", + "lastModified": 1728493385, + "narHash": "sha256-ryNG62K/XVIKt9/bBQxcavi3NOD/KHU2QRR+N4Z5xQA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "1602c0d3c0247d23eb7ca501c3e592aa1762e37b", + "rev": "516e84444d8aaaca070aba846b9c1015452f1a00", "type": "github" }, "original": { @@ -104,14 +104,14 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1722555339, - "narHash": "sha256-uFf2QeW7eAHlYXuDktm9c25OxOyCoUOQmh5SZ9amE5Q=", + "lastModified": 1727825735, + "narHash": "sha256-0xHYkMkeLVQAMa7gvkddbPqpxph+hDzdu1XdGPJR+Os=", "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz" + "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" }, "original": { "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz" + "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" } }, "root": { diff --git a/flake.nix b/flake.nix index 4d253c9c..216f4382 100644 --- a/flake.nix +++ b/flake.nix @@ -30,7 +30,7 @@ pkgs.just # needed for tests - edgedb.packages.${system}.edgedb-server + edgedb.packages.${system}.edgedb-server-nightly edgedb.packages.${system}.edgedb-cli ] ++ pkgs.lib.optional pkgs.stdenv.isDarwin [