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.EntityRepository;
13 
14 import hunt.entity.criteria;
15 import hunt.entity.EntityManager;
16 import hunt.entity.TypedQuery;
17 import hunt.entity.Model;
18 import hunt.entity.repository.CrudRepository;
19 import hunt.entity.DefaultEntityManagerFactory;
20 import hunt.Long;
21 
22 import hunt.database.query;
23 
24 public import hunt.entity.domain;
25 
26 class EntityRepository(T, ID) : CrudRepository!(T, ID) if (is(T : Model)) {
27     this(EntityManager manager = null) {
28         super(manager);
29         _member = new Member!T(entityManager.getPrefix());
30     }
31 
32     static string initObjects() {
33         // dfmt off
34         return `
35         auto em = _manager ? _manager : createEntityManager();
36         scope(exit) {if (!_manager) em.close();}
37         CriteriaBuilder builder = em.getCriteriaBuilder();
38         auto criteriaQuery = builder.createQuery!T;
39         Root!T root = criteriaQuery.from();`;
40 
41         // dfmt on
42     }
43 
44     alias count = CrudRepository!(T, ID).count;
45     alias findAll = CrudRepository!(T, ID).findAll;
46 
47     long count(Condition condition) {
48         mixin(initObjects);
49 
50         criteriaQuery.select(builder.count(root)).where(condition.toPredicate());
51 
52         Long result = cast(Long)(em.createQuery(criteriaQuery).getSingleResult());
53         return result.longValue();
54     }
55 
56     long count(Specification specification) {
57         mixin(initObjects);
58 
59         criteriaQuery.select(builder.count(root))
60             .where(specification.toPredicate(root, criteriaQuery, builder));
61 
62         Long result = cast(Long)(em.createQuery(criteriaQuery).getSingleResult());
63         return result.longValue();
64         // return 0;
65     }
66 
67     T find(Condition condition) {
68         // auto list = findAll(condition);
69         // if(list.length > 0)
70         //     return list[0];
71         // return null;
72         mixin(initObjects);
73 
74         //condition
75         criteriaQuery.select(root).where(condition.toPredicate());
76 
77         // page
78         TypedQuery!T typedQuery = em.createQuery(criteriaQuery).setFirstResult(0).setMaxResults(1);
79 
80         // result
81         auto res = typedQuery.getResultList();
82         if (res.length > 0) {
83             return res[0];
84         }
85         return null;
86     }
87 
88     T find(ID id) {
89         return this.findById(id);
90     }
91 
92     T[] findAll(Sort sort) {
93         mixin(initObjects);
94 
95         //sort
96         foreach (o; sort.list) {
97             criteriaQuery.getQueryBuilder().orderBy(o.getColumn() ~ " " ~ o.getOrderType());
98         }
99 
100         //all
101         criteriaQuery.select(root);
102 
103         TypedQuery!T typedQuery = em.createQuery(criteriaQuery);
104         auto res = typedQuery.getResultList();
105 
106         return res;
107     }
108 
109     T[] findAll(Condition condition) {
110         mixin(initObjects);
111 
112         //specification
113         criteriaQuery.select(root).where(condition.toPredicate());
114 
115         TypedQuery!T typedQuery = em.createQuery(criteriaQuery);
116         auto res = typedQuery.getResultList();
117 
118         return res;
119     }
120 
121     T[] findAll(R)(Comparison!R condition) {
122         mixin(initObjects);
123 
124         //specification
125         criteriaQuery.select(root).where(condition);
126 
127         TypedQuery!T typedQuery = em.createQuery(criteriaQuery);
128         auto res = typedQuery.getResultList();
129 
130         return res;
131     }
132 
133     T[] findAll(Specification specification) {
134         mixin(initObjects);
135 
136         //specification
137         criteriaQuery.select(root).where(specification.toPredicate(root, criteriaQuery, builder));
138 
139         TypedQuery!T typedQuery = em.createQuery(criteriaQuery);
140         auto res = typedQuery.getResultList();
141 
142         return res;
143     }
144 
145     T[] findAll(Condition condition, Sort sort) {
146         mixin(initObjects);
147 
148         //sort
149         foreach (o; sort.list)
150             criteriaQuery.getQueryBuilder().orderBy(o.getColumn() ~ " " ~ o.getOrderType());
151 
152         //specification
153         criteriaQuery.select(root).where(condition.toPredicate());
154 
155         TypedQuery!T typedQuery = em.createQuery(criteriaQuery);
156         auto res = typedQuery.getResultList();
157 
158         return res;
159     }
160 
161     T[] findAll(Specification specification, Sort sort) {
162         mixin(initObjects);
163 
164         //sort
165         foreach (o; sort.list)
166             criteriaQuery.getQueryBuilder().orderBy(o.getColumn() ~ " " ~ o.getOrderType());
167 
168         //specification
169         criteriaQuery.select(root).where(specification.toPredicate(root, criteriaQuery, builder));
170 
171         TypedQuery!T typedQuery = em.createQuery(criteriaQuery);
172         auto res = typedQuery.getResultList();
173 
174         return res;
175     }
176 
177     Page!T findAll(Pageable pageable) {
178         mixin(initObjects);
179 
180         //sort
181         foreach (o; pageable.getSort.list)
182             criteriaQuery.getQueryBuilder().orderBy(o.getColumn() ~ " " ~ o.getOrderType());
183 
184         //all
185         criteriaQuery.select(root);
186 
187         //page
188         TypedQuery!T typedQuery = em.createQuery(criteriaQuery)
189             .setFirstResult(pageable.getOffset()).setMaxResults(pageable.getPageSize());
190 
191         auto res = typedQuery.getResultList();
192         auto page = new Page!T(res, pageable, super.count());
193 
194         return page;
195     }
196 
197     ///
198     Page!T findAll(Condition condition, Pageable pageable) {
199         mixin(initObjects);
200 
201         //sort
202         foreach (o; pageable.getSort.list)
203             criteriaQuery.getQueryBuilder().orderBy(o.getColumn() ~ " " ~ o.getOrderType());
204 
205         //condition
206         criteriaQuery.select(root).where(condition.toPredicate());
207 
208         //page
209         TypedQuery!T typedQuery = em.createQuery(criteriaQuery)
210             .setFirstResult(pageable.getOffset()).setMaxResults(pageable.getPageSize());
211         auto res = typedQuery.getResultList();
212         auto page = new Page!T(res, pageable, count(condition));
213 
214         return page;
215     }
216 
217     Page!T findAll(Specification specification, Pageable pageable) {
218         mixin(initObjects);
219 
220         //sort
221         foreach (o; pageable.getSort.list)
222             criteriaQuery.getQueryBuilder().orderBy(o.getColumn() ~ " " ~ o.getOrderType());
223 
224         //specification
225         criteriaQuery.select(root).where(specification.toPredicate(root, criteriaQuery, builder));
226 
227         //page
228         TypedQuery!T typedQuery = em.createQuery(criteriaQuery)
229             .setFirstResult(pageable.getOffset()).setMaxResults(pageable.getPageSize());
230         auto res = typedQuery.getResultList();
231         auto page = new Page!T(res, pageable, count(specification));
232 
233         return page;
234     }
235 
236     @property Member!T field() {
237         return _member;
238     }
239 
240     deprecated("Using field instead.") 
241     @property Member!T Field() {
242         return _member;
243     }
244 
245 private:
246 
247     Member!T _member;
248 }
249 
250 /*
251 version(unittest)
252 {
253 	@Table("p_menu")
254 	class Menu  
255 	{
256         mixin MakeModel;
257 
258 		@PrimaryKey
259 		@AutoIncrement
260 		int 		ID;
261 
262 		@Column("name")
263 		string 		name;
264         @JoinColumn("up_menu_id")
265 		int 		up_menu_id;
266 		string 		perident;
267 		int			index;
268 		string		icon;
269 		bool		status;
270 	}
271 }
272 
273 unittest{
274 
275 	void test_entity_repository()
276 	{
277 		
278             //data
279             
280  //       (1, 'User', 0, 'user.edit', 0, 'fe-box', 0),
281  //       (2, 'Role', 0, 'role.edit', 0, 'fe-box', 0),
282  //       (3, 'Module', 0, 'module.edit', 0, 'fe-box', 0),
283  //       (4, 'Permission', 0, 'permission.edit', 0, 'fe-box', 0),
284  //       (5, 'Menu', 0, 'menu.edit', 0, 'fe-box', 0),
285  //       (6, 'Manage User', 1, 'user.edit', 0, '0', 0),
286  //       (7, 'Add User', 1, 'user.add', 0, '0', 0),
287  //       (8, 'Manage Role', 2, 'role.edit', 0, '0', 0),
288  //       (9, 'Add Role', 2, 'role.add', 0, '0', 0),
289  //       (10, 'Manage Module', 3, 'module.edit', 0, '0', 0),
290  //       (11, 'Add Module', 3, 'module.add', 0, '0', 0),
291  //       (12, 'Manage Permission', 4, 'permission.edit', 0, '0', 0),
292  //       (13, 'Add Permission', 4, 'permission.add', 0, '0', 0),
293  //       (14, 'Manage Menu', 5, 'menu.edit', 0, '0', 0),
294  //       (15, 'Add Menu', 5, 'menu.add', 0, '0', 0);
295             
296 
297         auto option = new EntityOption;
298 
299         option.database.driver = "mysql";
300         option.database.host = "127.0.0.1";
301         option.database.port = 3306;
302         option.database.database = "hunt_test";
303         option.database.username = "root";
304         option.database.password = "123456";
305         option.database.charset = "utf8mb4";
306         option.database.prefix = "";
307 
308         EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default", option);
309         EntityManager em = entityManagerFactory.createEntityManager();
310 
311 		auto rep = new EntityRepository!(Menu , int)(em);
312 		
313 		//sort
314 		auto menus1 = rep.findAll(new Sort(rep.field.ID , OrderBy.DESC));
315 		assert(menus1.length == 15);
316 		assert(menus1[0].ID == 15 && menus1[$ - 1].ID == 1);
317 		
318 		//specification
319 		class MySpecification: Specification!Menu
320 		{
321 			Predicate toPredicate(Root!Menu root, CriteriaQuery!Menu criteriaQuery ,
322 				CriteriaBuilder criteriaBuilder)
323 			{
324 				Predicate _name = criteriaBuilder.gt(root.Menu.ID, 5);
325 				return criteriaBuilder.and(_name);
326 			}
327 		}
328 		auto menus2 = rep.findAll(new MySpecification());
329 		assert(menus2.length == 10);
330 		assert(menus2[0].ID == 6);
331 		
332 		//sort specification
333 		auto menus3 = rep.findAll(new MySpecification , new Sort(rep.field.ID ,OrderBy.DESC));
334 		assert(menus3[0].ID == 15 && menus3[$ - 1].ID == 6);
335 
336 		//page
337 		auto pages1 = rep.findAll(new Pageable(0 , 10 , rep.field.ID , OrderBy.DESC));
338 		assert(pages1.getTotalPages() == 2);
339 		assert(pages1.getContent.length == 10);
340 		assert(pages1.getContent[0].ID == 15 && pages1.getContent[$-1].ID == 6);
341 		assert(pages1.getTotalElements() == 15);
342 
343 		//page specification
344 		auto pages2 = rep.findAll(new MySpecification , new Pageable(1 , 5 , rep.field.ID , OrderBy.DESC));
345 		assert(pages2.getTotalPages() == 2);
346 		assert(pages2.getContent.length == 5);
347 		assert(pages2.getContent[0].ID == 10 && pages1.getContent[$-1].ID == 6);
348 		assert(pages2.getTotalElements() == 10);
349 
350         ///where name == "User"   
351         auto condition = new Condition(`%s = '%s'` , rep.field.name , "User");
352         auto menu4 = rep.find(condition);
353         assert(menu4.ID == 1);
354 
355         ///count
356         assert(rep.count(new Condition(`%s > %d` , rep.field.ID , 0)) == 15);
357 
358 
359     }
360 
361 
362 	test_entity_repository();
363 }*/