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.repository.CrudRepository;
13 
14 import hunt.entity.Persistence;
15 import hunt.entity.DefaultEntityManagerFactory;
16 import hunt.entity;
17 import hunt.Long;
18 import hunt.logging;
19 
20 import std.traits;
21 
22 import hunt.entity.repository.Repository;
23 
24 
25 /**
26  * 
27  */
28 class CrudRepository(T, ID) : Repository!(T, ID)
29 {
30     protected EntityManager _manager;
31 
32     this(EntityManager manager = null) {
33         if(manager is null) {
34             _manager = defaultEntityManagerFactory().currentEntityManager();
35         } else {
36             _manager = manager;
37         }
38     }
39 
40     EntityManager entityManager() {
41         return _manager;
42     }
43 
44     EntityManager getEntityManager() {
45         return _manager;
46     }
47 
48     EntityManager createEntityManager()
49     {
50         return defaultEntityManagerFactory().currentEntityManager();
51     }
52 
53     /**
54      * 
55      */
56     long count()
57     {
58         EntityManager em = _manager ? _manager : createEntityManager();
59         scope(exit) {if (!_manager) em.close();}
60 
61         CriteriaBuilder builder = em.getCriteriaBuilder();
62         auto criteriaQuery = builder.createQuery!T;
63         Root!T root = criteriaQuery.from();
64         criteriaQuery.select(builder.count(root.getPrimaryField()));
65 
66         TypedQuery!T typedQuery = em.createQuery(criteriaQuery);
67         long result = typedQuery.getResultAs!long();
68         return result;
69     }
70 
71     long count(string fieldName)
72     {
73         EntityManager em = _manager ? _manager : createEntityManager();
74         scope(exit) {if (!_manager) em.close();}
75 
76         CriteriaBuilder builder = em.getCriteriaBuilder();
77         auto criteriaQuery = builder.createQuery!T;
78         Root!T root = criteriaQuery.from();
79         EntityFieldInfo fieldInfo = root.get(fieldName);
80         criteriaQuery.select(builder.count(fieldInfo));
81 
82         TypedQuery!T typedQuery = em.createQuery(criteriaQuery);
83         long result = typedQuery.getResultAs!long();
84         return result;
85     }
86 
87     /**
88      * 
89      */
90     long sum(string fieldName) {
91         EntityManager em = _manager ? _manager : createEntityManager();
92         scope(exit) {if (!_manager) em.close();}
93 
94         CriteriaBuilder builder = em.getCriteriaBuilder();
95         CriteriaQuery!(T, T) criteriaQuery = builder.createQuery!T;
96 
97         Root!T root = criteriaQuery.from();
98         EntityFieldInfo fieldInfo = root.get(fieldName);
99         criteriaQuery.select(builder.sum(fieldInfo));
100 
101         TypedQuery!T typedQuery = em.createQuery(criteriaQuery);
102         long result = typedQuery.getResultAs!long();
103         return result;
104     }
105 
106     void remove(T entity)
107     {
108         auto em = _manager ? _manager : createEntityManager;
109         scope(exit) {if (!_manager) em.close();}
110         em.remove!T(entity);
111     }
112 
113     void removeAll()
114     {
115         // FIXME: Needing refactor or cleanup -@zhangxueping at 2019-7-3 10:23:27
116         // user "delete from T"
117         auto em = _manager ? _manager : createEntityManager;
118         scope(exit) {if (!_manager) em.close();}
119         foreach (entity; findAll())
120         {
121             em.remove!T(entity);
122         }
123     }
124     
125     void removeAll(T[] entities)
126     {
127         auto em = _manager ? _manager : createEntityManager;
128         scope(exit) {if (!_manager) em.close();}
129         foreach (entity; entities)
130         {
131             em.remove!T(entity);
132         }
133     }
134 
135     void removeById(ID id)
136     {
137         auto em = _manager ? _manager : createEntityManager;
138         scope(exit) {if (!_manager) em.close();}
139         em.remove!T(id);
140         
141     }
142     
143     bool existsById(ID id)
144     {
145         T entity = this.findById(id);
146         return (entity !is null);
147     }
148 
149     T[] findAll()
150     {
151         auto em = _manager ? _manager : createEntityManager;
152         scope(exit) {if (!_manager) em.close();}
153         CriteriaBuilder builder = em.getCriteriaBuilder();
154         auto criteriaQuery = builder.createQuery!(T);
155         Root!T root = criteriaQuery.from();
156         TypedQuery!T typedQuery = em.createQuery(criteriaQuery.select(root));
157         return typedQuery.getResultList();
158     }
159 
160     T[] findAllById(ID[] ids)
161     {
162         T[] entities;
163         foreach (id; ids)
164         {
165             T entity = this.findById(id);
166             if (entity !is null)
167                 entities ~= entity;
168         }
169         return entities;
170     }
171 
172     T findById(ID id)
173     {
174         auto em = _manager ? _manager : createEntityManager;
175         scope(exit) {if (!_manager) em.close();}
176         T result = em.find!T(id);
177         return result;
178     }
179 
180     T save(T entity)
181     {
182         EntityManager em = _manager ? _manager : createEntityManager;
183         scope(exit) {if (!_manager) em.close();}
184         if (mixin(GenerateFindById!T()) is null)
185         {
186             em.persist!(T)(entity);
187         }
188         else
189         {
190             em.merge!T(entity);
191         }
192         return entity;
193     }
194 
195     T[] saveAll(T[] entities)
196     {
197         auto em = _manager ? _manager : createEntityManager;
198         scope(exit) {if (!_manager) em.close();}
199         T[] resultList;
200         foreach (entity; entities)
201         {
202             if (mixin(GenerateFindById!T()) is null)
203             {
204                 resultList ~= em.persist(entity);
205             }
206             else
207             {
208                 em.merge!T(entity);
209                 resultList ~= entity;
210             }
211         }
212         return resultList;
213     }
214 
215     T insert(T entity)
216     {
217         auto em = _manager ? _manager : createEntityManager;
218         scope(exit) {if (!_manager) em.close();}
219         em.persist(entity);
220         return entity;
221     }
222     T[] insertAll(T[] entities)
223     {
224         auto em = _manager ? _manager : createEntityManager;
225         scope(exit) {if (!_manager) em.close();}
226         T[] resultList;
227         foreach (entity; entities)
228         {
229             resultList ~= em.persist(entity);
230         }
231         return resultList;
232     }
233 
234     T update(T entity)
235     {
236         auto em = _manager ? _manager : createEntityManager;
237         scope(exit) {if (!_manager) em.close();}
238         em.merge!T(entity);
239         return entity;
240     }
241     
242     T[] updateAll(T[] entities)
243     {
244         auto em = _manager ? _manager : createEntityManager;
245         scope(exit) {if (!_manager) em.close();}
246         T[] resultList;
247         foreach (entity; entities)
248         {
249             em.merge!T(entity);
250             resultList ~= entity;
251         }
252         return resultList;
253     }
254 
255 }
256 
257 string GenerateFindById(T)()
258 {
259     return "em.find!T(entity." ~ getSymbolsByUDA!(T, PrimaryKey)[0].stringof ~ ")";
260 }