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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use std::sync::Arc;

use bytes::Bytes;

use edgedb_errors::{Error, ErrorKind};
use edgedb_errors::{ProtocolEncodingError, DescriptorMismatch};

use crate::codec::Codec;
use crate::queryable::{Queryable, Decoder, DescriptorContext};
use crate::descriptors::{TypePos};
use crate::value::Value;


pub trait Sealed: Sized {}

/// A trait representing single result from a query.
///
/// This is implemented for scalars and tuples. To receive a shape from EdgeDB
/// derive [`Queryable`](Queryable) for a structure. This will automatically
/// implement `QueryResult` for you.
pub trait QueryResult: Sealed {
    type State;
    fn prepare(ctx: &DescriptorContext, root_pos: TypePos)
        -> Result<Self::State, Error>;
    fn decode(state: &mut Self::State, msg: &Bytes)
        -> Result<Self, Error>;
}

impl<T: Queryable> Sealed for T {
}

impl Sealed for Value {
}

impl<T: Queryable> QueryResult for T {
    type State = Decoder;
    fn prepare(ctx: &DescriptorContext, root_pos: TypePos)
        -> Result<Decoder, Error>
    {
        T::check_descriptor(ctx, root_pos)
            .map_err(DescriptorMismatch::with_source)?;
        Ok(Decoder {
            has_implicit_id: ctx.has_implicit_id,
            has_implicit_tid: ctx.has_implicit_tid,
            has_implicit_tname: ctx.has_implicit_tname,
        })
    }
    fn decode(decoder: &mut Decoder, msg: &Bytes)
        -> Result<Self, Error>
    {
        Queryable::decode(&decoder, msg)
            .map_err(ProtocolEncodingError::with_source)
    }
}

impl QueryResult for Value {
    type State = Arc<dyn Codec>;
    fn prepare(ctx: &DescriptorContext, root_pos: TypePos)
        -> Result<Arc<dyn Codec>, Error>
    {
        ctx.build_codec(root_pos)
    }
    fn decode(codec: &mut Arc<dyn Codec>, msg: &Bytes)
        -> Result<Self, Error>
    {
        codec.decode(msg)
            .map_err(ProtocolEncodingError::with_source)
    }
}