Skip to content

Commit 7cd49f1

Browse files
committed
0.0.198
1 parent 51d96cc commit 7cd49f1

File tree

3 files changed

+97
-2
lines changed

3 files changed

+97
-2
lines changed

orso/types.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import re
1616
from enum import Enum
1717
from typing import Any
18+
from typing import Iterable
1819
from typing import Tuple
1920
from typing import Type
2021
from typing import Union
@@ -95,7 +96,7 @@ def __init__(self, *args, **kwargs):
9596

9697
def is_numeric(self):
9798
"""is the typle number-based"""
98-
return self in (self.INTEGER, self.DOUBLE, self.DECIMAL)
99+
return self in (self.INTEGER, self.DOUBLE, self.DECIMAL, self.BOOLEAN)
99100

100101
def is_temporal(self):
101102
"""is the type time-based"""
@@ -222,3 +223,59 @@ def from_name(name: str) -> tuple:
222223
OrsoTypes.JSONB: bytes,
223224
OrsoTypes.NULL: lambda x: None,
224225
}
226+
227+
228+
def find_compatible_type(types: Iterable[OrsoTypes]) -> OrsoTypes:
229+
"""
230+
Find the most compatible type that can represent all input types.
231+
232+
Parameters:
233+
types (list): List of OrsoTypes to find a compatible type for
234+
235+
Returns:
236+
OrsoTypes: The most compatible type that can represent all input types
237+
238+
Examples:
239+
>>> OrsoTypes.find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.DOUBLE])
240+
OrsoTypes.DOUBLE
241+
>>> OrsoTypes.find_compatible_type([OrsoTypes.BLOB, OrsoTypes.VARCHAR])
242+
OrsoTypes.VARCHAR
243+
"""
244+
if not types:
245+
return OrsoTypes.NULL
246+
247+
# Handle single type case
248+
if len(set(types)) == 1:
249+
return types[0]
250+
251+
# Define type promotion hierarchy
252+
type_hierarchy = {
253+
# Numeric promotion
254+
OrsoTypes.BOOLEAN: 1,
255+
OrsoTypes.INTEGER: 2,
256+
OrsoTypes.DOUBLE: 3,
257+
OrsoTypes.DECIMAL: 4,
258+
# Temporal promotion
259+
OrsoTypes.DATE: 1,
260+
OrsoTypes.TIMESTAMP: 2,
261+
# String/binary promotion
262+
OrsoTypes.BLOB: 1,
263+
OrsoTypes.VARCHAR: 2,
264+
}
265+
266+
# First check if all types are in the same category
267+
if all(t.is_numeric() for t in types):
268+
return max(types, key=lambda t: type_hierarchy.get(t, 0))
269+
if all(t.is_temporal() for t in types):
270+
return max(types, key=lambda t: type_hierarchy.get(t, 0))
271+
if all(t.is_large_object() for t in types):
272+
return max(types, key=lambda t: type_hierarchy.get(t, 0))
273+
if all(
274+
t in (OrsoTypes.BLOB, OrsoTypes.STRUCT, OrsoTypes.JSONB, OrsoTypes.VARCHAR) for t in types
275+
):
276+
return OrsoTypes.BLOB
277+
278+
# For heterogeneous types, default to the most flexible type
279+
if any(t == OrsoTypes.BLOB for t in types):
280+
return OrsoTypes.BLOB
281+
return OrsoTypes.VARCHAR

orso/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
# See the License for the specific language governing permissions and
1111
# limitations under the License.
1212

13-
__version__: str = "0.0.197"
13+
__version__: str = "0.0.198"
1414
__author__: str = "@joocer"

tests/test_schema.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,44 @@ def test_type_name_parser():
409409
(_type, _length, _scale, _precision, _element_type) = OrsoTypes.from_name("ARRAY<TIMESTAMP>")
410410
assert (_type, _length, _scale, _precision, _element_type) == (OrsoTypes.ARRAY, None, None, None, OrsoTypes.TIMESTAMP)
411411

