1 /***********************************************************************************************
2 *	Copyright: © 2017-2021 UI Manufaktur UG
3 *	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
4 *	Authors: UI Manufaktur Team
5 *	Documentation [DE]: https://ui-manufaktur.com/docu/uim-core/containers/aa
6 ************************************************************************************************/
7 module uim.core.containers.aa;
8 
9 @safe:
10 import uim.core;
11 
12 enum SORTED = true;
13 
14 /// get keys of an associative array
15 @safe K[] getKeys(K, V)(V[K] aa, bool sorted = false) {
16 	K[] results;
17 	foreach(k, v; aa) results ~= k;
18 	if (sorted) return results.sort.array;
19 	return results;
20 }
21 unittest {
22 	// Examples by value
23 	assert([1:4, 2:5, 3:6].getKeys(SORTED) == [1, 2, 3]);
24 	assert([1:"4", 2:"5", 3:"6"].getKeys(SORTED) == [1, 2, 3]);
25 	assert(["1":4, "2":5, "3":6].getKeys(SORTED) == ["1", "2", "3"]);
26 	assert(["1":"4", "2":"5", "3":"6"].getKeys(SORTED) == ["1", "2", "3"]);
27 	
28 	// Examples by reference
29 	class Test {}
30 	auto a = new Test;
31 	auto b = new Test;
32 	auto c = new Test;
33 	assert([1:a, 2:b, 3:c].getKeys(SORTED) == [1, 2, 3]);
34 }
35 
36 /// get values of an associative array - currently not working für objects
37 @safe V[] getValues(K, V)(V[K] aa, bool sorted = false) {
38 	V[] results;
39 	foreach(k, v; aa) results ~= v;
40 	if (sorted) return results.sort.array;
41 	return results;
42 }
43 unittest {
44 	assert([1:4, 2:5, 3:6].getValues(SORTED) == [4, 5, 6]);
45 	assert([1:"4", 2:"5", 3:"6"].getValues(SORTED) == ["4", "5", "6"]);
46 	assert(["1":4, "2":5, "3":6].getValues(SORTED) == [4, 5, 6]);
47 	assert(["1":"4", "2":"5", "3":"6"].getValues(SORTED) == ["4", "5", "6"]);
48 }
49 
50 // Add Items from array
51 @safe T[S] add(T, S)(T[S] baseItems, T[S] addItems) {
52 	T[S] results = baseItems.dup;
53 	foreach(k, v; addItems) results[k] = v;
54 	return results;
55 }
56 unittest {
57 	assert([1:"b", 2:"d"].add([3:"f"]) == [1:"b", 2:"d", 3:"f"]);
58 	assert(["a":"b", "c":"d"].add(["e":"f"]) == ["a":"b", "c":"d", "e":"f"]);
59 	assert(["a":"b", "c":"d"].add(["e":"f"]).add(["g":"h"]) == ["a":"b", "c":"d", "e":"f", "g":"h"]);
60 }
61 
62 /// remove subItems from baseItems if key and value of item are equal
63 @safe T[S] sub(T, S)(T[S] baseItems, T[S] subItems) {
64 	T[S] results = baseItems.dup;
65 	foreach(k, v; subItems) 
66 		if ((k in results) && (results[k] == v)) results.remove(k);
67 	return results;
68 }
69 unittest {
70  	assert([1:"4", 2:"5", 3:"6"].sub([1:"5", 2:"5", 3:"6"]) == [1:"4"]);
71 }
72 
73 /// remove subItems from baseItems if key exists
74 @safe T[S] subKeys(T, S)(T[S] baseItems, S[] subItems...) {
75 	return subKeys(baseItems, subItems);
76 }
77 unittest {
78  	assert([1:"4", 2:"5", 3:"6"].subKeys(2, 3) == [1:"4"]);
79 }
80 
81 /// remove subItems from baseItems if key exists
82 @safe T[S] subKeys(T, S)(T[S] baseItems, S[] subItems) {
83 	T[S] results = baseItems.dup;
84 	foreach(key; subItems) results.remove(key);
85 	return results;
86 }
87 unittest {
88  	assert([1:"4", 2:"5", 3:"6"].subKeys([2, 3]) == [1:"4"]);
89 }
90 
91 /// remove subItems from baseItems if key exists
92 @safe T[S] subKeys(T, S)(T[S] baseItems, T[S] subItems) {
93 	T[S] results = baseItems.dup;
94 	foreach(k, v; subItems) results.remove(k);
95 	return results;
96 }
97 unittest {
98  	assert([1:"4", 2:"5", 3:"6"].subKeys([2:"x", 3:"y"]) == [1:"4"]);
99 }
100 
101 /// remove subItems from baseItems if value exists
102 @safe T[S] subValues(T, S)(T[S] baseItems, T[S] subItems) {
103 	T[S] results = baseItems.dup;
104 	foreach(k, v; subItems) {
105 		foreach(kk, vv; baseItems) if (v == vv) results.remove(kk);
106 	}
107 	return results;
108 }
109 unittest {
110  	assert([1:"4", 2:"5", 3:"6"].subValues([2:"5", 3:"6"]) == [1:"4"]);
111  	assert([7:"4", 8:"5", 9:"6"].subValues([2:"5", 3:"6"]) == [7:"4"]);
112  	assert([7:"4", 8:"5", 9:"6"].subValues([2:"2", 3:"2"]) != [7:"4"]);
113 
114  	assert([1:4, 2:5, 3:6].subValues([2:5, 3:6]) == [1:4]);
115  	assert([7:4, 8:5, 9:6].subValues([2:5, 3:6]) == [7:4]);
116  	assert([7:4, 8:5, 9:6].subValues([2:2, 3:2]) != [7:4]);
117 }
118 
119 @safe pure size_t[T] indexAA(T)(T[] values, size_t startPos = 0) {
120 	size_t[T] results;
121 	foreach(i, value; values) results[value] = i + startPos;
122 	return results;
123 }
124 unittest {
125 	assert(["a", "b", "c"].indexAA == ["a":0UL, "b":1UL, "c":2UL]);
126 	assert(["a", "b", "c"].indexAA(1) == ["a":1UL, "b":2UL, "c":3UL]);
127 }
128 
129 @safe pure size_t[T] indexAAReverse(T)(T[] values, size_t startPos = 0) {
130 	size_t[T] results;
131 	foreach(i, value; values) results[i + startPos] = value;
132 	return results;
133 }
134 unittest {
135 	//
136 }
137 
138 @safe bool hasKey(T, S)(T[S] base, S key) { return (key in base) ? true : false; }
139 @safe bool hasKeys(T, S)(T[S] base, S[] keys...) { return base.hasKeys(keys); }
140 @safe bool hasKeys(T, S)(T[S] base, S[] keys) { bool result; foreach(key; keys) if (key !in base) return false; return true; }
141 unittest {
142 	assert(["a":"b", "c":"d"].hasKey("a"));
143 	assert(["a":"b", "c":"d"].hasKeys("a"));
144 	assert(["a":"b", "c":"d"].hasKeys("a", "c"));
145 	assert(["a":"b", "c":"d"].hasKeys(["a"]));
146 	assert(["a":"b", "c":"d"].hasKeys(["a", "c"]));
147 }
148 
149 @safe bool hasValue(T, S)(T[S] base, S value...) { foreach(v; base.getValues) if (v == value) return true; return false; }
150 @safe bool hasValues(T, S)(T[S] base, S[] values...) { return base.hasValues(values); }
151 @safe bool hasValues(T, S)(T[S] base, S[] values) { foreach(value; values) if (!base.hasValue(value)) return false; return true; }
152 unittest {
153 	assert(["a":"b", "c":"d"].hasValue("b"));
154 	assert(["a":"b", "c":"d"].hasValues("b"));
155 	assert(["a":"b", "c":"d"].hasValues("b", "d"));
156 	assert(["a":"b", "c":"d"].hasValues(["b"]));
157 	assert(["a":"b", "c":"d"].hasValues(["b", "d"]));
158 }
159 
160 @safe pure string toJSONString(T)(T[string] values, bool sorted = false) {
161 	string[] result; 
162 
163 	foreach(k; values.getKeys(sorted)) result ~= `"%s":%s`.format(k, values[k]);
164 
165 	return "{"~result.join(",")~"}";
166 }
167 unittest {
168 	assert(["a":1, "b":2].toJSONString(SORTED) == `{"a":1,"b":2}`);
169 }
170 
171 @safe pure string toHTML(T)(T[string] values, bool sorted = false) {
172 	string[] results; 
173 	foreach(k; values.getKeys(sorted)) {
174 		results ~= `%s="%s"`.format(k, values[k]);
175 	}
176 	return results.join(" ");
177 }
178 unittest {
179 	assert(["a":1, "b":2].toHTML(SORTED) == `a="1" b="2"`);
180 }
181 
182 @safe pure string toSqlUpdate(T)(T[string] values, bool sorted = false) {
183 	string[] results; 
184 	foreach(k; values.getKeys(sorted)) results ~= `%s=%s`.format(k, values[k]);
185 	return results.join(",");
186 }
187 unittest {
188 	assert(["a":1, "b":2].toSqlUpdate(SORTED) == `a=1,b=2`);
189 }