Coverage for python/felis/utils.py: 16%

49 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-03-09 03:01 -0800

1# This file is part of felis. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22from collections.abc import Mapping, MutableMapping 

23from typing import Any, Iterable 

24 

25_Mapping = Mapping[str, Any] 

26_MutableMapping = MutableMapping[str, Any] 

27 

28 

29class ReorderingVisitor: 

30 def __init__(self, add_type: bool = False): 

31 """ 

32 A visitor that reorders and optionall adds the "@type" 

33 :param add_type: If true, add the "@type" if it doesn't exist 

34 """ 

35 self.add_type = add_type 

36 

37 def visit_schema(self, schema_obj: _MutableMapping) -> _Mapping: 

38 """The input MUST be a normalized representation""" 

39 # Override with default 

40 tables = [self.visit_table(table_obj, schema_obj) for table_obj in schema_obj["tables"]] 

41 schema_obj["tables"] = tables 

42 if self.add_type: 

43 schema_obj["@type"] = schema_obj.get("@type", "Schema") 

44 return _new_order(schema_obj, ["@context", "name", "@id", "@type", "description", "tables"]) 

45 

46 def visit_table(self, table_obj: _MutableMapping, schema_obj: _Mapping) -> _Mapping: 

47 columns = [self.visit_column(c, table_obj) for c in table_obj["columns"]] 

48 primary_key = self.visit_primary_key(table_obj.get("primaryKey", []), table_obj) 

49 constraints = [self.visit_constraint(c, table_obj) for c in table_obj.get("constraints", [])] 

50 indexes = [self.visit_index(i, table_obj) for i in table_obj.get("indexes", [])] 

51 table_obj["columns"] = columns 

52 if primary_key: 

53 table_obj["primaryKey"] = primary_key 

54 if constraints: 

55 table_obj["constraints"] = constraints 

56 if indexes: 

57 table_obj["indexes"] = indexes 

58 if self.add_type: 

59 table_obj["@type"] = table_obj.get("@type", "Table") 

60 return _new_order( 

61 table_obj, 

62 ["name", "@id", "@type", "description", "columns", "primaryKey", "constraints", "indexes"], 

63 ) 

64 

65 def visit_column(self, column_obj: _MutableMapping, table_obj: _Mapping) -> _Mapping: 

66 if self.add_type: 

67 column_obj["@type"] = column_obj.get("@type", "Column") 

68 return _new_order(column_obj, ["name", "@id", "@type", "description", "datatype"]) 

69 

70 def visit_primary_key(self, primary_key_obj: _MutableMapping, table: _Mapping) -> _Mapping: 

71 # FIXME: Handle Primary Keys 

72 return primary_key_obj 

73 

74 def visit_constraint(self, constraint_obj: _MutableMapping, table: _Mapping) -> _Mapping: 

75 # Type MUST be present... we can skip 

76 return _new_order(constraint_obj, ["name", "@id", "@type", "description"]) 

77 

78 def visit_index(self, index_obj: _MutableMapping, table: _Mapping) -> _Mapping: 

79 if self.add_type: 

80 index_obj["@type"] = index_obj.get("@type", "Index") 

81 return _new_order(index_obj, ["name", "@id", "@type", "description"]) 

82 

83 

84def _new_order(obj: _Mapping, order: Iterable[str]) -> _Mapping: 

85 reordered_object: _MutableMapping = {} 

86 for name in order: 

87 if name in obj: 

88 reordered_object[name] = obj[name] 

89 for key, value in obj.items(): 

90 if key not in reordered_object: 

91 reordered_object[key] = value 

92 return reordered_object