1 module dast.util; 2 3 version (Have_database_util) { 4 public import database.util : as, ignore, snakeCase, camelCase, KeyName; 5 } else { 6 struct as { // @suppress(dscanner.style.phobos_naming_convention) 7 string name; 8 } 9 10 enum ignore; // @suppress(dscanner.style.phobos_naming_convention) 11 12 import tame.text.ascii; 13 14 S snakeCase(S)(S input, char sep = '_') { 15 if (!input.length) 16 return []; 17 char[128] buffer; 18 size_t length; 19 20 auto pcls = classify(input[0]); 21 foreach (ch; input) { 22 auto cls = classify(ch); 23 switch (cls) with (CharClass) { 24 case UpperCase: 25 if (pcls != UpperCase && pcls != Underscore) 26 buffer[length++] = sep; 27 buffer[length++] = ch | ' '; 28 break; 29 case Digit: 30 if (pcls != Digit) 31 buffer[length++] = sep; 32 goto default; 33 default: 34 buffer[length++] = ch; 35 break; 36 } 37 pcls = cls; 38 39 if (length >= buffer.length - 1) 40 break; 41 } 42 return cast(S)buffer[0 .. length].dup; 43 } 44 45 unittest { 46 static void test(string str, string expected) { 47 auto result = str.snakeCase; 48 assert(result == expected, str ~ ": " ~ result); 49 } 50 51 test("AA", "aa"); 52 test("AaA", "aa_a"); 53 test("AaA1", "aa_a_1"); 54 test("AaA11", "aa_a_11"); 55 test("_AaA1", "_aa_a_1"); 56 test("_AaA11_", "_aa_a_11_"); 57 test("aaA", "aa_a"); 58 test("aaAA", "aa_aa"); 59 test("aaAA1", "aa_aa_1"); 60 test("aaAA11", "aa_aa_11"); 61 test("authorName", "author_name"); 62 test("authorBio", "author_bio"); 63 test("authorPortraitId", "author_portrait_id"); 64 test("authorPortraitID", "author_portrait_id"); 65 test("coverURL", "cover_url"); 66 test("coverImageURL", "cover_image_url"); 67 } 68 69 S camelCase(S, bool upper = false)(S input, char sep = '_') { 70 S output; 71 bool upcaseNext = upper; 72 foreach (c; input) { 73 if (c != sep) { 74 if (upcaseNext) { 75 output ~= c.toUpper; 76 upcaseNext = false; 77 } else 78 output ~= c.toLower; 79 } else 80 upcaseNext = true; 81 } 82 return output; 83 } 84 85 unittest { 86 assert("c".camelCase == "c"); 87 assert("c".camelCase!true == "C"); 88 assert("c_a".camelCase == "cA"); 89 assert("ca".camelCase!true == "Ca"); 90 assert("camel".camelCase!true == "Camel"); 91 assert("Camel".camelCase!false == "camel"); 92 assert("camel_case".camelCase!true == "CamelCase"); 93 assert("camel_camel_case".camelCase!true == "CamelCamelCase"); 94 assert("caMel_caMel_caSe".camelCase!true == "CamelCamelCase"); 95 assert("camel2_camel2_case".camelCase!true == "Camel2Camel2Case"); 96 assert("get_http_response_code".camelCase == "getHttpResponseCode"); 97 assert("get2_http_response_code".camelCase == "get2HttpResponseCode"); 98 assert("http_response_code".camelCase!true == "HttpResponseCode"); 99 assert("http_response_code_xyz".camelCase!true == "HttpResponseCodeXyz"); 100 } 101 102 /// Get the keyname of `T` 103 template KeyName(alias T, string defaultName = T.stringof) { 104 import std.traits; 105 106 static if (hasUDA!(T, ignore)) 107 enum KeyName = ""; 108 else static if (hasUDA!(T, as)) 109 enum KeyName = getUDAs!(T, as)[0].name; 110 else 111 static foreach (attr; __traits(getAttributes, T)) 112 static if (is(typeof(KeyName) == void) && is(typeof(attr("")))) 113 enum KeyName = attr(defaultName); 114 static if (is(typeof(KeyName) == void)) 115 enum KeyName = defaultName; 116 } 117 118 alias SQLName = KeyName; 119 }