1 module scorpion.gem.crud; 2 3 import std.conv : to; 4 import std..string : join; 5 import std.traits : hasUDA; 6 import std.typetuple : TypeTuple; 7 8 import scorpion.repository; 9 10 import shark : PrimaryKey; 11 12 /** 13 * Generates an interface with methods for creating, 14 * reading, updating and deleting the given entity. 15 * Example: 16 * --- 17 * @Entity("example") 18 * class Example { 19 * 20 * @PrimaryKey 21 * Integer a; 22 * 23 * String b; 24 * 25 * } 26 * 27 * Example entity = new Example(); 28 * entity.b = "test"; 29 * repository.insert(entity); 30 * assert(repository.select(entity.a).b == "test"); 31 * --- 32 */ 33 interface CrudRepository(T) : Repository!T if(Ids!T.length) { 34 35 /** 36 * Selects and entity using the entity's primary key(s). 37 * Example: 38 * --- 39 * Example entity = repository.select(12); 40 * if(entity !is null) { 41 * // do something 42 * } 43 * --- 44 */ 45 @Select 46 @Where(generateWhere!T) 47 T select(Ids!T args); 48 49 /** 50 * Selects every entity in the table. 51 * Example: 52 * --- 53 * foreach(entity ; repository.selectAll()) { 54 * // do something 55 * } 56 * --- 57 */ 58 @Select 59 T[] selectAll(); 60 61 /** 62 * Inserts a new entity in the table. 63 * Example: 64 * --- 65 * Example entity = new Example(); 66 * entity.b = "Hello!"; 67 * repository.insert(entity); 68 * --- 69 */ 70 @Insert 71 void insert(T entity); 72 73 /** 74 * Updates an existing entity's fields. 75 * Example: 76 * --- 77 * if(auto entity = repository.select(1)) { 78 * entity.b = "Updated"; 79 * repository.update(entity); 80 * } 81 * --- 82 */ 83 @Update 84 void update(T entity); 85 86 /** 87 * Removes an entity from the table. 88 * Example: 89 * --- 90 * Example entity = new Example(); 91 * entity.a = 12; 92 * repository.remove(entity); 93 * --- 94 */ 95 @Remove 96 void remove(T entity); 97 98 /** 99 * Removes an entity from the table using its primary key(s). 100 * Example: 101 * --- 102 * repository.removeById(55); 103 * --- 104 */ 105 @Remove 106 @Where(generateWhere!T) 107 void removeById(Ids!T args); 108 109 } 110 111 private template Ids(T) { 112 113 mixin(idsImpl!T); 114 115 } 116 117 private string idsImpl(T)() { 118 string[] ret; 119 foreach(immutable member ; __traits(allMembers, T)) { 120 static if(hasUDA!(__traits(getMember, T, member), PrimaryKey)) { 121 ret ~= "typeof(__traits(getMember, T, \"" ~ member ~ "\"))"; 122 } 123 } 124 return "alias Ids=TypeTuple!(" ~ ret.join(",") ~ ");"; 125 } 126 127 private string generateWhere(T)() { 128 size_t counter = 0; 129 string[] ret; 130 foreach(immutable member ; __traits(allMembers, T)) { 131 static if(hasUDA!(__traits(getMember, T, member), PrimaryKey)) { 132 ret ~= member ~ "=$" ~ to!string(counter++); 133 } 134 } 135 return ret.join(" and "); 136 }