412+
def test_type_combinations():
413+
414+
from orso.types import find_compatible_type
415+
416+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.INTEGER]) == OrsoTypes.INTEGER
417+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.DOUBLE]) == OrsoTypes.DOUBLE
418+
assert find_compatible_type([OrsoTypes.DOUBLE, OrsoTypes.INTEGER]) == OrsoTypes.DOUBLE
419+
assert find_compatible_type([OrsoTypes.DOUBLE, OrsoTypes.DOUBLE]) == OrsoTypes.DOUBLE
420+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.DECIMAL]) == OrsoTypes.DECIMAL
421+
assert find_compatible_type([OrsoTypes.DECIMAL, OrsoTypes.INTEGER]) == OrsoTypes.DECIMAL
422+
assert find_compatible_type([OrsoTypes.DECIMAL, OrsoTypes.DECIMAL]) == OrsoTypes.DECIMAL
423+
assert find_compatible_type([OrsoTypes.DECIMAL, OrsoTypes.DOUBLE]) == OrsoTypes.DECIMAL
424+
assert find_compatible_type([OrsoTypes.DOUBLE, OrsoTypes.DECIMAL]) == OrsoTypes.DECIMAL
425+
assert find_compatible_type([OrsoTypes.DOUBLE, OrsoTypes.DOUBLE]) == OrsoTypes.DOUBLE
426+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.TIMESTAMP]) == OrsoTypes.VARCHAR
427+
assert find_compatible_type([OrsoTypes.TIMESTAMP, OrsoTypes.INTEGER]) == OrsoTypes.VARCHAR
428+
assert find_compatible_type([OrsoTypes.TIMESTAMP, OrsoTypes.TIMESTAMP]) == OrsoTypes.TIMESTAMP
429+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.VARCHAR]) == OrsoTypes.VARCHAR
430+
assert find_compatible_type([OrsoTypes.VARCHAR, OrsoTypes.INTEGER]) == OrsoTypes.VARCHAR
431+
assert find_compatible_type([OrsoTypes.VARCHAR, OrsoTypes.VARCHAR]) == OrsoTypes.VARCHAR
432+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.BLOB]) == OrsoTypes.BLOB
433+
assert find_compatible_type([OrsoTypes.BLOB, OrsoTypes.INTEGER]) == OrsoTypes.BLOB
434+
assert find_compatible_type([OrsoTypes.BLOB, OrsoTypes.BLOB]) == OrsoTypes.BLOB
435+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.BOOLEAN]) == OrsoTypes.INTEGER
436+
assert find_compatible_type([OrsoTypes.BOOLEAN, OrsoTypes.INTEGER]) == OrsoTypes.INTEGER
437+
assert find_compatible_type([OrsoTypes.BOOLEAN, OrsoTypes.BOOLEAN]) == OrsoTypes.BOOLEAN
438+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.DATE]) == OrsoTypes.VARCHAR
439+
assert find_compatible_type([OrsoTypes.DATE, OrsoTypes.INTEGER]) == OrsoTypes.VARCHAR
440+
assert find_compatible_type([OrsoTypes.DATE, OrsoTypes.DATE]) == OrsoTypes.DATE
441+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.ARRAY]) == OrsoTypes.VARCHAR
442+
assert find_compatible_type([OrsoTypes.ARRAY, OrsoTypes.INTEGER]) == OrsoTypes.VARCHAR
443+
assert find_compatible_type([OrsoTypes.ARRAY, OrsoTypes.ARRAY]) == OrsoTypes.ARRAY
444+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.STRUCT]) == OrsoTypes.VARCHAR
445+
assert find_compatible_type([OrsoTypes.STRUCT, OrsoTypes.INTEGER]) == OrsoTypes.VARCHAR
446+
assert find_compatible_type([OrsoTypes.STRUCT, OrsoTypes.STRUCT]) == OrsoTypes.STRUCT
447+
assert find_compatible_type([OrsoTypes.INTEGER, OrsoTypes.JSONB]) == OrsoTypes.VARCHAR
448+
449+
412450
if __name__ == "__main__": # prgama: nocover
413451
from tests import run_tests
414452

0 commit comments

Comments
 (0)