Coverage for gws-app/gws/base/model/scalar_field.py: 83%

71 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-05 13:35 +0200

1"""Base class for scalar fields.""" 

2 

3from typing import Optional, Callable, cast 

4 

5import gws 

6import gws.base.model.field 

7 

8 

9class Config(gws.base.model.field.Config): 

10 """Configuration for the scalar field.""" 

11 

12 isVirtual: Optional[bool] 

13 """The field is not read from or written to the database.""" 

14 

15 

16class Props(gws.base.model.field.Props): 

17 pass 

18 

19 

20class Object(gws.base.model.field.Object): 

21 """Base scalar field. 

22 

23 Maps the field to the source column with the same name. Provides reading the column 

24 and writing it to the record, and the transfer of the value between record, feature 

25 and props, applying value objects and field permissions. 

26 """ 

27 

28 isVirtual: bool 

29 """The field is not read from or written to the database.""" 

30 

31 def configure(self): 

32 self.isVirtual = self.cfg('isVirtual', default=False) 

33 

34 def before_select(self, mc): 

35 if self.isVirtual: 

36 return 

37 model = cast(gws.DatabaseModel, self.model) 

38 mc.dbSelect.columns.append(model.column(self.name)) 

39 

40 def after_select(self, features, mc): 

41 for feature in features: 

42 self.from_record(feature, mc) 

43 

44 def before_create(self, feature, mc): 

45 if self.isAuto: 

46 return 

47 if self.isVirtual: 

48 return 

49 self.to_record(feature, mc) 

50 

51 def before_update(self, feature, mc): 

52 if self.isAuto: 

53 return 

54 if self.isVirtual: 

55 return 

56 self.to_record(feature, mc) 

57 

58 ## 

59 

60 def from_props(self, feature, mc): 

61 value = feature.props.attributes.get(self.name) 

62 if value is not None: 

63 value = self.prop_to_python(feature, value, mc) 

64 if value is not None: 

65 feature.set(self.name, value) 

66 

67 def to_props(self, feature, mc): 

68 if not mc.user.can_read(self): 

69 return 

70 value = feature.get(self.name) 

71 if value is not None: 

72 value = self.python_to_prop(feature, value, mc) 

73 if value is not None: 

74 feature.props.attributes[self.name] = value 

75 

76 ## 

77 

78 def do_init(self, feature, mc): 

79 value = self.get_value( 

80 feature, 

81 {}, 

82 mc.user.can_read(self), 

83 self.prop_to_python, 

84 mc, 

85 ) 

86 if value is not None: 

87 feature.set(self.name, value) 

88 

89 ## 

90 

91 def from_record(self, feature, mc): 

92 value = self.get_value( 

93 feature, 

94 feature.record.attributes, 

95 mc.user.can_read(self), 

96 self.raw_to_python, 

97 mc, 

98 ) 

99 if value is not None: 

100 feature.set(self.name, value) 

101 

102 def to_record(self, feature, mc): 

103 value = self.get_value( 

104 feature, 

105 feature.attributes, 

106 mc.user.can_write(self), 

107 self.python_to_raw, 

108 mc, 

109 ) 

110 if value is not None: 

111 feature.record.attributes[self.name] = value 

112 

113 def get_value( 

114 self, 

115 feature: gws.Feature, 

116 source: dict, 

117 has_access: bool, 

118 convert_fn: Callable, 

119 mc: gws.ModelContext, 

120 ): 

121 """Compute the field value for the current operation. 

122 

123 A value object that is not a default value provides the value. Otherwise the value 

124 is taken from ``source`` and converted, if the user has access and the value is not 

125 None. Otherwise a default value object provides the value. 

126 

127 Args: 

128 feature: The feature. 

129 source: A dict of attributes to read the value from. 

130 has_access: Whether the user may access the field. 

131 convert_fn: Function ``(feature, value, mc)`` that converts the source value. 

132 mc: The model context. 

133 

134 Returns: 

135 The value, or None if there is none. 

136 """ 

137 mv = self.model_value(mc) 

138 

139 if mv and not mv.isDefault: 

140 return mv.compute(self, feature, mc) 

141 

142 if has_access and self.name in source: 

143 value = source.get(self.name) 

144 if value is not None: 

145 return convert_fn(feature, value, mc) 

146 

147 if mv: 

148 return mv.compute(self, feature, mc) 

149 

150 def model_value(self, mc: gws.ModelContext): 

151 """Return the first value object for the current operation that the user can use. 

152 

153 Args: 

154 mc: The model context. 

155 

156 Returns: 

157 The value object, or None if there is none. 

158 """ 

159 for mv in self.values: 

160 if mc.op in mv.ops and mc.user.can_use(mv): 

161 return mv