reifydb_type/value/type/
promote.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the MIT, see license.md file
3
4use std::cmp::min;
5
6use crate::Type;
7
8impl Type {
9	/// Promote two Types to a common supertype, similar to Postgres
10	/// expression evaluation.
11	pub fn promote(left: Type, right: Type) -> Type {
12		use Type::*;
13
14		if left == Undefined || right == Undefined {
15			return Undefined;
16		}
17
18		if left == Utf8 || right == Utf8 {
19			return Utf8;
20		}
21
22		if left == Boolean || right == Boolean {
23			return Boolean;
24		}
25
26		if left == Float8 || right == Float8 {
27			return Float8;
28		}
29
30		if left == Float4 || right == Float4 {
31			return Float8;
32		}
33
34		let signed_order = [Int1, Int2, Int4, Int8, Int16];
35		let unsigned_order = [Uint1, Uint2, Uint4, Uint8, Uint16];
36
37		let is_signed = |k: Type| signed_order.contains(&k);
38		let is_unsigned = |k: Type| unsigned_order.contains(&k);
39
40		let rank = |k: Type| match k {
41			Int1 | Uint1 => 0,
42			Int2 | Uint2 => 1,
43			Int4 | Uint4 => 2,
44			Int8 | Uint8 => 3,
45			Int16 | Uint16 => 4,
46			_ => usize::MAX,
47		};
48
49		if is_signed(left) && is_signed(right) {
50			return signed_order[min(rank(left).max(rank(right)), 3) + 1];
51		}
52
53		if is_unsigned(left) && is_unsigned(right) {
54			return unsigned_order[min(rank(left).max(rank(right)), 3) + 1];
55		}
56
57		if (is_signed(left) && is_unsigned(right)) || (is_unsigned(left) && is_signed(right)) {
58			return match rank(left).max(rank(right)) + 1 {
59				0 => Int1,
60				1 => Int2,
61				2 => Int4,
62				3 => Int8,
63				4 => Int16,
64				_ => Int16,
65			};
66		}
67
68		Undefined
69	}
70}
71
72#[cfg(test)]
73mod tests {
74	use crate::{
75		Type,
76		Type::{
77			Boolean, Float4, Float8, Int1, Int2, Int4, Int8, Int16, Uint1, Uint2, Uint4, Uint8, Uint16,
78			Undefined, Utf8,
79		},
80	};
81
82	#[test]
83	fn test_promote_bool() {
84		let cases = [
85			(Boolean, Boolean, Boolean),
86			(Boolean, Float4, Boolean),
87			(Boolean, Float8, Boolean),
88			(Boolean, Int1, Boolean),
89			(Boolean, Int2, Boolean),
90			(Boolean, Int4, Boolean),
91			(Boolean, Int8, Boolean),
92			(Boolean, Int16, Boolean),
93			(Boolean, Utf8, Utf8),
94			(Boolean, Uint1, Boolean),
95			(Boolean, Uint2, Boolean),
96			(Boolean, Uint4, Boolean),
97			(Boolean, Uint8, Boolean),
98			(Boolean, Uint16, Boolean),
99			(Boolean, Undefined, Undefined),
100		];
101		for (left, right, expected) in cases {
102			assert_eq!(Type::promote(left, right), expected);
103		}
104	}
105
106	#[test]
107	fn test_promote_float4() {
108		let cases = [
109			(Float4, Boolean, Boolean),
110			(Float4, Float4, Float8),
111			(Float4, Float8, Float8),
112			(Float4, Int1, Float8),
113			(Float4, Int2, Float8),
114			(Float4, Int4, Float8),
115			(Float4, Int8, Float8),
116			(Float4, Int16, Float8),
117			(Float4, Utf8, Utf8),
118			(Float4, Uint1, Float8),
119			(Float4, Uint2, Float8),
120			(Float4, Uint4, Float8),
121			(Float4, Uint8, Float8),
122			(Float4, Uint16, Float8),
123			(Float4, Undefined, Undefined),
124		];
125		for (left, right, expected) in cases {
126			assert_eq!(Type::promote(left, right), expected);
127		}
128	}
129
130	#[test]
131	fn test_promote_float8() {
132		let cases = [
133			(Float8, Boolean, Boolean),
134			(Float8, Float4, Float8),
135			(Float8, Float8, Float8),
136			(Float8, Int1, Float8),
137			(Float8, Int2, Float8),
138			(Float8, Int4, Float8),
139			(Float8, Int8, Float8),
140			(Float8, Int16, Float8),
141			(Float8, Utf8, Utf8),
142			(Float8, Uint1, Float8),
143			(Float8, Uint2, Float8),
144			(Float8, Uint4, Float8),
145			(Float8, Uint8, Float8),
146			(Float8, Uint16, Float8),
147			(Float8, Undefined, Undefined),
148		];
149		for (left, right, expected) in cases {
150			assert_eq!(Type::promote(left, right), expected);
151		}
152	}
153
154	#[test]
155	fn test_promote_int1() {
156		let cases = [
157			(Int1, Boolean, Boolean),
158			(Int1, Float4, Float8),
159			(Int1, Float8, Float8),
160			(Int1, Int1, Int2),
161			(Int1, Int2, Int4),
162			(Int1, Int4, Int8),
163			(Int1, Int8, Int16),
164			(Int1, Int16, Int16),
165			(Int1, Utf8, Utf8),
166			(Int1, Uint1, Int2),
167			(Int1, Uint2, Int4),
168			(Int1, Uint4, Int8),
169			(Int1, Uint8, Int16),
170			(Int1, Uint16, Int16),
171			(Int1, Undefined, Undefined),
172		];
173		for (left, right, expected) in cases {
174			assert_eq!(Type::promote(left, right), expected);
175		}
176	}
177
178	#[test]
179	fn test_promote_int2() {
180		let cases = [
181			(Int2, Boolean, Boolean),
182			(Int2, Float4, Float8),
183			(Int2, Float8, Float8),
184			(Int2, Int1, Int4),
185			(Int2, Int2, Int4),
186			(Int2, Int4, Int8),
187			(Int2, Int8, Int16),
188			(Int2, Int16, Int16),
189			(Int2, Utf8, Utf8),
190			(Int2, Uint1, Int4),
191			(Int2, Uint2, Int4),
192			(Int2, Uint4, Int8),
193			(Int2, Uint8, Int16),
194			(Int2, Uint16, Int16),
195			(Int2, Undefined, Undefined),
196		];
197		for (left, right, expected) in cases {
198			assert_eq!(Type::promote(left, right), expected);
199		}
200	}
201
202	#[test]
203	fn test_promote_int4() {
204		let cases = [
205			(Int4, Boolean, Boolean),
206			(Int4, Float4, Float8),
207			(Int4, Float8, Float8),
208			(Int4, Int1, Int8),
209			(Int4, Int2, Int8),
210			(Int4, Int4, Int8),
211			(Int4, Int8, Int16),
212			(Int4, Int16, Int16),
213			(Int4, Utf8, Utf8),
214			(Int4, Uint1, Int8),
215			(Int4, Uint2, Int8),
216			(Int4, Uint4, Int8),
217			(Int4, Uint8, Int16),
218			(Int4, Uint16, Int16),
219			(Int4, Undefined, Undefined),
220		];
221		for (left, right, expected) in cases {
222			assert_eq!(Type::promote(left, right), expected);
223		}
224	}
225
226	#[test]
227	fn test_promote_int8() {
228		let cases = [
229			(Int8, Boolean, Boolean),
230			(Int8, Float4, Float8),
231			(Int8, Float8, Float8),
232			(Int8, Int1, Int16),
233			(Int8, Int2, Int16),
234			(Int8, Int4, Int16),
235			(Int8, Int8, Int16),
236			(Int8, Int16, Int16),
237			(Int8, Utf8, Utf8),
238			(Int8, Uint1, Int16),
239			(Int8, Uint2, Int16),
240			(Int8, Uint4, Int16),
241			(Int8, Uint8, Int16),
242			(Int8, Uint16, Int16),
243			(Int8, Undefined, Undefined),
244		];
245		for (left, right, expected) in cases {
246			assert_eq!(Type::promote(left, right), expected);
247		}
248	}
249
250	#[test]
251	fn test_promote_int16() {
252		let cases = [
253			(Int16, Boolean, Boolean),
254			(Int16, Float4, Float8),
255			(Int16, Float8, Float8),
256			(Int16, Int1, Int16),
257			(Int16, Int2, Int16),
258			(Int16, Int4, Int16),
259			(Int16, Int8, Int16),
260			(Int16, Int16, Int16),
261			(Int16, Utf8, Utf8),
262			(Int16, Uint1, Int16),
263			(Int16, Uint2, Int16),
264			(Int16, Uint4, Int16),
265			(Int16, Uint8, Int16),
266			(Int16, Uint16, Int16),
267			(Int16, Undefined, Undefined),
268		];
269		for (left, right, expected) in cases {
270			assert_eq!(Type::promote(left, right), expected);
271		}
272	}
273
274	#[test]
275	fn test_promote_string() {
276		let kinds = [
277			Boolean, Float4, Float8, Int1, Int2, Int4, Int8, Int16, Utf8, Uint1, Uint2, Uint4, Uint8,
278			Uint16,
279		];
280		for ty in kinds {
281			assert_eq!(Type::promote(Utf8, ty), Utf8);
282		}
283
284		assert_eq!(Type::promote(Utf8, Undefined), Undefined);
285	}
286
287	#[test]
288	fn test_promote_uint1() {
289		let cases = [
290			(Uint1, Boolean, Boolean),
291			(Uint1, Float4, Float8),
292			(Uint1, Float8, Float8),
293			(Uint1, Int1, Int2),
294			(Uint1, Int2, Int4),
295			(Uint1, Int4, Int8),
296			(Uint1, Int8, Int16),
297			(Uint1, Int16, Int16),
298			(Uint1, Utf8, Utf8),
299			(Uint1, Uint1, Uint2),
300			(Uint1, Uint2, Uint4),
301			(Uint1, Uint4, Uint8),
302			(Uint1, Uint8, Uint16),
303			(Uint1, Uint16, Uint16),
304			(Uint1, Undefined, Undefined),
305		];
306		for (left, right, expected) in cases {
307			assert_eq!(Type::promote(left, right), expected);
308		}
309	}
310
311	#[test]
312	fn test_promote_uint2() {
313		let cases = [
314			(Uint2, Boolean, Boolean),
315			(Uint2, Float4, Float8),
316			(Uint2, Float8, Float8),
317			(Uint2, Int1, Int4),
318			(Uint2, Int2, Int4),
319			(Uint2, Int4, Int8),
320			(Uint2, Int8, Int16),
321			(Uint2, Int16, Int16),
322			(Uint2, Utf8, Utf8),
323			(Uint2, Uint1, Uint4),
324			(Uint2, Uint2, Uint4),
325			(Uint2, Uint4, Uint8),
326			(Uint2, Uint8, Uint16),
327			(Uint2, Uint16, Uint16),
328			(Uint2, Undefined, Undefined),
329		];
330		for (left, right, expected) in cases {
331			assert_eq!(Type::promote(left, right), expected);
332		}
333	}
334
335	#[test]
336	fn test_promote_uint4() {
337		let cases = [
338			(Uint4, Boolean, Boolean),
339			(Uint4, Float4, Float8),
340			(Uint4, Float8, Float8),
341			(Uint4, Int1, Int8),
342			(Uint4, Int2, Int8),
343			(Uint4, Int4, Int8),
344			(Uint4, Int8, Int16),
345			(Uint4, Int16, Int16),
346			(Uint4, Utf8, Utf8),
347			(Uint4, Uint1, Uint8),
348			(Uint4, Uint2, Uint8),
349			(Uint4, Uint4, Uint8),
350			(Uint4, Uint8, Uint16),
351			(Uint4, Uint16, Uint16),
352			(Uint4, Undefined, Undefined),
353		];
354		for (left, right, expected) in cases {
355			assert_eq!(Type::promote(left, right), expected);
356		}
357	}
358
359	#[test]
360	fn test_promote_uint8() {
361		let cases = [
362			(Uint8, Boolean, Boolean),
363			(Uint8, Float4, Float8),
364			(Uint8, Float8, Float8),
365			(Uint8, Int1, Int16),
366			(Uint8, Int2, Int16),
367			(Uint8, Int4, Int16),
368			(Uint8, Int8, Int16),
369			(Uint8, Int16, Int16),
370			(Uint8, Utf8, Utf8),
371			(Uint8, Uint1, Uint16),
372			(Uint8, Uint2, Uint16),
373			(Uint8, Uint4, Uint16),
374			(Uint8, Uint8, Uint16),
375			(Uint8, Uint16, Uint16),
376			(Uint8, Undefined, Undefined),
377		];
378		for (left, right, expected) in cases {
379			assert_eq!(Type::promote(left, right), expected);
380		}
381	}
382
383	#[test]
384	fn test_promote_uint16() {
385		let cases = [
386			(Uint16, Boolean, Boolean),
387			(Uint16, Float4, Float8),
388			(Uint16, Float8, Float8),
389			(Uint16, Int1, Int16),
390			(Uint16, Int2, Int16),
391			(Uint16, Int4, Int16),
392			(Uint16, Int8, Int16),
393			(Uint16, Int16, Int16),
394			(Uint16, Utf8, Utf8),
395			(Uint16, Uint1, Uint16),
396			(Uint16, Uint2, Uint16),
397			(Uint16, Uint4, Uint16),
398			(Uint16, Uint8, Uint16),
399			(Uint16, Uint16, Uint16),
400			(Uint16, Undefined, Undefined),
401		];
402		for (left, right, expected) in cases {
403			assert_eq!(Type::promote(left, right), expected);
404		}
405	}
406
407	#[test]
408	fn test_promote_undefined() {
409		let kinds = [
410			Boolean, Float4, Float8, Int1, Int2, Int4, Int8, Int16, Utf8, Uint1, Uint2, Uint4, Uint8,
411			Uint16, Undefined,
412		];
413		for ty in kinds {
414			assert_eq!(Type::promote(Undefined, ty), Undefined);
415		}
416	}
417}