# Learn about Properties As you may already know, every SJD model has a set of properties. This properties inform the package about type of data you gonna put inside it. Here you'll learn more about available properties that you can use inside your model. Available types are those are available in JSON: - `String` - `Integer` - `Float` - `Boolean` - `List` ( or `Array` ) - `Object` ( another JSON object ) ## Access You can access all of properties in one place like this: ```py from sjd import properties as props ``` ## Options Every property has a set of options that you can modify based on your case. - `init`: Indicates if this property should be passed to model's `__init__` function or not ( If there's any `__init__` function defined ). - `json_property_name`: The property name inside json file. Defaults to attribute name. - `required`: Indicates if this property should always be available while serializing or deserializing object. ## Explain Here you can find a brief explanation about all properties and their use case. ### `props.string()` For python `str` fields. **Required Parameters:** _This method has no required parameter._ ```py class Model(TEntity): # ---- sniff ---- string_field = props.string() # ---- sniff ---- ``` ### `props.integer()` For python `int` fields. **Required Parameters:** _This method has no required parameter._ ```py class Model(TEntity): # ---- sniff ---- integer_field = props.integer() # ---- sniff ---- ``` ### `props.double()` For python `float` fields. ( Why i named it like this then? ) **Required Parameters:** _This method has no required parameter._ ```py class Model(TEntity): # ---- sniff ---- float_field = props.double() # ---- sniff ---- ``` ### `props.boolean()` For python `bool` fields. **Required Parameters:** _This method has no required parameter._ ```py class Model(TEntity): # ---- sniff ---- bool_field = props.boolean() # ---- sniff ---- ``` ### `props.array()` For python `list` fields. You can use this to store a list of any valid type. Note that, if wanna use a list of other models inside your model, it should be a subclass of `EmbeddedEntity`. **Required Parameters:** - `of_typed`: You should pass the type of objects this field should store. ```py class OtherModel(EmbeddedEntity): # ---- sniff ---- class Model(TEntity): # ---- sniff ---- str_list_field = props.array(str) other_models_field = props.array(OtherModel) ... # ---- sniff ---- ``` ### `props.entity()` For other python model inside your model. Note that, the model should be a subclass of `EmbeddedEntity`. **Required Parameters:** - `of_typed`: You should pass the type of object this field should store. ```py class OtherModel(EmbeddedEntity): # ---- sniff ---- class Model(TEntity): # ---- sniff ---- other_model_field = props.entity(OtherModel) ... # ---- sniff ---- ``` ### `props.from_entity()` This is for virtual properties. ([Read more](VirtualProperties.md)) To use other models inside your model virtually ( or lazily ). It's like `props.entity` but the target entity is saved inside another collection and it's not included inside main entity unless you ask for it. Note that, the type your gonna use here should be a subclass of `Entity`. You can consider this as a **one-to-one** relation between two collections. **Required Parameters:** - `of_typed`: You should pass the type of object this field should store. - `refers_to`: The name of reference property inside other entity. ```py class OtherModel(Entity): # ---- sniff ---- model_id = props.reference() class Model(TEntity): # ---- sniff ---- other_model_field = props.from_entity(OtherModel, "model_id") ... # ---- sniff ---- ``` ### `props.from_entities()` It's like [props.from_entity()](Properties.md/#propsfromentity), for a list of other model. You can consider this as a **one-to-many** relation. **Required Parameters:** - `of_typed`: You should pass the type of objects this field should store. - `refers_to`: The name of reference property inside other entity. ```py class OtherModel(Entity): # ---- sniff ---- model_id = props.reference() class Model(TEntity): # ---- sniff ---- other_models_field = props.from_entities(OtherModel, "model_id") ... # ---- sniff ---- ``` ### `props.reference()` This property should be inside models that are virtually used inside another model. See [props.from_entity()](Properties.md/#propsfromentity). **Required Parameters:** _This method has no required parameter (nor optional)._ ## Optional properties Normally when you pass `required` parameter as `False`, the field is optional. but for the sake of type hinting, you have other ways to mark your property as optional. ### `props.optional()` Wrap your property with this and now it's `T | None`, instead of `T`. ```py optional_str = props.optional(props.string()) ``` ### `TProperty.optional()` Or you can simply call `optional()` method of any property. ```py optional_str = props.string().optional() ``` ## `__init__` Method It's super common that we use `__init__` method inside our model, to make things simpler. But when you're going to use it here, you should consider things. 1. USE `__json_init__ = True`. 2. Namings in props definition, inside `__init__` method's parameters and inside the body of `__init__`, SHOULD be the same. 3. Set default value for optional properties. 4. If you're using other parameters for `__init__`, set default value for them too. ```py class Model(TEntity): __json_init__ = True name = props.string() family_name = props.string().optional() def __init__(self, name: str, family_name: str | None = None, other_blah = default): self.name = name self.family_name = family_name # blah ``` _Now it's a good init!_ ### `props.auto_collect()` [decorator] Instead of things we did above, we could simply use `props.auto_collect()` decorator on our `Model`. ```py @props.auto_collect(ignore_params=["other_blah"]) class Model(TEntity): def __init__(self, name: str, family_name: str | None = None, other_blah = default): self.name = name self.family_name = family_name # blah ``` #### Consideration 1. Type hints are required! ( `: str`, `: str | None`, ... ) 2. Use valid types as type hint. 3. Add params that are not properties, inside `ignore_params` of `auto_collect`. 4. Watch for namings just like [above](Properties.md/#init-method). ## FAQ 1. Should i do something especial when i wanna use `__init__` inside my model? **Yes**, see [`__init__` Method](Properties.md/#init-method).