finos / legend-studio

Legend Studio
https://legend.finos.org
Apache License 2.0
89 stars 114 forks source link

Bug: Unable to open query builder form editor for multiply `Boolean` expression of an explosion property. #648

Open MauricioUyaguari opened 3 years ago

MauricioUyaguari commented 3 years ago

Similar issues

How are you using Studio?

Legend Query

Current and expected behavior

When editing a query lambda on an explosion property with multiple booleans, the rendering of the query builder will fail with Can't display query in form mode due to: Can't process filter expression: no compatible filter operator processer available from plugins. We should be able to process the given lambda. If required we may need to enable derived filter expression support

Steps to reproduce

Model data

###Relational
Database store::MyDatabase
(
  Schema MySchema
  (
    Table PersonTable1
    (
      Brand VARCHAR(128) NOT NULL,
      NAME VARCHAR(128),
      LASTNAME VARCHAR(128),
      Nick_Name VARCHAR(128) NOT NULL,
      Hq1_State VARCHAR(128),
      Hq1_Street VARCHAR(128),
      Hq2_State VARCHAR(128),
      Hq2_Street VARCHAR(128),
      Value DOUBLE,
      Locations INTEGER,
      Found_Date DATE PRIMARY KEY,
      ID VARCHAR(128) PRIMARY KEY
    )
    Table PersonTable2
    (
      Brand VARCHAR(128) NOT NULL,
      NAME VARCHAR(128),
      LASTNAME VARCHAR(128),
      Nick_Name VARCHAR(128) NOT NULL,
      Hq1_State VARCHAR(128),
      Hq1_Street VARCHAR(128),
      Hq2_State VARCHAR(128),
      Hq2_Street VARCHAR(128),
      Value DOUBLE,
      Locations INTEGER,
      Found_Date DATE PRIMARY KEY,
      ID VARCHAR(128) PRIMARY KEY
    )
  )
)

###Pure
Class model::Firm
{
  hq1: model::HQ[0..1];
  hq2: model::HQ[0..1];
  brand: String[1];
  value: Float[1];
  date: Date[1];
  locations: Integer[1];
}

Class model::HQ
{
  state: String[1];
  street: String[1];
}

Class model::Person
{
  name: String[1];
  lastName: String[1];
  nickName: String[1];
  firm: model::Firm[*];
}

###Mapping
Mapping mapping::MyMapping
(
  *model::Person: Operation
  {
    meta::pure::router::operations::union_OperationSetImplementation_1__SetImplementation_MANY_(person1,person2)
  }
  model::Person[person1]: Relational
  {
    ~primaryKey
    (
      [store::MyDatabase]MySchema.PersonTable1.Found_Date,
      [store::MyDatabase]MySchema.PersonTable1.ID
    )
    ~mainTable [store::MyDatabase]MySchema.PersonTable1
    name: [store::MyDatabase]MySchema.PersonTable1.NAME,
    lastName: [store::MyDatabase]MySchema.PersonTable1.LASTNAME,
    nickName: [store::MyDatabase]MySchema.PersonTable1.Nick_Name,
    firm
    (
      hq1
      (
        state: [store::MyDatabase]MySchema.PersonTable1.Hq1_State,
        street: [store::MyDatabase]MySchema.PersonTable1.Hq1_Street
      ),
      hq2
      (
        state: [store::MyDatabase]MySchema.PersonTable1.Hq2_State,
        street: [store::MyDatabase]MySchema.PersonTable1.Hq2_Street
      ),
      brand: [store::MyDatabase]MySchema.PersonTable1.Brand,
      locations: [store::MyDatabase]MySchema.PersonTable1.Locations,
      value: [store::MyDatabase]MySchema.PersonTable1.Value,
      date: [store::MyDatabase]MySchema.PersonTable1.Found_Date
    )
  }
  model::Person[person2]: Relational
  {
    ~primaryKey
    (
      [store::MyDatabase]MySchema.PersonTable2.Found_Date,
      [store::MyDatabase]MySchema.PersonTable2.ID
    )
    ~mainTable [store::MyDatabase]MySchema.PersonTable2
    name: [store::MyDatabase]MySchema.PersonTable2.NAME,
    lastName: [store::MyDatabase]MySchema.PersonTable2.LASTNAME,
    nickName: [store::MyDatabase]MySchema.PersonTable2.Nick_Name,
    firm
    (
      hq1
      (
        state: [store::MyDatabase]MySchema.PersonTable2.Hq1_State,
        street: [store::MyDatabase]MySchema.PersonTable2.Hq1_Street
      ),
      hq2
      (
        state: [store::MyDatabase]MySchema.PersonTable2.Hq2_State,
        street: [store::MyDatabase]MySchema.PersonTable2.Hq2_Street
      ),
      brand: [store::MyDatabase]MySchema.PersonTable2.Brand,
      locations: [store::MyDatabase]MySchema.PersonTable2.Locations,
      value: [store::MyDatabase]MySchema.PersonTable2.Value,
      date: [store::MyDatabase]MySchema.PersonTable2.Found_Date
    )
  }
)

Environment

Windows

Possible solution and workaround

Equivalent query grammar will work.

{date: Date[1],nickNames: String[*],brands: String[*]|model::Person.all()->filter(
  x|$x.firm->exists(
    x_1|$x_1.brand->in(
      $brands
    )
  ) &&
    ($x.firm->exists(
    x_1|$x_1.date ==
      $date
  ) &&
    $x.nickName->in(
    $nickNames
  ))
)->project(
  [
    x|$x.name
  ],
  ['name']
)}

Contribution

MauricioUyaguari commented 3 years ago

Main issue is query builder is not understanding multiple grouped expression within the exists. Query Builder throws an error for the below as its expecting a single expression within the exists

$x.firm->exists(
    x_1|$x_1.brand->in(
      $brands
    ) &&
      ($x_1.date ==
      $date)
  ) 

It does not throw for the same logical expression below which separates the below into 2 exist expressions.

$x.firm->exists(
    x_1|$x_1.brand->in(
      $brands
    )
  ) &&
    ($x.firm->exists(
    x_1|$x_1.date ==
      $date
  ) 

Thoughts on solution

Solution could be both the implementation of 627 and the flatten on this expression. @akphi thoughts???