doc/entities.md in power_stencil-0.4.6 vs doc/entities.md in power_stencil-0.4.7

- old
+ new

@@ -23,18 +23,20 @@ - [My first custom entity](#my-first-custom-entity) - [Directives](#directives) - [entity_type](#entity_type) - [auto_named_entity_type](#auto_named_entity_type) - [field](#field) - - [has_one](#has_one) - - [has_many](#has_many) - - [is_array](#is_array) - - [is_hash](#is_hash) - - [not_null](#not_null) - - [not_empty](#not_empty) - - [should_match](#should_match) - - [class_name](#class_name) + - [Integrity constraints](#integrity-constraints) + - [is_array](#is_array) + - [is_hash](#is_hash) + - [not_null](#not_null) + - [not_empty](#not_empty) + - [should_match](#should_match) + - [class_name](#class_name) + - [Relational constraints](#relational-constraints) + - [has_one](#has_one) + - [has_many](#has_many) - [buildable and buildable_by](#buildable-and-buildable_by) - [Module you could include in your entity types](#module-you-could-include-in-your-entity-types) - [Adding functional code](#adding-functional-code) <!-- /TOC --> @@ -610,121 +612,16 @@ :information_source: By default the [base_entity][PowerStencil::SystemEntityDefinitions::ProjectEntity] has only two fields declared: - The `name` field that we already saw and which is mandatory. - The `description` field which is optional, and which is pretty self-explanatory. -### has_one -This property may look familiar to users of [ActiveRecord], it introduces the concept of relationship between entities. +### Integrity constraints -```ruby -class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity - entity_type :custom_entity - has_one :custom_entity, name: :parent -end -``` +#### is_array -```ruby -PowerStencil DSL> e = new_custom_entity name: :test_entity -=> #<MyCustomEntity:47215552142260 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566478203.584915)'> -PowerStencil DSL> p = new_custom_entity name: :foo -=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'> -PowerStencil DSL> e.parent = p -=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'> -PowerStencil DSL> e.fields -=> {:name=>"test_entity", :parent=>#<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'>} -PowerStencil DSL> p.save=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'> -PowerStencil DSL> e.save -=> #<MyCustomEntity:47215552142260 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566478203.584915)'> -PowerStencil DSL> exit -``` - -Which translates at persistence level as: - -```shell -$ power_stencil get custom_entity/test_entity --raw ---- !ruby/object:MyCustomEntity -:name: test_entity -:parent: !psref - type: :custom_entity - name: foo -``` -Here we are referencing an entity of the same type, but of course you can reference any type of entity. Using `has_one` will enforce the type of data you reference. Let's try to mess-up: - -```ruby -PowerStencil DSL> e.parent = :bar -=> :bar -PowerStencil DSL> e.fields -=> {:name=>"test_entity", :parent=>:bar} -PowerStencil DSL> e.valid? -=> false -PowerStencil DSL> e.valid? raise_error: true -UniverseCompiler::Error: Invalid entity '[:custom_entity, "test_entity"]' for fields parent ! -from /opt/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/universe_compiler-0.2.7/lib/universe_compiler/utils/error_propagation.rb:10:in `false_or_raise' -PowerStencil DSL> e.save -UniverseCompiler::Error: Invalid entity '[:custom_entity, "test_entity"]' for fields parent ! -from /opt/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/universe_compiler-0.2.7/lib/universe_compiler/utils/error_propagation.rb:10:in `false_or_raise' -``` -So you see that if we try to set parent with something wrong, the accessor seems to accept, you can even see the `#fields` Hash updated. But as soon as you try to save to entity, or if you use the `#valid?` method, it complains about the type... Cool. - -:information_source: The `name` property of the `has_one` directive is optional. If not present the field will be named from the entity_type referenced instead... - -**:warning: See more advanced features, like reverse methods in the [universe_compiler advanced relations documentation].** - -### has_many - -Once you know the `has_one` directive, you should not be surprised by the `has_many` directive... - -```ruby -class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity - entity_type :custom_entity - - has_many :base_entity, name: :sub_properties -end -``` - -```ruby -PowerStencil DSL> e = new_custom_entity name: :test_entity -=> #<MyCustomEntity:47312117001560 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566482056.789871)'> -PowerStencil DSL> sub_prop1 = new_base_entity name: :prop1 -=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'> -PowerStencil DSL> e.sub_properties << sub_prop1 -=> [#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>] -PowerStencil DSL> sub_prop2 = new_base_entity name: :prop2 -=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'> -PowerStencil DSL> e.sub_properties << sub_prop2 -=> [#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>, - #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>] -PowerStencil DSL> sub_prop1.save -=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'> -PowerStencil DSL> sub_prop2.save -=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'> -PowerStencil DSL> e.save -=> #<MyCustomEntity:47312117001560 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566482056.789871)'> -PowerStencil DSL> exit -``` - -Which translates at persistence level as: - -```shell ---- !ruby/object:MyCustomEntity -:sub_properties: -- !psref - type: :base_entity - name: prop1 -- !psref - type: :base_entity - name: prop2 -:name: test_entity -``` -Nice ! - -**:warning: See more advanced features, like reverse methods in the [universe_compiler advanced relations documentation].** - -### is_array - You can define a field as being an array: ```ruby class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity entity_type :custom_entity @@ -743,11 +640,11 @@ => {:name=>"test_entity", :an_array=>[], :another_array=>[]} ``` :information_source: Please note the two syntaxes are equivalent. -### is_hash +#### is_hash You can define a field as being an array: ```ruby class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity @@ -767,11 +664,11 @@ => {:name=>"test_entity", :a_hash=>{}, :another_hash=>{}} ``` :information_source: Please note the two syntaxes are equivalent. -### not_null +#### not_null I guess you start getting used to what happens: ```ruby class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity @@ -802,11 +699,11 @@ PowerStencil DSL> e.valid? => true ``` Nothing very surprising there. Please note an empty string is not a null value... -### not_empty +#### not_empty This directive will adapt depending on the field type ```ruby class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity @@ -845,11 +742,11 @@ :warning: Please note that neither `has_one` nor `has_many` support the "_condensed_" version of the syntax (like `field` can). You have to specify the directive on a separated line. :information_source: `has_one` does not support `not_empty` but support `not_null`, and the opposite for `has_many`... -### should_match +#### should_match `should_match` will perform a validation of the content regarding a regular expression or a string. It should work on strings or symbols: ```ruby class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity @@ -886,11 +783,11 @@ => true ``` :warning: As you can see there, unless specified as `not_null` or `not_empty`, the `should_match` validation will not be performed ! Pretty normal if you think about it... -### class_name +#### class_name ```ruby class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity entity_type :custom_entity @@ -915,10 +812,123 @@ ``` `class_name` supports actually both a class (like here) or a class name. :warning: Use this one with caution, as it does not test anything regarding inheritance... + +### Relational constraints + +#### has_one + +This property may look familiar to users of [ActiveRecord], it introduces the concept of relationship between entities. + +```ruby +class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity + entity_type :custom_entity + + has_one :custom_entity, name: :parent +end +``` + +```ruby +PowerStencil DSL> e = new_custom_entity name: :test_entity +=> #<MyCustomEntity:47215552142260 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566478203.584915)'> +PowerStencil DSL> p = new_custom_entity name: :foo +=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'> +PowerStencil DSL> e.parent = p +=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'> +PowerStencil DSL> e.fields +=> {:name=>"test_entity", :parent=>#<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'>} +PowerStencil DSL> p.save=> #<MyCustomEntity:47215551934000 composite_key=[:custom_entity, "foo"], @universe='Project entities (1566478203.584915)'> +PowerStencil DSL> e.save +=> #<MyCustomEntity:47215552142260 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566478203.584915)'> +PowerStencil DSL> exit +``` + +Which translates at persistence level as: + +```shell +$ power_stencil get custom_entity/test_entity --raw +--- !ruby/object:MyCustomEntity +:name: test_entity +:parent: !psref + type: :custom_entity + name: foo +``` +Here we are referencing an entity of the same type, but of course you can reference any type of entity. Using `has_one` will enforce the type of data you reference. Let's try to mess-up: + +```ruby +PowerStencil DSL> e.parent = :bar +=> :bar +PowerStencil DSL> e.fields +=> {:name=>"test_entity", :parent=>:bar} +PowerStencil DSL> e.valid? +=> false +PowerStencil DSL> e.valid? raise_error: true +UniverseCompiler::Error: Invalid entity '[:custom_entity, "test_entity"]' for fields parent ! +from /opt/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/universe_compiler-0.2.7/lib/universe_compiler/utils/error_propagation.rb:10:in `false_or_raise' +PowerStencil DSL> e.save +UniverseCompiler::Error: Invalid entity '[:custom_entity, "test_entity"]' for fields parent ! +from /opt/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/universe_compiler-0.2.7/lib/universe_compiler/utils/error_propagation.rb:10:in `false_or_raise' +``` +So you see that if we try to set parent with something wrong, the accessor seems to accept, you can even see the `#fields` Hash updated. But as soon as you try to save to entity, or if you use the `#valid?` method, it complains about the type... Cool. + +:information_source: The `name` property of the `has_one` directive is optional. If not present the field will be named from the entity_type referenced instead... + +**:information_source: See more advanced features, like the very powerful reverse methods in the [`universe_compiler` advanced relations documentation].** + +#### has_many + +Once you know the `has_one` directive, you should not be surprised by the `has_many` directive... + +```ruby +class MyCustomEntity < PowerStencil::SystemEntityDefinitions::ProjectEntity + entity_type :custom_entity + + has_many :base_entity, name: :sub_properties +end +``` + +```ruby +PowerStencil DSL> e = new_custom_entity name: :test_entity +=> #<MyCustomEntity:47312117001560 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566482056.789871)'> +PowerStencil DSL> sub_prop1 = new_base_entity name: :prop1 +=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'> +PowerStencil DSL> e.sub_properties << sub_prop1 +=> [#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>] +PowerStencil DSL> sub_prop2 = new_base_entity name: :prop2 +=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'> +PowerStencil DSL> e.sub_properties << sub_prop2 +=> [#<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'>, + #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'>] +PowerStencil DSL> sub_prop1.save +=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116793880 composite_key=[:base_entity, "prop1"], @universe='Project entities (1566482056.789871)'> +PowerStencil DSL> sub_prop2.save +=> #<PowerStencil::SystemEntityDefinitions::ProjectEntity:47312116175620 composite_key=[:base_entity, "prop2"], @universe='Project entities (1566482056.789871)'> +PowerStencil DSL> e.save +=> #<MyCustomEntity:47312117001560 composite_key=[:custom_entity, "test_entity"], @universe='Project entities (1566482056.789871)'> +PowerStencil DSL> exit +``` + +Which translates at persistence level as: + +```shell +--- !ruby/object:MyCustomEntity +:sub_properties: +- !psref + type: :base_entity + name: prop1 +- !psref + type: :base_entity + name: prop2 +:name: test_entity +``` +Nice ! + +**:information_source: See more advanced features, like the very powerful reverse methods in the [`universe_compiler` advanced relations documentation].** + + ### buildable and buildable_by One of the most important directives ! More information is provided in the [builds] documentation, but basically this defines an `entity_type` as a potential target for the build process. @@ -971,7 +981,7 @@ [Ruby]: https://www.ruby-lang.org "The powerful Ruby language" [Pry]: https://github.com/pry/pry "The awesome Pry console" [ActiveRecord]: https://guides.rubyonrails.org/active_record_basics.html "The ultimate ORM" [Ruby On Rails]: https://rubyonrails.org/ "One of the best Web framework" [universe_compiler]: https://gitlab.com/tools4devops/universe_compiler "The underlying engine to manage entities and compilation !" -[universe_compiler advanced relations documentation]: https://gitlab.com/tools4devops/universe_compiler#advanced-relations "Advanced relational features" +[`universe_compiler` advanced relations documentation]: https://gitlab.com/tools4devops/universe_compiler#advanced-relations "Advanced relational features" [Graphviz]: (https://www.graphviz.org/) "Graph Visualization Software" \ No newline at end of file