surrealdb_expr/val/
file.rs1use revision::revisioned;
2use storekey::{BorrowDecode, Encode};
3use surrealdb_types::{SqlFormat, ToSql, write_sql};
4
5use crate::val::IndexFormat;
6
7#[revisioned(revision = 1)]
8#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Encode, BorrowDecode)]
9#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
10#[storekey(format = "()")]
11#[storekey(format = "IndexFormat")]
12pub struct File {
13 pub bucket: String,
14 pub key: String,
15}
16
17impl File {
18 pub fn new(bucket: String, key: String) -> Self {
19 let key = if key.starts_with("/") {
20 key
21 } else {
22 format!("/{key}")
23 };
24
25 Self {
26 bucket,
27 key,
28 }
29 }
30
31 pub fn is_bucket_type(&self, types: &[String]) -> bool {
33 types.is_empty() || types.contains(&self.bucket)
34 }
35
36 pub fn display_inner(&self) -> String {
37 format!("{}:{}", fmt_inner(&self.bucket, true), fmt_inner(&self.key, false))
38 }
39}
40
41impl From<surrealdb_types::File> for File {
42 fn from(v: surrealdb_types::File) -> Self {
43 Self {
44 bucket: v.bucket,
45 key: v.key,
46 }
47 }
48}
49
50impl From<File> for surrealdb_types::File {
51 fn from(x: File) -> Self {
52 surrealdb_types::File::new(x.bucket, x.key)
53 }
54}
55
56fn fmt_inner(v: &str, escape_slash: bool) -> String {
57 v.chars()
58 .flat_map(|c| {
59 if c.is_ascii_alphanumeric()
60 || matches!(c, '-' | '_' | '.')
61 || (!escape_slash && c == '/')
62 {
63 vec![c]
64 } else {
65 vec!['\\', c]
66 }
67 })
68 .collect::<String>()
69}
70
71impl ToSql for File {
72 fn fmt_sql(&self, f: &mut String, sql_fmt: SqlFormat) {
73 write_sql!(f, sql_fmt, "f\"{}\"", self.display_inner())
74 }
75}