1 /*
2  * Entity - Entity is an object-relational mapping tool for the D programming language. Referring to the design idea of JPA.
3  *
4  * Copyright (C) 2015-2018  Shanghai Putao Technology Co., Ltd
5  *
6  * Developer: HuntLabs.cn
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.entity.TypedQuery;
13 
14 import hunt.entity;
15 import hunt.Long;
16 import hunt.logging;
17 
18 import std.variant;
19 
20 // version(WITH_HUNT_TRACE)
21 // {
22 //     // import hunt.trace.Constrants;
23 //     // import hunt.trace.Plugin;
24 //     import hunt.trace.Span;
25 // }
26 
27 class TypedQuery(T, F = T) if(is(T : Object) && is(F : Object)) {
28 
29     private string _sqlSting;
30     private CriteriaQuery!(T, F) _query;
31     private EntityManager _manager;
32 
33     // version (WITH_HUNT_TRACE)
34     // {
35     //     private Span _span;
36     //     private string[string] _tags;
37     // }
38 
39     this(CriteriaQuery!(T, F) query, EntityManager manager) {
40         _query = query;
41         _manager = manager;
42     }
43 
44     // version (WITH_HUNT_TRACE)
45     // {
46     //     private void beginTrace(string name)
47     //     {
48     //         _tags.clear();
49     //         _span = traceSpanBefore(name);
50     //     }
51 
52     //     private void endTrace(string error = null)
53     //     {
54     //         if (_span !is null)
55     //         {
56     //             traceSpanAfter(_span, _tags, error);
57     //         }
58     //     }
59     // }
60 
61     R getResultAs(R)() {
62         string sql = _query.toString();
63         Statement stmt = _manager.getSession().prepare(sql);
64         RowSet rowSet = stmt.query();
65         version (HUNT_ENTITY_DEBUG) {
66             infof("The result columns: %s", rowSet.columnsNames());
67         }
68 
69         if (rowSet.size() == 0) {
70             warning("The result is empty");
71             return R.init;
72         }
73 
74         // First row and first column
75 
76         Row firstRow = rowSet.firstRow();
77         if (firstRow.size() == 0) {
78             warning("The column in the row is empty.");
79             return R.init;
80         }
81 
82         Variant singleValue = firstRow.getValue(0);
83         version (HUNT_ENTITY_DEBUG) {
84             tracef("The first columns, type: %s, value: %s", singleValue.type, singleValue.toString());
85         }
86 
87         if (singleValue.hasValue())
88             return singleValue.get!R();
89         else
90             return R.init;
91     }
92 
93     Object getSingleResult() {
94         Object[] ret = _getResultList();
95         if (ret.length == 0)
96             return null;
97         return ret[0];
98     }
99 
100     T[] getResultList() {
101         Object[] ret = _getResultList();
102         if (ret.length == 0) {
103             return null;
104         }
105         return cast(T[]) ret;
106     }
107 
108     TypedQuery!(T, F) setMaxResults(int maxResult) {
109         _query.getQueryBuilder().limit(maxResult);
110         return this;
111     }
112 
113     TypedQuery!(T, F) setFirstResult(int startPosition) {
114         _query.getQueryBuilder().offset(startPosition);
115         return this;
116     }
117 
118     private Object[] _getResultList() {
119         string sql = _query.toString();
120 
121         // version (WITH_HUNT_TRACE)
122         // {
123         //     beginTrace("TypeQuery _getResultList");
124         //     scope (exit)
125         //     {
126         //         _tags["sql"] = sql;
127         //         endTrace();
128         //     }
129         // }
130 
131         Statement stmt = _manager.getSession().prepare(sql);
132         RowSet res = stmt.query();
133         version (HUNT_ENTITY_DEBUG) {
134             infof("The result columns: %s", res.columnsNames());
135         }
136 
137         Row[] rows;
138         foreach (value; res) {
139             rows ~= value;
140         }
141 
142         long count = -1;
143         Object[] ret;
144         Root!(T, F) r = _query.getRoot();
145         foreach (size_t k, Row v; rows) {
146             T t = r.deSerialize(rows, count, cast(int) k, null);
147             if (t is null) {
148                 warningf("t is null, count=%d", count);
149                 if (count != -1) {
150                     ret ~= new Long(count);
151                 } else {
152                     throw new EntityException("getResultList has an null data");
153                 }
154             }
155             ret ~= t;
156         }
157         return ret;
158     }
159 
160 }