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