1 module dpq2.args;
2 
3 @safe:
4 
5 public import dpq2.conv.from_d_types;
6 public import dpq2.conv.from_bson;
7 
8 import dpq2.value;
9 import dpq2.oids: Oid;
10 import std.conv: to;
11 import std..string: toStringz;
12 
13 /// Query parameters
14 struct QueryParams
15 {
16     string sqlCommand; /// SQL command
17     ValueFormat resultFormat = ValueFormat.BINARY; /// Result value format
18     private Value[] _args; // SQL command arguments
19 
20     /// SQL command arguments
21     @property void args(Value[] vargs)
22     {
23         _args = vargs;
24     }
25 
26     /// ditto
27     @property ref inout (Value[]) args() inout pure
28     {
29         return _args;
30     }
31 
32     /// Useful for simple text-only query params
33     /// Postgres infers a data type for the parameter in the same way it would do for an untyped literal string.
34     @property void argsFromArray(in string[] arr)
35     {
36         _args.length = arr.length;
37 
38         foreach(i, ref a; _args)
39             a = toValue(arr[i], ValueFormat.TEXT);
40     }
41 
42     void argsVariadic(Targs ...)(Targs t_args)
43     {
44         _args.length = t_args.length;
45 
46         static foreach(i, T; Targs)
47         {
48             _args[i] = toValue!T(t_args[i]);
49         }
50     }
51 
52     @property string preparedStatementName() const { return sqlCommand; }
53     @property void preparedStatementName(string s){ sqlCommand = s; }
54 }
55 
56 unittest
57 {
58     QueryParams qp;
59     qp.argsVariadic(123, "asd", true);
60 
61     assert(qp.args[0] == 123.toValue);
62     assert(qp.args[1] == "asd".toValue);
63     assert(qp.args[2] == true.toValue);
64 }
65 
66 /// Used as parameters by PQexecParams-like functions
67 package struct InternalQueryParams
68 {
69     private
70     {
71         const(string)* sqlCommand;
72         Oid[] oids;
73         int[] formats;
74         int[] lengths;
75         const(ubyte)*[] values;
76     }
77 
78     ValueFormat resultFormat;
79 
80     this(in QueryParams* qp) pure
81     {
82         sqlCommand = &qp.sqlCommand;
83         resultFormat = qp.resultFormat;
84 
85         oids = new Oid[qp.args.length];
86         formats = new int[qp.args.length];
87         lengths = new int[qp.args.length];
88         values = new const(ubyte)* [qp.args.length];
89 
90         for(int i = 0; i < qp.args.length; ++i)
91         {
92             oids[i] = qp.args[i].oidType;
93             formats[i] = qp.args[i].format;
94 
95             if(!qp.args[i].isNull)
96             {
97                 lengths[i] = qp.args[i].data.length.to!int;
98 
99                 immutable ubyte[] zeroLengthArg = [123]; // fake value, isn't used as argument
100 
101                 if(qp.args[i].data.length == 0)
102                     values[i] = &zeroLengthArg[0];
103                 else
104                     values[i] = &qp.args[i].data[0];
105             }
106         }
107     }
108 
109     /// Values used by PQexecParams-like functions
110     const(char)* command() pure const
111     {
112         return cast(const(char)*) (*sqlCommand).toStringz;
113     }
114 
115     /// ditto
116     const(char)* stmtName() pure const
117     {
118         return command();
119     }
120 
121     /// ditto
122     int nParams() pure const
123     {
124         return values.length.to!int;
125     }
126 
127     /// ditto
128     const(Oid)* paramTypes() pure
129     {
130         if(oids.length == 0)
131             return null;
132         else
133             return &oids[0];
134     }
135 
136     /// ditto
137     const(ubyte*)* paramValues() pure
138     {
139         if(values.length == 0)
140             return null;
141         else
142             return &values[0];
143     }
144 
145     /// ditto
146     const(int)* paramLengths() pure
147     {
148         if(lengths.length == 0)
149             return null;
150         else
151             return &lengths[0];
152     }
153 
154     /// ditto
155     const(int)* paramFormats() pure
156     {
157         if(formats.length == 0)
158             return null;
159         else
160             return &formats[0];
161     }
162 }