You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ofbiz.apache.org by Jacopo Cappellato <ja...@hotwaxsystems.com> on 2017/07/01 08:59:57 UTC

Re: Suggest to improve groovy DSL

Hi Nicolas,

thank you, this is great feedback!
Please see some comments inline:

On Fri, Jun 30, 2017 at 11:33 PM, Nicolas Malin <ni...@nereide.fr>
wrote:

> Hello
>
> I found some idea to improve the groovy DSL during my first try to convert
> mini-lang.
> I don't know if it's possible or logical at this time but I just sharing
> my mind :)
>
> ****
> entity-one : with the minilang is really usefull to call directly a entity
> like that
>     <entity-one entity-name="Product" value-name="product"/>
> currently with groovy
>     GenericValue product = from("Product").where([productId:
> productId).findOne()
> we lose the automapping so I imagine a syntax like that :
>     GenericValue product = from("Product").autoMap(groovyCtx).findOne()
> or
>     GenericValue product = from("Product").findOne(groovyCtx)
> or
>     GenericValue product = from("Product").resolveOne(groovyCtx)
> or something like that
>

We could probably make the existing EntityQuery.where(Map) method more
clever and automatically exclude fields that are not in the entity
definition; after that we could use:

GenericValue product = from("Product").where(groovyCtx).findOne()


>
> Make valid service context :
> in minilang
>     <set-service-fields service-name="createProduct" map="context"
> to-map="createProductMap"/>
> Currently with groovy we need to call the dispatchcontext
>     Map createProductMap = dispatcher.getDispatchContext(
> ).makeValidContext('createProduct', 'IN', parameters)
> My idea would be like that
>     Map createProductMap = prepare service: 'createProduct' //to pool from
> groovyCtx
> or
>     Map createProductMap = prepare service: 'createProduct' with:
> parameters //to pool from parameters
> or
>     Map createProductMap = prepare service: 'createProduct' with:
> parameters mode: 'IN' //to pool from parameters and indicate the mode
>
>
We could probably improve the GroovyBaseScript.runService(...) method to
always prepare a valid context before calling the service; in this way we
would simply call runService passing the context map.


> It's would be the same to prepare a genericValue:
>     GenericValue product = prepare entity: 'Product' with: parameters
>
> Resolve a label
> in minilang
>     <fail-property resource="AccountingUiLabels"
> property="AccountingCreatePaymentPermissionError"/>
> in groovy
>     String message = UtilProperties.getMessage('AccountingErrorUiLabels',
> 'AccountingUpdateRateAmountAlreadyExist', locale)
> My idea
>     String message = message: 'AccountingUpdateRateAmountAlreadyExist',
> from: 'AccountingErrorUiLabels', with: 'messageCtx'
>
>
String message = getLabel withName: 'AccountingUpdateRateAmountAlreadyExist',
from: 'AccountingErrorUiLabels'
that could be also called with:
String message = getLabel 'AccountingUpdateRateAmountAlreadyExist',
'AccountingErrorUiLabels'



> Security control
> in minilang
>     <if-has-permission permission="ACCOUNTING" action="_CREATE"/>
> in groovy
>     if (security.hasPermission("ACCOUNTING_CREATE", userLogin))
> My idea
>     if (has permission: 'ACCOUNTING_CREATE')
>

I love it


Kind regards,

Jacopo

*******
>
> I tried to implement "prepapre" for fun with success below :)
>
> Index: framework/service/src/main/java/org/apache/ofbiz/service/eng
> ine/GroovyBaseScript.groovy
> ===================================================================
> --- framework/service/src/main/java/org/apache/ofbiz/service/engine/GroovyBaseScript.groovy
> (révision 1800195)
> +++ framework/service/src/main/java/org/apache/ofbiz/service/engine/GroovyBaseScript.groovy
> (copie de travail)
> @@ -19,6 +19,8 @@
>  package org.apache.ofbiz.service.engine
>
>  import org.apache.ofbiz.base.util.Debug
> +import org.apache.ofbiz.entity.finder.PrimaryKeyFinder
> +import org.apache.ofbiz.entity.model.ModelEntity
>  import org.apache.ofbiz.entity.util.EntityQuery
>  import org.apache.ofbiz.service.ServiceUtil
>  import org.apache.ofbiz.service.ExecutionServiceException
> @@ -47,6 +49,15 @@
>          return runService((String)args.get('service'),
> (Map)args.get('with', new HashMap()))
>      }
>
> +    Map prepare(Map args) throws ExecutionServiceException {
> +        if ((String)args.get('service')) {
> +            return result = binding.getVariable('dispatche
> r').getDispatchContext().makeValidContext((String) args.get('service'),
> "IN", (Map) args.get('with', binding.getVariable('parameters')))
> +        }
> +        if ((String)args.get('entity')) {
> +            return result = binding.getVariable('delegator').makeValidValue((String)
> args.get('entity'), (Map) args.get('with', binding.getVariable('parameter
> s')))
> +        }
> +    }
> +
>      Map makeValue(String entityName) throws ExecutionServiceException {
>          return result = binding.getVariable('delegator
> ').makeValue(entityName)
>      }
> @@ -63,6 +74,13 @@
>          return EntityQuery.use(binding.getVariable('delegator')).select(
> fields)
>      }
>
> +    Map fromOneAuto(def entity) {
> +        Debug.logError( ' ' + binding.getVariables(), '######')
> +        return result = PrimaryKeyFinder.runFind(bindi
> ng.getVariable('delegator').getModelEntity(entity),
> +                binding.getVariables(), binding.getVariable('delegator'),
> true, true, null, null)
> +
> +    }
> +
>      def success(String message) {
>          // TODO: implement some clever i18n mechanism based on the
> userLogin and locale in the binding
>          if (this.binding.hasVariable('request')) {
> Index: applications/accounting/groovyScripts/payment/FindInvoicesBy
> DueDate.groovy
> ===================================================================
> --- applications/accounting/groovyScripts/payment/FindInvoicesByDueDate.groovy
> (révision 1800195)
> +++ applications/accounting/groovyScripts/payment/FindInvoicesByDueDate.groovy
> (copie de travail)
> @@ -20,7 +20,7 @@
>  context.invoicePaymentInfoList = []
>
>  if (parameters.invoiceTypeId) { // it's not the initialisation but a real
> search request
> -    serviceCtx = dispatcher.getDispatchContext(
> ).makeValidContext("getInvoicePaymentInfoListByDueDateOffset", "IN",
> parameters)
> +    serviceCtx = prepare service: 'getInvoicePaymentInfoListByDu
> eDateOffset'
>      result = runService("getInvoicePaymentInfoListByDueDateOffset",
> serviceCtx)
>      context.invoicePaymentInfoList = result.invoicePaymentInfoList
>  }
> Index: applications/accounting/groovyScripts/rate/RateServices.groovy
> ===================================================================
> --- applications/accounting/groovyScripts/rate/RateServices.groovy
> (révision 1800245)
> +++ applications/accounting/groovyScripts/rate/RateServices.groovy (copie
> de travail)
> @@ -31,7 +31,7 @@
>   * Service to create a rate amount value, if a existing value is present
> expire it before
>   */
>  def updateRateAmount() {
> -    GenericValue newEntity = delegator.makeValidValue('RateAmount',
> parameters)
> +    GenericValue newEntity = prepare entity: 'RateAmount'
>      if (!newEntity.rateCurrencyUomId) {
>          newEntity.rateCurrencyUomId = UtilProperties.getPropertyValue('general.properties',
> 'currency.uom.id.default')
>      }
> @@ -65,11 +65,11 @@
>   * Service to expire a rate amount value
>   */
>  def expireRateAmount() {
> -    GenericValue lookedUpValue = delegator.makeValidValue('RateAmount',
> parameters)
> +    GenericValue lookedUpValue = prepare entity: 'RateAmount'
>      if (!lookedUpValue.rateCurrencyUomId) {
>          lookedUpValue.rateCurrencyUomId = UtilProperties.getPropertyValue('general.properties',
> 'currency.uom.id.default')
>      }
> -    lookedUpValue = from('RateAmount').where(looke
> dUpValue.getFields(lookedUpValue.getModelEntity().
> getPkFieldNames())).queryOne()
> +    lookedUpValue = fromOneAuto('RateAmount')
>      if (lookedUpValue) {
>          Timestamp previousDay = UtilDateTime.adjustTimestamp(UtilDateTime.nowTimestamp(),
> 5, -1)
>          lookedUpValue.thruDate = UtilDateTime.getDayEnd(previousDay)
> @@ -93,7 +93,7 @@
>          GenericValue partyRate = EntityUtil.getFirst(partyRates)
>          partyRate.thruDate = UtilDateTime.nowTimestamp()
>      }
> -    GenericValue newEntity = delegator.makeValidValue('PartyRate',
> parameters)
> +    GenericValue newEntity = prepare entity: 'PartyRate'
>      if (!newEntity.fromDate) newEntity.fromDate =
> UtilDateTime.nowTimestamp()
>      newEntity.create()
>
> Index: framework/base/src/main/java/org/apache/ofbiz/base/OfbizDslD
> escriptorForIntelliJ.gdsl
> ===================================================================
> --- framework/base/src/main/java/org/apache/ofbiz/base/OfbizDslDescriptorForIntelliJ.gdsl
> (révision 1800195)
> +++ framework/base/src/main/java/org/apache/ofbiz/base/OfbizDslDescriptorForIntelliJ.gdsl
> (copie de travail)
> @@ -29,6 +29,7 @@
>
>      method name: 'runService', type: 'java.util.Map', params:
> [serviceName: 'String', inputMap: 'java.util.Map']
>      method name: 'run', type: 'java.util.Map', params: [args:
> 'java.util.Map']
> +    method name: 'prepare', type: 'java.util.Map', params: [args:
> 'java.util.Map']
>      method name: 'makeValue', type: 'java.util.Map', params: [entityName:
> 'String']
>      method name: 'select', type: 'org.apache.ofbiz.entity.util.EntityQuery',
> params: [entity: 'java.util.Set']
>      method name: 'select', type: 'org.apache.ofbiz.entity.util.EntityQuery',
> params: [entity: 'String...']
> --
> logoNrd <https://nereide.fr/>
>         Nicolas Malin
> The apache way <http://theapacheway.com/> : *Openness* Technical
> decisions are made publicly
> information@nereide.fr
> 8 rue des Déportés 37000 TOURS, 02 47 50 30 54
>
> Apache OFBiz <http://ofbiz.apache.org/>|The Apache Way <
> http://theapacheway.com/>|ofbiz-fr <http://www.ofbiz-fr.org/>|réseau LE <
> http://www.libre-entreprise.org/>
>

Re: Suggest to improve groovy DSL -> entity-one

Posted by Jacques Le Roux <ja...@les7arts.com>.
Good job indeed Nicolas and Jacopo, with also OFBIZ-9523

Thanks

Jacques

PS: Now we just need to change Groovy files with the new syntactic sugars ;)


Le 21/07/2017 à 20:39, Swapnil Mane a écrit :
> Liked this proposed improvement of queryOne() for Groovy.
>
> Thank you Nicolas and Jacopo!
>
>
> - Best Regards,
> Swapnil M Mane
>
> On Fri, Jul 21, 2017 at 11:15 PM, Nicolas Malin <ni...@nereide.fr>
> wrote:
>
>> Hi Jacopo,
>>
>> I implement your suggest on the issue https://issues.apache.org/jira
>> /browse/OFBIZ-9447.
>>
>> I'm available for any comment :)
>>
>> Nicolas
>>
>>
>>
>> Le 03/07/2017 à 23:27, Nicolas Malin a écrit :
>>
>>> Hi
>>>
>>>> Most entity definitions have about 1-4 fields in the primary key: as a
>>>> consequence the above API would require to maintain a reference to the
>>>> map
>>>> and then fetch from the entity definition the field names that compose
>>>> the
>>>> primary key and perform 1-4 map lookups. This should not impact the
>>>> performance in a measurable way. However, only tests will tell!
>>>> Some design details: the where(Map) method should only save a reference
>>>> to
>>>> the map; the actual map lookup with primary key fields should be
>>>> performed
>>>> later by the findOne() method.
>>>>
>>> Hmmm, maybe a subtely escape me because the where(Map) function call an
>>> EntityCondition to prepare the whereEntityCondition.
>>> So I have two solutions :
>>>   * not follow your suggest and prepare the Map on the fly for the
>>> EntityCondition (it was my first idea)
>>>   * add a new variable EntityQuery.searchContext to store the link as you
>>> suggest and change all query function to create the whereentityCondition or
>>> parse if it's the queryOne.
>>>
>>> I implemented with success the first, now I will try to implement the
>>> second and I will present the result
>>> Cheers,
>>> Nicolas
>>>
>>> Regards,
>>>> Jacopo
>>>>
>>>>
>>>


Re: Suggest to improve groovy DSL -> entity-one

Posted by Swapnil Mane <sw...@hotwaxsystems.com>.
Liked this proposed improvement of queryOne() for Groovy.

Thank you Nicolas and Jacopo!


- Best Regards,
Swapnil M Mane

On Fri, Jul 21, 2017 at 11:15 PM, Nicolas Malin <ni...@nereide.fr>
wrote:

> Hi Jacopo,
>
> I implement your suggest on the issue https://issues.apache.org/jira
> /browse/OFBIZ-9447.
>
> I'm available for any comment :)
>
> Nicolas
>
>
>
> Le 03/07/2017 à 23:27, Nicolas Malin a écrit :
>
>> Hi
>>
>>> Most entity definitions have about 1-4 fields in the primary key: as a
>>> consequence the above API would require to maintain a reference to the
>>> map
>>> and then fetch from the entity definition the field names that compose
>>> the
>>> primary key and perform 1-4 map lookups. This should not impact the
>>> performance in a measurable way. However, only tests will tell!
>>> Some design details: the where(Map) method should only save a reference
>>> to
>>> the map; the actual map lookup with primary key fields should be
>>> performed
>>> later by the findOne() method.
>>>
>> Hmmm, maybe a subtely escape me because the where(Map) function call an
>> EntityCondition to prepare the whereEntityCondition.
>> So I have two solutions :
>>  * not follow your suggest and prepare the Map on the fly for the
>> EntityCondition (it was my first idea)
>>  * add a new variable EntityQuery.searchContext to store the link as you
>> suggest and change all query function to create the whereentityCondition or
>> parse if it's the queryOne.
>>
>> I implemented with success the first, now I will try to implement the
>> second and I will present the result
>> Cheers,
>> Nicolas
>>
>> Regards,
>>>
>>> Jacopo
>>>
>>>
>>
>>
>

Re: Suggest to improve groovy DSL -> entity-one

Posted by Nicolas Malin <ni...@nereide.fr>.
Hi Jacopo,

I implement your suggest on the issue 
https://issues.apache.org/jira/browse/OFBIZ-9447.

I'm available for any comment :)

Nicolas


Le 03/07/2017 à 23:27, Nicolas Malin a écrit :
> Hi
>> Most entity definitions have about 1-4 fields in the primary key: as a
>> consequence the above API would require to maintain a reference to 
>> the map
>> and then fetch from the entity definition the field names that 
>> compose the
>> primary key and perform 1-4 map lookups. This should not impact the
>> performance in a measurable way. However, only tests will tell!
>> Some design details: the where(Map) method should only save a 
>> reference to
>> the map; the actual map lookup with primary key fields should be 
>> performed
>> later by the findOne() method.
> Hmmm, maybe a subtely escape me because the where(Map) function call 
> an EntityCondition to prepare the whereEntityCondition.
> So I have two solutions :
>  * not follow your suggest and prepare the Map on the fly for the 
> EntityCondition (it was my first idea)
>  * add a new variable EntityQuery.searchContext to store the link as 
> you suggest and change all query function to create the 
> whereentityCondition or parse if it's the queryOne.
>
> I implemented with success the first, now I will try to implement the 
> second and I will present the result
> Cheers,
> Nicolas
>
>> Regards,
>>
>> Jacopo
>>
>
>


Re: Suggest to improve groovy DSL -> entity-one

Posted by Nicolas Malin <ni...@nereide.fr>.
Hi
> Most entity definitions have about 1-4 fields in the primary key: as a
> consequence the above API would require to maintain a reference to the map
> and then fetch from the entity definition the field names that compose the
> primary key and perform 1-4 map lookups. This should not impact the
> performance in a measurable way. However, only tests will tell!
> Some design details: the where(Map) method should only save a reference to
> the map; the actual map lookup with primary key fields should be performed
> later by the findOne() method.
Hmmm, maybe a subtely escape me because the where(Map) function call an 
EntityCondition to prepare the whereEntityCondition.
So I have two solutions :
  * not follow your suggest and prepare the Map on the fly for the 
EntityCondition (it was my first idea)
  * add a new variable EntityQuery.searchContext to store the link as 
you suggest and change all query function to create the 
whereentityCondition or parse if it's the queryOne.

I implemented with success the first, now I will try to implement the 
second and I will present the result
Cheers,
Nicolas

> Regards,
>
> Jacopo
>


Re: Suggest to improve groovy DSL -> entity-one

Posted by Jacopo Cappellato <ja...@hotwaxsystems.com>.
Hi Nicolas,

On Sat, Jul 1, 2017 at 9:57 PM, Nicolas Malin <ni...@nereide.fr>
wrote:

> Hi Jacopo,
>
> I was sure that this thread will pick your interest  ;)
>

Indeed it did :-)


> Le 01/07/2017 à 10:59, Jacopo Cappellato a écrit :
>
>> ...
>> GenericValue product = from("Product").where(groovyCtx).findOne()
>>
> Yeah it's a good idea to keep the same syntax with the EntityQuery but you
> are not afraid to slow down the global function ?
> I will test it to ensure this is a good way ... or not.


Most entity definitions have about 1-4 fields in the primary key: as a
consequence the above API would require to maintain a reference to the map
and then fetch from the entity definition the field names that compose the
primary key and perform 1-4 map lookups. This should not impact the
performance in a measurable way. However, only tests will tell!
Some design details: the where(Map) method should only save a reference to
the map; the actual map lookup with primary key fields should be performed
later by the findOne() method.

Regards,

Jacopo

Re: Suggest to improve groovy DSL -> entity-one

Posted by Nicolas Malin <ni...@nereide.fr>.
Hi Jacopo,

I was sure that this thread will pick your interest  ;)

I separate the thread for each suggest

in line

Le 01/07/2017 à 10:59, Jacopo Cappellato a écrit :
> Hi Nicolas,
> [...]
> entity-one : with the minilang is really usefull to call directly a entity
> like that
>      <entity-one entity-name="Product" value-name="product"/>
> currently with groovy
>      GenericValue product = from("Product").where([productId:
> productId).findOne()
> We could probably make the existing EntityQuery.where(Map) method more
> clever and automatically exclude fields that are not in the entity
> definition; after that we could use:
>
> GenericValue product = from("Product").where(groovyCtx).findOne()
Yeah it's a good idea to keep the same syntax with the EntityQuery but 
you are not afraid to slow down the global function ?
I will test it to ensure this is a good way ... or not.

Nicolas

Re: Suggest to improve groovy DSL

Posted by Nicolas Malin <ni...@nereide.fr>.
Jacopo, I open the issue 
https://issues.apache.org/jira/browse/OFBIZ-9523 with a patch related to 
you suggest

Regards,

Nicolas


Le 01/07/2017 à 10:59, Jacopo Cappellato a écrit :
>> Make valid service context :
>> in minilang
>>      <set-service-fields service-name="createProduct" map="context"
>> to-map="createProductMap"/>
>> Currently with groovy we need to call the dispatchcontext
>>      Map createProductMap = dispatcher.getDispatchContext(
>> ).makeValidContext('createProduct', 'IN', parameters)
>> My idea would be like that
>>      Map createProductMap = prepare service: 'createProduct' //to pool from
>> groovyCtx
>> or
>>      Map createProductMap = prepare service: 'createProduct' with:
>> parameters //to pool from parameters
>> or
>>      Map createProductMap = prepare service: 'createProduct' with:
>> parameters mode: 'IN' //to pool from parameters and indicate the mode
>>
>>
> We could probably improve the GroovyBaseScript.runService(...) method to
> always prepare a valid context before calling the service; in this way we
> would simply call runService passing the context map.
>
>