1use core::hash::{Hash, Hasher};
2use spacetimedb_execution::Row;
3use spacetimedb_lib::db::auth::StAccess;
4use spacetimedb_sats::bsatn::{ser::BsatnError, ToBsatn};
5use spacetimedb_sats::product_value::ProductValue;
6use spacetimedb_sats::{impl_serialize, AlgebraicValue};
7use spacetimedb_schema::relation::{ColExpr, ColExprRef, Header};
8use spacetimedb_table::read_column::ReadColumn;
9use spacetimedb_table::table::RowRef;
10use std::borrow::Cow;
11use std::sync::Arc;
12
13#[derive(Debug, Clone)]
19pub enum RelValue<'a> {
20 Row(RowRef<'a>),
22 Projection(ProductValue),
24 ProjRef(&'a ProductValue),
30}
31
32impl<'a> From<Row<'a>> for RelValue<'a> {
33 fn from(value: Row<'a>) -> Self {
34 match value {
35 Row::Ptr(ptr) => Self::Row(ptr),
36 Row::Ref(ptr) => Self::ProjRef(ptr),
37 }
38 }
39}
40
41impl Eq for RelValue<'_> {}
42
43impl PartialEq for RelValue<'_> {
44 fn eq(&self, other: &Self) -> bool {
45 match (self, other) {
46 (Self::Projection(x), Self::Projection(y)) => x == y,
47 (Self::ProjRef(x), Self::ProjRef(y)) => x == y,
48 (Self::Row(x), Self::Row(y)) => x == y,
49 (Self::Projection(x), Self::ProjRef(y)) | (Self::ProjRef(y), Self::Projection(x)) => x == *y,
50 (Self::Row(x), Self::Projection(y)) | (Self::Projection(y), Self::Row(x)) => x == y,
51 (Self::Row(x), Self::ProjRef(y)) | (Self::ProjRef(y), Self::Row(x)) => x == *y,
52 }
53 }
54}
55
56impl Hash for RelValue<'_> {
57 fn hash<H: Hasher>(&self, state: &mut H) {
58 match self {
59 Self::Row(x) => x.hash(state),
62 Self::Projection(x) => x.hash(state),
63 Self::ProjRef(x) => x.hash(state),
64 }
65 }
66}
67
68impl_serialize!(['a] RelValue<'a>, (self, ser) => match self {
69 Self::Row(row) => row.serialize(ser),
70 Self::Projection(row) => row.serialize(ser),
71 Self::ProjRef(row) => row.serialize(ser),
72});
73
74impl<'a> RelValue<'a> {
75 pub fn into_product_value(self) -> ProductValue {
80 match self {
81 Self::Row(row) => row.to_product_value(),
82 Self::Projection(row) => row,
83 Self::ProjRef(row) => row.clone(),
84 }
85 }
86
87 pub fn into_product_value_cow(self) -> Cow<'a, ProductValue> {
92 match self {
93 Self::Row(row) => Cow::Owned(row.to_product_value()),
94 Self::Projection(row) => Cow::Owned(row),
95 Self::ProjRef(row) => Cow::Borrowed(row),
96 }
97 }
98
99 pub fn num_columns(&self) -> usize {
101 match self {
102 Self::Row(row_ref) => row_ref.row_layout().product().elements.len(),
103 Self::Projection(row) => row.elements.len(),
104 Self::ProjRef(row) => row.elements.len(),
105 }
106 }
107
108 pub fn extend(self, other: RelValue<'a>) -> RelValue<'a> {
112 let mut x: Vec<_> = self.into_product_value().elements.into();
113 x.extend(other.into_product_value());
114 RelValue::Projection(x.into())
115 }
116
117 pub fn read_column(&self, col: usize) -> Option<Cow<'_, AlgebraicValue>> {
121 match self {
122 Self::Row(row_ref) => AlgebraicValue::read_column(*row_ref, col).ok().map(Cow::Owned),
123 Self::Projection(pv) => pv.elements.get(col).map(Cow::Borrowed),
124 Self::ProjRef(pv) => pv.elements.get(col).map(Cow::Borrowed),
125 }
126 }
127
128 pub fn get(&'a self, col: ColExprRef<'a>) -> Cow<'a, AlgebraicValue> {
133 match col {
134 ColExprRef::Col(col) => self.read_column(col.idx()).unwrap(),
135 ColExprRef::Value(x) => Cow::Borrowed(x),
136 }
137 }
138
139 pub fn read_or_take_column(&mut self, col: usize) -> Option<AlgebraicValue> {
145 match self {
146 Self::Row(row_ref) => AlgebraicValue::read_column(*row_ref, col).ok(),
147 Self::Projection(pv) => pv.elements.get_mut(col).map(AlgebraicValue::take),
148 Self::ProjRef(pv) => pv.elements.get(col).cloned(),
149 }
150 }
151
152 pub fn project_owned(mut self, cols: &[ColExpr]) -> ProductValue {
157 cols.iter()
158 .map(|col| match col {
159 ColExpr::Col(col) => self.read_or_take_column(col.idx()).unwrap(),
160 ColExpr::Value(x) => x.clone(),
161 })
162 .collect()
163 }
164}
165
166impl ToBsatn for RelValue<'_> {
167 fn to_bsatn_vec(&self) -> Result<Vec<u8>, BsatnError> {
168 match self {
169 RelValue::Row(this) => this.to_bsatn_vec(),
170 RelValue::Projection(this) => this.to_bsatn_vec(),
171 RelValue::ProjRef(this) => (*this).to_bsatn_vec(),
172 }
173 }
174 fn to_bsatn_extend(&self, buf: &mut Vec<u8>) -> Result<(), BsatnError> {
175 match self {
176 RelValue::Row(this) => this.to_bsatn_extend(buf),
177 RelValue::Projection(this) => this.to_bsatn_extend(buf),
178 RelValue::ProjRef(this) => this.to_bsatn_extend(buf),
179 }
180 }
181 fn static_bsatn_size(&self) -> Option<u16> {
182 match self {
183 RelValue::Row(this) => this.static_bsatn_size(),
184 RelValue::Projection(this) => this.static_bsatn_size(),
185 RelValue::ProjRef(this) => this.static_bsatn_size(),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Eq, PartialEq)]
193pub struct MemTable {
194 pub head: Arc<Header>,
195 pub data: Vec<ProductValue>,
196 pub table_access: StAccess,
197}
198
199impl MemTable {
200 pub fn new(head: Arc<Header>, table_access: StAccess, data: Vec<ProductValue>) -> Self {
201 assert_eq!(
202 head.fields.len(),
203 data.first()
204 .map(|pv| pv.elements.len())
205 .unwrap_or_else(|| head.fields.len()),
206 "number of columns in `header.len() != data.len()`"
207 );
208 Self {
209 head,
210 data,
211 table_access,
212 }
213 }
214
215 pub fn from_iter(head: Arc<Header>, data: impl IntoIterator<Item = ProductValue>) -> Self {
216 Self {
217 head,
218 data: data.into_iter().collect(),
219 table_access: StAccess::Public,
220 }
221 }
222}