1 module tagion.hibon.HiBONregex; 2 3 @safe: 4 import std.algorithm; 5 import std.range; 6 import std.regex; 7 import tagion.basic.basic; 8 import tagion.hibon.Document; 9 import tagion.hibon.HiBONBase; 10 import tagion.hibon.HiBONRecord; 11 12 struct HiBONregex { 13 alias RegexT = Regex!char; 14 uint[] types; 15 string name; 16 string record_type; 17 RegexT regex_name; 18 RegexT regex_record_type; 19 this(Name, HType, Types)(Name name, HType record_type, Types types) pure 20 21 22 23 if ((is(Name == string) || is(Name == RegexT)) && 24 (is(HType == string) || is(HType == RegexT)) && 25 (is(Types 26 : const(Type))) || is(Types : const(Type[]))) { 27 static if (is(Name == string)) { 28 this.name = name; 29 } 30 else { 31 regex_name = name; 32 } 33 static if (is(HType == string)) { 34 this.record_type = record_type; 35 } 36 else { 37 regex_record_type = record_type; 38 } 39 import std.algorithm : filter; 40 import std.array; 41 42 Type[] _types; 43 _types ~= types; 44 this.types = _types 45 .filter!(type => type !is Type.NONE) 46 .map!(type => cast(uint) type) 47 .array; 48 } 49 50 this(Name)(Name name) pure { 51 this(name, string.init, Type.init); 52 } 53 54 this(Name, HType)(Name name, HType record_type) pure { 55 this(name, record_type, Type.init); 56 } 57 58 bool match(const Document doc) const { 59 bool result; 60 if (!record_type.empty) { 61 if (record_type == "!") { 62 return doc.getType.isinit; 63 } 64 if (doc.getType != record_type) { 65 return false; 66 } 67 } 68 else if (!regex_record_type.isinit) { 69 if (doc.getType.matchFirst(regex_record_type).empty) { 70 return false; 71 } 72 } 73 bool canMatch(const Document.Element elm) { 74 if (!name.empty) { 75 if (elm.key != name) { 76 return false; 77 } 78 } 79 else if (!regex_name.isinit) { 80 if (elm.key.matchFirst(regex_name).empty) { 81 return false; 82 } 83 } 84 if (!types.empty) { 85 if (!types.canFind(elm.type)) { 86 return false; 87 } 88 } 89 return true; 90 } 91 92 return doc[].any!(elm => canMatch(elm)); 93 } 94 95 bool match(T)(T rec) if (isHiBONRecord!T) { 96 return match(rec.toDoc); 97 } 98 } 99 100 /// 101 unittest { 102 enum record_type_name = "Some_type"; 103 @recordType(record_type_name) 104 static struct RegexDoc { 105 string name; 106 int x; 107 @label("12") bool flag; 108 mixin HiBONRecord!(q{ 109 this(string name, int x, bool flag) { 110 this.name=name; 111 this.x=x; 112 this.flag=flag; 113 } 114 }); 115 } 116 117 static struct NoRecordType { 118 int x; 119 mixin HiBONRecord; 120 } 121 122 const no_record_type_doc = NoRecordType.init.toDoc; 123 const regex_doc = RegexDoc("text", 42, false); 124 const doc = regex_doc.toDoc; 125 { // Test hibon key name match 126 assert(HiBONregex("name").match(doc)); 127 assert(HiBONregex(regex(`\d+`)).match(doc)); 128 assert(!HiBONregex("no match").match(doc)); 129 assert(!HiBONregex(regex(`no match`)).match(doc)); 130 131 } 132 { // Test hibon record type match 133 assert(HiBONregex(string.init, record_type_name).match(doc)); 134 assert(!HiBONregex(string.init, "Not found").match(doc)); 135 assert(HiBONregex(string.init, regex(`_\w+`)).match(doc)); 136 assert(!HiBONregex(string.init, regex(`_\d+`)).match(doc)); 137 assert(!HiBONregex(string.init, "!").match(doc)); 138 assert(HiBONregex(string.init, "!").match(no_record_type_doc)); 139 } 140 { // Test hibon record type match 141 assert(HiBONregex(string.init, string.init, Type.STRING).match(doc)); 142 assert(!HiBONregex(string.init, string.init, Type.BINARY).match(doc)); 143 assert(HiBONregex(string.init, string.init, [Type.BINARY, Type.STRING]).match(doc)); 144 assert(!HiBONregex(string.init, string.init, [Type.BINARY, Type.BIGINT]).match(doc)); 145 } 146 }