1 module dpq2.value;
2 
3 @safe:
4 
5 import dpq2.oids;
6 
7 /// Minimal Postgres value
8 struct Value
9 {
10     private
11     {
12         bool _isNull = true;
13         OidType _oidType = OidType.Undefined;
14 
15         ValueFormat _format;
16     }
17 
18     package ubyte[] _data;
19 
20     // FIXME:
21     // The pointer returned by PQgetvalue points to storage that is part of the PGresult structure.
22     // One should not modify the data it points to, and one must explicitly copy the data into other
23     // storage if it is to be used past the lifetime of the PGresult structure itself.
24     // Thus, it is need to store reference to Answer here to ensure that result is still available.
25 
26     this(ubyte[] data, in OidType oidType, bool isNull, in ValueFormat format = ValueFormat.BINARY) pure
27     {
28         this._data = data;
29         this._format = format;
30         this._oidType = oidType;
31         this._isNull = isNull;
32     }
33 
34     /// Null Value constructor
35     this(in ValueFormat format, in OidType oidType) pure
36     {
37         this._format = format;
38         this._oidType = oidType;
39     }
40 
41     @safe const pure nothrow @nogc
42     {
43         /// Indicates if the value is NULL
44         bool isNull()
45         {
46             return _isNull;
47         }
48 
49         /// Indicates if the value is supported array type
50         bool isSupportedArray()
51         {
52             return dpq2.oids.isSupportedArray(oidType);
53         }
54 
55         /// Returns OidType of the value
56         OidType oidType()
57         {
58             return _oidType;
59         }
60 
61         /// Returns ValueFormat representation (text or binary)
62         ValueFormat format()
63         {
64             return _format;
65         }
66     }
67 
68     package void oidType(OidType type) @safe pure nothrow @nogc
69     {
70         _oidType = type;
71     }
72 
73     inout (ubyte[]) data() pure inout
74     {
75         import std.exception;
76         import core.exception;
77 
78         enforceEx!AssertError(!isNull, "Attempt to read NULL value", __FILE__, __LINE__);
79 
80         return _data;
81     }
82 
83     debug string toString() const @trusted
84     {
85         import vibe.data.bson: Bson;
86         import dpq2.conv.to_bson;
87         import std.conv: to;
88 
89         return this.as!Bson.toString~"::"~oidType.to!string~"("~(format == ValueFormat.TEXT? "t" : "b")~")";
90     }
91 }
92 
93 @trusted unittest
94 {
95     import dpq2.conv.to_d_types;
96     import core.exception: AssertError;
97 
98     Value v = Value(ValueFormat.BINARY, OidType.Int4);
99 
100     bool exceptionFlag = false;
101 
102     try
103         cast(void) v.as!int;
104     catch(AssertError e)
105         exceptionFlag = true;
106 
107     assert(exceptionFlag);
108 }
109 
110 enum ValueFormat : int {
111     TEXT,
112     BINARY
113 }
114 
115 import std.conv: to, ConvException;
116 
117 /// Conversion exception types
118 enum ConvExceptionType
119 {
120     NOT_ARRAY, /// Format of the value isn't array
121     NOT_BINARY, /// Format of the column isn't binary
122     NOT_TEXT, /// Format of the column isn't text string
123     NOT_IMPLEMENTED, /// Support of this type isn't implemented (or format isn't matches to specified D type)
124     SIZE_MISMATCH, /// Result value size is not matched to the received Postgres value
125     CORRUPTED_JSONB, /// Corrupted JSONB value
126     DATE_VALUE_OVERFLOW, /// Date value isn't fits to Postgres binary Date value
127 }
128 
129 class ValueConvException : ConvException
130 {
131     const ConvExceptionType type; /// Exception type
132 
133     this(ConvExceptionType t, string msg, string file, size_t line) pure @safe
134     {
135         type = t;
136         super(msg, file, line);
137     }
138 }