Add unspecified resource (#4577)
This commit is contained in:
parent
07d834ef1c
commit
a9e6efd9b1
10 changed files with 128 additions and 18 deletions
|
@ -296,15 +296,27 @@ pub trait RpcContext {
|
|||
// Return a single result?
|
||||
let one = what.is_thing_single();
|
||||
// Specify the SQL query string
|
||||
let sql = "INSERT INTO $what $data RETURN AFTER";
|
||||
// Specify the query parameters
|
||||
let var = Some(map! {
|
||||
String::from("what") => what.could_be_table(),
|
||||
String::from("data") => data,
|
||||
=> &self.vars()
|
||||
});
|
||||
// Execute the query on the database
|
||||
let mut res = self.kvs().execute(sql, self.session(), var).await?;
|
||||
|
||||
let mut res = match what {
|
||||
Value::None | Value::Null => {
|
||||
let sql = "INSERT $data RETURN AFTER";
|
||||
let var = Some(map! {
|
||||
String::from("data") => data,
|
||||
=> &self.vars()
|
||||
});
|
||||
self.kvs().execute(sql, self.session(), var).await?
|
||||
}
|
||||
what => {
|
||||
let sql = "INSERT INTO $what $data RETURN AFTER";
|
||||
let var = Some(map! {
|
||||
String::from("what") => what.could_be_table(),
|
||||
String::from("data") => data,
|
||||
=> &self.vars()
|
||||
});
|
||||
self.kvs().execute(sql, self.session(), var).await?
|
||||
}
|
||||
};
|
||||
|
||||
// Extract the first query result
|
||||
let res = match one {
|
||||
true => res.remove(0).result?.first(),
|
||||
|
|
|
@ -43,7 +43,7 @@ pub(crate) enum Command {
|
|||
},
|
||||
Insert {
|
||||
// inserts can only be on a table.
|
||||
what: String,
|
||||
what: Option<String>,
|
||||
data: CoreValue,
|
||||
},
|
||||
Patch {
|
||||
|
@ -197,9 +197,16 @@ impl Command {
|
|||
what,
|
||||
data,
|
||||
} => {
|
||||
let mut table = CoreTable::default();
|
||||
table.0 = what.clone();
|
||||
let params = vec![CoreValue::from(what), data];
|
||||
let table = match what {
|
||||
Some(w) => {
|
||||
let mut tmp = CoreTable::default();
|
||||
tmp.0 = w.clone();
|
||||
CoreValue::from(tmp)
|
||||
}
|
||||
None => CoreValue::None,
|
||||
};
|
||||
|
||||
let params = vec![table, data];
|
||||
|
||||
RouterRequest {
|
||||
id,
|
||||
|
|
|
@ -600,7 +600,7 @@ async fn router(
|
|||
let one = !data.is_array();
|
||||
let statement = {
|
||||
let mut stmt = InsertStatement::default();
|
||||
stmt.into = Some(Table(what).into_core().into());
|
||||
stmt.into = what.map(|w| Table(w).into_core().into());
|
||||
stmt.data = Data::SingleExpression(data);
|
||||
stmt.output = Some(Output::After);
|
||||
stmt
|
||||
|
|
|
@ -48,6 +48,7 @@ fn resource_to_values(r: Resource) -> CoreValues {
|
|||
Resource::Array(x) => res.0 = Value::array_to_core(x),
|
||||
Resource::Edge(x) => res.0 = vec![x.into_inner().into()],
|
||||
Resource::Range(x) => res.0 = vec![x.into_inner().into()],
|
||||
Resource::Unspecified => {}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
|
|
@ -54,9 +54,13 @@ pub enum Error {
|
|||
RangeOnEdges,
|
||||
|
||||
/// Tried to use a range query on an existing range
|
||||
#[error("Tried to add a range to an resource which was already a range")]
|
||||
#[error("Tried to add a range to a resource which was already a range")]
|
||||
RangeOnRange,
|
||||
|
||||
/// Tried to use a range query on an unspecified resource
|
||||
#[error("Tried to add a range to an unspecified resource")]
|
||||
RangeOnUnspecified,
|
||||
|
||||
/// Tried to use `table:id` syntax as a method parameter when `(table, id)` should be used instead
|
||||
#[error("Table name `{table}` contained a colon (:), this is dissallowed to avoid confusion with record-id's try `Table(\"{table}\")` instead.")]
|
||||
TableColonId {
|
||||
|
@ -181,6 +185,10 @@ pub enum Error {
|
|||
#[error("Live queries on edges not supported")]
|
||||
LiveOnEdges,
|
||||
|
||||
/// Tried to use a range query on an unspecified resource
|
||||
#[error("Live queries on unspecified resource not supported")]
|
||||
LiveOnUnspecified,
|
||||
|
||||
/// Tried to access a query statement as a live query when it isn't a live query
|
||||
#[error("Query statement {0} is not a live query")]
|
||||
NotLiveQuery(usize),
|
||||
|
@ -209,6 +217,10 @@ pub enum Error {
|
|||
#[error("Insert queries on ranges are not supported")]
|
||||
InsertOnRange,
|
||||
|
||||
/// Tried to insert on an unspecified resource with no data
|
||||
#[error("Insert queries on unspecified resource with no data are not supported")]
|
||||
InsertOnUnspecified,
|
||||
|
||||
#[error("{0}")]
|
||||
InvalidNetTarget(#[from] ParseNetTargetError),
|
||||
|
||||
|
|
|
@ -62,9 +62,10 @@ macro_rules! into_future {
|
|||
Resource::Range {
|
||||
..
|
||||
} => return Err(Error::InsertOnRange.into()),
|
||||
Resource::Unspecified => return Err(Error::InsertOnUnspecified.into()),
|
||||
};
|
||||
let cmd = Command::Insert {
|
||||
what: table.to_string(),
|
||||
what: Some(table.to_string()),
|
||||
data: data.into(),
|
||||
};
|
||||
|
||||
|
@ -121,7 +122,7 @@ where
|
|||
let mut data = to_core_value(data)?;
|
||||
match self.resource? {
|
||||
Resource::Table(table) => Ok(Command::Insert {
|
||||
what: table,
|
||||
what: Some(table),
|
||||
data,
|
||||
}),
|
||||
Resource::RecordId(thing) => {
|
||||
|
@ -137,7 +138,7 @@ where
|
|||
}
|
||||
|
||||
Ok(Command::Insert {
|
||||
what: thing.tb,
|
||||
what: Some(thing.tb),
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
@ -146,6 +147,10 @@ where
|
|||
Resource::Array(_) => Err(Error::InsertOnArray.into()),
|
||||
Resource::Edge(_) => Err(Error::InsertOnEdges.into()),
|
||||
Resource::Range(_) => Err(Error::InsertOnRange.into()),
|
||||
Resource::Unspecified => Ok(Command::Insert {
|
||||
what: None,
|
||||
data,
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ where
|
|||
stmt.what = table.into();
|
||||
stmt.cond = range.to_cond();
|
||||
}
|
||||
Resource::Unspecified => return Err(Error::LiveOnUnspecified.into()),
|
||||
}
|
||||
let query =
|
||||
Query::new(client.clone(), vec![Statement::Live(stmt)], Default::default(), false);
|
||||
|
|
|
@ -845,6 +845,27 @@ where
|
|||
/// },
|
||||
/// ])
|
||||
/// .await?;
|
||||
///
|
||||
/// // Insert multiple records into different tables
|
||||
/// #[derive(Serialize)]
|
||||
/// struct WithId<'a> {
|
||||
/// id: sql::Thing,
|
||||
/// name: &'a str,
|
||||
/// }
|
||||
///
|
||||
/// let people: Vec<Person> = db.insert(())
|
||||
/// .content(vec![
|
||||
/// WithId {
|
||||
/// id: sql::thing("person:tobie")?,
|
||||
/// name: "Tobie",
|
||||
/// },
|
||||
/// WithId {
|
||||
/// id: sql::thing("company:surrealdb")?,
|
||||
/// name: "SurrealDB",
|
||||
/// },
|
||||
/// ])
|
||||
/// .await?;
|
||||
///
|
||||
/// #
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
|
|
|
@ -74,6 +74,8 @@ pub enum Resource {
|
|||
Edge(Edge),
|
||||
/// A range of id's on a table.
|
||||
Range(QueryRange),
|
||||
/// Unspecified resource
|
||||
Unspecified,
|
||||
}
|
||||
|
||||
impl Resource {
|
||||
|
@ -86,6 +88,7 @@ impl Resource {
|
|||
Resource::Array(_) => Err(Error::RangeOnArray.into()),
|
||||
Resource::Edge(_) => Err(Error::RangeOnEdges.into()),
|
||||
Resource::Range(_) => Err(Error::RangeOnRange.into()),
|
||||
Resource::Unspecified => Err(Error::RangeOnUnspecified.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,6 +101,7 @@ impl Resource {
|
|||
Resource::Array(x) => Value::array_to_core(x).into(),
|
||||
Resource::Edge(x) => x.into_inner().into(),
|
||||
Resource::Range(x) => x.into_inner().into(),
|
||||
Resource::Unspecified => CoreValue::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +183,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl From<()> for Resource {
|
||||
fn from(_value: ()) -> Self {
|
||||
Self::Unspecified
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds the `start` and `end` bounds of a range query
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct KeyRange {
|
||||
|
@ -390,3 +400,9 @@ impl<R> IntoResource<Vec<R>> for &String {
|
|||
Ok(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoResource<Vec<R>> for () {
|
||||
fn into_resource(self) -> Result<Resource> {
|
||||
Ok(Resource::Unspecified)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -540,6 +540,41 @@ async fn insert_thing() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test_log::test(tokio::test)]
|
||||
async fn insert_unspecified() {
|
||||
let (permit, db) = new_db().await;
|
||||
db.use_ns(NS).use_db(Ulid::new().to_string()).await.unwrap();
|
||||
drop(permit);
|
||||
let tmp: Result<Vec<RecordId>, _> = db.insert(()).await;
|
||||
tmp.unwrap_err();
|
||||
let tmp: Result<Vec<RecordId>, _> = db.insert(()).content(json!({ "foo": "bar" })).await;
|
||||
tmp.unwrap_err();
|
||||
let tmp: Vec<ApiRecordId> = db
|
||||
.insert(())
|
||||
.content("{id: user:user1, foo: 'bar'}".parse::<Value>().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
tmp,
|
||||
vec![ApiRecordId {
|
||||
id: "user:user1".parse::<RecordId>().unwrap(),
|
||||
}]
|
||||
);
|
||||
|
||||
let tmp: Result<Value, _> = db.insert(Resource::from(())).await;
|
||||
tmp.unwrap_err();
|
||||
let tmp: Result<Value, _> =
|
||||
db.insert(Resource::from(())).content(json!({ "foo": "bar" })).await;
|
||||
tmp.unwrap_err();
|
||||
let tmp: Value = db
|
||||
.insert(Resource::from(()))
|
||||
.content("{id: user:user2, foo: 'bar'}".parse::<Value>().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
let val = "{id: user:user2, foo: 'bar'}".parse::<Value>().unwrap();
|
||||
assert_eq!(tmp, val);
|
||||
}
|
||||
|
||||
#[test_log::test(tokio::test)]
|
||||
async fn select_table() {
|
||||
let (permit, db) = new_db().await;
|
||||
|
|
Loading…
Reference in a new issue