diff --git a/CHANGELOG.md b/CHANGELOG.md
index 09aa1b2604d414a9b5c510d9292f539e48b98fcc..3907b4e320916caa7abd5d900dbb882215cfa1fa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,9 +20,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * Wrong serialization of date time values in the GRPC-API (resulting in
   org.caosdb.server.datatime@12347abcd or similar).
 * Missing serialization of file descriptors in the GRPC-API during retrievals.
+* [caosdb-server#131](https://gitlab.com/caosdb/caosdb-server/-/issues/131)
+  Query: AND does not work with sub-properties
 
 ### Security
 
+
 ## [v0.7.1] - 2021-12-13
 (Timm Fitschen)
 
diff --git a/README_SETUP.md b/README_SETUP.md
index 5065e3383c4ac2f2d549bfedb15687d0b4124ec0..d46722d26458757a53f081dd1ce9af3db2688283 100644
--- a/README_SETUP.md
+++ b/README_SETUP.md
@@ -58,12 +58,14 @@ libpam0g-dev`. Then try again.
 After a fresh clone of the repository, this is what you need to setup the
 server:
 
-1. Compile the server with `make compile`. This may take a while and there
+1. Install the `proto` submodule (and submodules for those extensions you want, see above):
+   `git submodule update --init caosdb-proto`
+2. Compile the server with `make compile`. This may take a while and there
    needs to be an internet connection as packages are downloaded to be
    integrated in the java file.
    1. It is recommended to run the unit tests with `make test`. It may take a
       while.
-2. Create an SSL certificate somewhere with a `Java Key Store` file.  For
+3. Create an SSL certificate somewhere with a `Java Key Store` file.  For
    self-signed certificates (not recommended for production use) you can do:
    - `mkdir certificates; cd certificates`
    - `keytool -genkey -keyalg RSA -alias selfsigned -keystore caosdb.jks -validity 375 -keysize 2048 -ext san=dns:localhost`
@@ -77,11 +79,11 @@ server:
    Alternatively, you can create a keystore from certificate files that you already have:
    - `openssl pkcs12 -export -inkey privkey.pem -in fullchain.pem -out all-certs.pkcs12`
    - `keytool -importkeystore -srckeystore all-certs.pkcs12 -srcstoretype PKCS12  -deststoretype pkcs12 -destkeystore caosdb.jks`
-3. Install/configure the MySQL back-end: see the `README_SETUP.md` of the
+4. Install/configure the MySQL back-end: see the `README_SETUP.md` of the
    `caosdb-mysqlbackend` repository
-4. Create an authtoken config (e.g. copy `conf/core/authtoken.example.yaml` to
+5. Create an authtoken config (e.g. copy `conf/core/authtoken.example.yaml` to
    `conf/ext/authtoken.yml` and change it)
-5. Copy `conf/core/server.conf` to `conf/ext/server.conf` and change it
+6. Copy `conf/core/server.conf` to `conf/ext/server.conf` and change it
    appropriately:
     * Setup for MySQL back-end:
       specify the fields `MYSQL_USER_NAME`, `MYSQL_USER_PASSWORD`,
@@ -94,7 +96,7 @@ server:
       `CERTIFICATES_KEY_STORE_PATH`, and `CERTIFICATES_KEY_STORE_PASSWORD`.
       Make sure that the conf file is not readable by other users because the
       certificate passwords are stored in plaintext.
-    - Set the path to the authtoken config (see step 4)
+    * Set the path to the authtoken config (see step 4)
     * Set the file system paths:
       - `FILE_SYSTEM_ROOT`: The root for all the files managed by CaosDB.
       - `DROP_OFF_BOX`: Files can be put here for insertion into CaosDB.
@@ -112,8 +114,8 @@ server:
       - `INSERT_FILES_IN_DIR_ALLOWED_DIRS`: add mounted filesystems here that
         shall be accessible by CaosDB
     * Maybe set another `SESSION_TIMEOUT_MS`.
-    * See also [CONFIGURATION.rst](src/doc/administration/configuration.rst)
-6. Copy `conf/core/usersources.ini.template` to `conf/ext/usersources.ini`.
+     * See also [CONFIGURATION.rst](src/doc/administration/configuration.rst)
+7. Copy `conf/core/usersources.ini.template` to `conf/ext/usersources.ini`.
     * You can skip this if you do not want to use an external authentication. 
       Local users (CaosDB realm) are always available.
     * Define the users/groups who you want to include/exclude.
@@ -128,7 +130,7 @@ server:
       Especially that there are no `properties` (aka `keys`) without a
       `value`. An emtpy value can be represented by `""`. Comments are
       everything from `#` or `;` to the end of the line.
-7. Possibly install the PAM caller in `misc/pam_authentication/` if you have 
+8. Possibly install the PAM caller in `misc/pam_authentication/` if you have
    not do so already. See above.
    
 Done!
diff --git a/src/doc/index.rst b/src/doc/index.rst
index 4f63fe07f37a4432a442040ff2f614f01c959472..b5ce9f3235277b613b357dca5dfc3334d80aeb3f 100644
--- a/src/doc/index.rst
+++ b/src/doc/index.rst
@@ -10,6 +10,7 @@ Welcome to caosdb-server's documentation!
 
    Getting started <README_SETUP>
    Concepts <concepts>
+   tutorials
    Query Language <CaosDB-Query-Language>
    administration
    Development <development/devel>
diff --git a/src/doc/tutorials.rst b/src/doc/tutorials.rst
new file mode 100644
index 0000000000000000000000000000000000000000..27aacfb3eb9a4f04ab261b12f904e652c4daf3d3
--- /dev/null
+++ b/src/doc/tutorials.rst
@@ -0,0 +1,10 @@
+Tutorials
+==============
+
+.. toctree::
+   :maxdepth: 1
+   :glob:
+
+   tutorials/*
+
+
diff --git a/src/doc/tutorials/setup_state_model.py b/src/doc/tutorials/setup_state_model.py
new file mode 100755
index 0000000000000000000000000000000000000000..0a1a7daa3b14d7c3e7a5b8eac093857bddfad330
--- /dev/null
+++ b/src/doc/tutorials/setup_state_model.py
@@ -0,0 +1,379 @@
+#!/usr/bin/env python3
+# encoding: utf-8
+#
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2021 Indiscale GmbH <info@indiscale.com>
+# Copyright (C) 2021 Henrik tom Wörden <h.tomwoerden@indiscale.com>
+# Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+"""
+This is a utility script to setup a publication process in LinkAhead using
+states.
+
+If you start from scratch you should perform the following actions in that
+order:
+
+1. setup_roles
+2. setup_state_data_model
+4. setup_model_publication_cycle
+"""
+from argparse import ArgumentParser, RawDescriptionHelpFormatter
+
+import caosdb as db
+from caosdb.common.administration import generate_password
+
+
+def teardown(args):
+    """fully clears the database"""
+
+    if "yes" != input(
+        "Are you really sure that you want to delete ALL "
+        "ENTITIES in LinkAhead? [yes/No]"
+    ):
+
+        print("Nothing done.")
+
+        return
+    d = db.execute_query("FIND ENTITY WITH ID > 99")
+
+    if len(d) > 0:
+        d.delete(flags={"forceFinalState": "true"})
+
+
+def soft_teardown(args):
+    """ allows to remove state data only """
+    recs = db.execute_query("FIND Entity WITH State")
+
+    for rec in recs:
+        rec.state = None
+    recs.update(flags={"forceFinalState": "true"})
+    db.execute_query("FIND StateModel").delete()
+    db.execute_query("FIND Transition").delete()
+    db.execute_query("FIND State").delete()
+    db.execute_query(
+        "FIND Property WITH name=from or name=to or name=initial or name=final or name=color").delete()
+
+
+def setup_user(args):
+    """Creates a user with given username and adds the given role.
+
+    If the user exists, it is deleted first. A random password is generated
+    and printed in clear text in the console output.
+
+    """
+
+    username, role = args.username, args.role
+    try:
+        db.administration._delete_user(name=username)
+    except Exception:
+        pass
+
+    password = generate_password(10)
+    print("new password for {}:\n{}".format(username, password))
+    db.administration._insert_user(
+        name=username, password=password, status="ACTIVE")
+    db.administration._set_roles(username=username, roles=[role])
+
+
+def remove_user(args):
+    """deletes the given user"""
+    db.administration._delete_user(name=args.username)
+
+
+def setup_role_permissions():
+    """
+    Adds the appropriate permissions to the 'normal' and 'publisher' role.
+
+    The permissions are such that they suit the publication life cycle.
+    """
+    db.administration._set_permissions(
+        role="normal",
+        permission_rules=[
+            db.administration.PermissionRule("Grant", "TRANSACTION:*"),
+            db.administration.PermissionRule(
+                "Grant", "ACM:USER:UPDATE_PASSWORD:?REALM?:?USERNAME?"
+            ),
+            db.administration.PermissionRule("Grant", "STATE:TRANSITION:Edit"),
+            db.administration.PermissionRule("Grant", "UPDATE:PROPERTY:ADD"),
+            db.administration.PermissionRule(
+                "Grant", "UPDATE:PROPERTY:REMOVE"),
+            db.administration.PermissionRule(
+                "Grant", "STATE:TRANSITION:Start Review"),
+            db.administration.PermissionRule(
+                "Grant", "STATE:ASSIGN:Publish Life-cycle"
+            ),
+        ],
+    )
+
+    db.administration._set_permissions(
+        role="publisher",
+        permission_rules=[
+            db.administration.PermissionRule(
+                "Grant", "ACM:USER:UPDATE_PASSWORD:?REALM?:?USERNAME?"
+            ),
+            db.administration.PermissionRule("Grant", "TRANSACTION:*"),
+            db.administration.PermissionRule("Grant", "UPDATE:PROPERTY:ADD"),
+            db.administration.PermissionRule(
+                "Grant", "UPDATE:PROPERTY:REMOVE"),
+            db.administration.PermissionRule("Grant", "STATE:*"),
+        ],
+    )
+
+
+def setup_roles(args):
+    """Creates 'publisher' and 'normla' roles and assigns appropriate
+    permissions
+
+    If those roles exist they are deleted first.
+    """
+
+    for role in ["publisher", "normal"]:
+        try:
+            db.administration._delete_role(name=role)
+        except Exception:
+            print("Could not delete role {}".format(role))
+
+    for role in ["publisher", "normal"]:
+        db.administration._insert_role(name=role, description="")
+
+    setup_role_permissions()
+
+
+def setup_state_data_model(args):
+    """Creates the data model for using states
+
+    RecordTypes: State, StateModel, Transition
+    Properties: from, to, initial, final, color
+    """
+    cont = db.Container().extend(
+        [
+            db.RecordType("State"),
+            db.RecordType("StateModel"),
+            db.RecordType("Transition"),
+            db.Property(name="from", datatype="State"),
+            db.Property(name="to", datatype="State"),
+            db.Property(name="initial", datatype="State"),
+            db.Property(name="final", datatype="State"),
+            db.Property(name="color", datatype=db.TEXT),
+        ]
+    )
+    cont.insert()
+
+
+def setup_model_publication_cycle(args):
+    """Creates States and Transitions for the Publication Life Cycle"""
+    unpublished_acl = db.ACL()
+    unpublished_acl.grant(role="publisher", permission="*")
+    unpublished_acl.grant(role="normal", permission="UPDATE:*")
+    unpublished_acl.grant(role="normal", permission="RETRIEVE:ENTITY")
+    unpublished_acl = db.State.create_state_acl(unpublished_acl)
+
+    unpublished_state = (
+        db.Record(
+            "Unpublished",
+            description="Unpublished entries are only visible to the team "
+            "and may be edited by any team member.",
+        )
+        .add_parent("State")
+        .add_property("color", "#5bc0de")
+    )
+    unpublished_state.acl = unpublished_acl
+    unpublished_state.insert()
+
+    review_acl = db.ACL()
+    review_acl.grant(role="publisher", permission="*")
+    review_acl.grant(role="normal", permission="RETRIEVE:ENTITY")
+
+    review_state = (
+        db.Record(
+            "Under Review",
+            description="Entries under review are not publicly available yet, "
+            "but they can only be edited by the members of the publisher "
+            "group.",
+        )
+        .add_parent("State")
+        .add_property("color", "#FFCC33")
+    )
+    review_state.acl = db.State.create_state_acl(review_acl)
+    review_state.insert()
+
+    published_acl = db.ACL()
+    published_acl.grant(role="guest", permission="RETRIEVE:ENTITY")
+
+    published_state = (
+        db.Record(
+            "Published",
+            description="Published entries are publicly available and "
+            "cannot be edited unless they are unpublished again.",
+        )
+        .add_parent("State")
+        .add_property("color", "#333333")
+    )
+    published_state.acl = db.State.create_state_acl(published_acl)
+    published_state.insert()
+
+    # 1->2
+    (
+        db.Record(
+            "Start Review",
+            description="This transitions denies the permissions to edit an "
+            "entry for anyone but the members of the publisher group. "
+            "However, the entry is not yet publicly available.",
+        )
+        .add_parent("Transition")
+        .add_property("from", "unpublished")
+        .add_property("to", "under review")
+        .add_property("color", "#FFCC33")
+        .insert()
+    )
+
+    # 2->3
+    (
+        db.Record(
+            "Publish",
+            description="Published entries are visible for the public and "
+            "cannot be changed unless they are unpublished again. Only members"
+            " of the publisher group can publish or unpublish entries.",
+        )
+        .add_parent("Transition")
+        .add_property("from", "under review")
+        .add_property("to", "published")
+        .add_property("color", "red")
+        .insert()
+    )
+
+    # 3->1
+    (
+        db.Record(
+            "Unpublish",
+            description="Unpublish this entry to hide it from "
+            "the public. Unpublished entries can be edited by any team "
+            "member.",
+        )
+        .add_parent("Transition")
+        .add_property("from", "published")
+        .add_property("to", "unpublished")
+        .insert()
+    )
+
+    # 2->1
+    (
+        db.Record(
+            "Reject",
+            description="Reject the publishing of this entity.  Afterwards, "
+            "the entity is editable for any team member again.",
+        )
+        .add_parent("Transition")
+        .add_property("from", "under review")
+        .add_property("to", "unpublished")
+        .insert()
+    )
+
+    # 1->1
+    (
+        db.Record(
+            "Edit",
+            description="Edit this entity. The changes are not publicly "
+            "available until this entity will have been reviewed and "
+            "published.",
+        )
+        .add_parent(
+            "Transition",
+        )
+        .add_property("from", "unpublished")
+        .add_property("to", "unpublished")
+        .insert()
+    )
+
+    (
+        db.Record(
+            "Publish Life-cycle",
+            description="The publish life-cycle is a quality assurance tool. "
+            "Database entries can be edited without being publicly available "
+            "until the changes have been reviewed and explicitely published by"
+            " an eligible user.",
+        )
+        .add_parent("StateModel")
+        .add_property(
+            "Transition",
+            datatype=db.LIST("Transition"),
+            value=[
+                "Edit",
+                "Start Review",
+                "Reject",
+                "Publish",
+                "Unpublish",
+            ],
+        )
+        .add_property("initial", "Unpublished")
+        .add_property("final", "Unpublished")
+        .insert()
+    )
+
+
+def parse_args():
+    parser = ArgumentParser(
+        description=__doc__, formatter_class=RawDescriptionHelpFormatter
+    )
+    subparsers = parser.add_subparsers(
+        title="action",
+        metavar="ACTION",
+        description=(
+            "You can perform the following actions. "
+            "Print the detailed help for each command with "
+            "#> setup_state_model ACTION -h"
+        ),
+    )
+
+    subparser = subparsers.add_parser(
+        "setup_state_data_model", help=setup_state_data_model.__doc__
+    )
+    subparser.set_defaults(call=setup_state_data_model)
+
+    subparser = subparsers.add_parser(
+        "setup_model_publication_cycle", help=setup_model_publication_cycle.__doc__
+    )
+    subparser.set_defaults(call=setup_model_publication_cycle)
+
+    subparser = subparsers.add_parser("setup_roles", help=setup_roles.__doc__)
+    subparser.set_defaults(call=setup_roles)
+
+    subparser = subparsers.add_parser("remove_user", help=remove_user.__doc__)
+    subparser.set_defaults(call=remove_user)
+    subparser.add_argument("username")
+
+    subparser = subparsers.add_parser("setup_user", help=setup_user.__doc__)
+    subparser.set_defaults(call=setup_user)
+    subparser.add_argument("username")
+    subparser.add_argument("role")
+
+    subparser = subparsers.add_parser(
+        "teardown", help="Removes ALL ENTITIES from LinkAhead!"
+    )
+    subparser.set_defaults(call=teardown)
+
+    subparser = subparsers.add_parser(
+        "soft_teardown", help=soft_teardown.__doc__
+    )
+    subparser.set_defaults(call=soft_teardown)
+
+    return parser.parse_args()
+
+
+if __name__ == "__main__":
+    args = parse_args()
+    args.call(args)
diff --git a/src/doc/tutorials/statemachine.rst b/src/doc/tutorials/statemachine.rst
new file mode 100644
index 0000000000000000000000000000000000000000..317620423e6221ccaf29297fc1f71f0c008f78a0
--- /dev/null
+++ b/src/doc/tutorials/statemachine.rst
@@ -0,0 +1,34 @@
+
+State Machine
+=============
+
+Prerequisites
+-------------
+
+In order to use the state machine functionality you have to set the
+corresponding server setting: ``EXT_ENTITY_STATE=ENABLED``.
+
+Also, a few RecordTypes and Properties are required. You can use the
+script `setup_state_model.py <https://gitlab.com/caosdb/caosdb-server/-/blob/dev/src/doc/tutorials/setup_state_model.py>`_
+to create those or you may have a look at it to see what is needed (``setup_state_data_model`` function).
+
+Defining the State Machine
+--------------------------
+
+Now you are setup to create your own state machine. You can define States and Transitions
+and bundle it all to a StateModel. The above mentioned ``setup_state_model.py`` script defines
+a publication cycle with the state "Unpublished", "UnderReview" and "Published".
+Again, the ``setup_state_model.py`` script provides orientation on how this
+can be setup (``setup_model_publication_cycle`` function).
+
+Note, that you can provide ACL to the state definition which will be applied to an entity once
+the state is reached. This is for example useful to change the visibility depending on a state change.
+
+If you assign a state to a RecordType, this state will be the initial state
+of Records that have that parent. For example by executing:
+
+.. code-block:: Python
+
+    rt = db.RecordType("Article").retrieve()
+    rt.state = db.State(name="UnPublished", model="Publish Life-cycle")``
+    rt.update()
diff --git a/src/main/java/org/caosdb/server/query/CQLParser.g4 b/src/main/java/org/caosdb/server/query/CQLParser.g4
index c4311ac1cbe03f490b79456e091cc0e73b94c506..f8c2a3b5ea4e7c34f3cc8fd07cdc77c912a5cc7b 100644
--- a/src/main/java/org/caosdb/server/query/CQLParser.g4
+++ b/src/main/java/org/caosdb/server/query/CQLParser.g4
@@ -287,15 +287,36 @@ pov returns [POV filter] locals [Query.Pattern p, String o, String v, String a]
 ;
 
 
-subproperty returns [SubProperty subp] locals [String p]
+subproperty returns [SubProperty subp]
 @init{
-    $p = null;
     $subp = null;
 }
 :
-    entity_filter {$subp = new SubProperty($entity_filter.filter);}
+	subproperty_filter {$subp = new SubProperty($subproperty_filter.filter);}
 ;
 
+subproperty_filter returns [EntityFilterInterface filter]
+    @init{
+        $filter = null;
+    }
+:
+    which_exp
+    (
+        (
+            LPAREN WHITE_SPACE?
+            (
+                filter_expression {$filter = $filter_expression.efi;}
+                | conjunction {$filter = $conjunction.c;}
+                | disjunction {$filter = $disjunction.d;}
+            )
+            RPAREN
+        ) | (
+            filter_expression {$filter = $filter_expression.efi;}
+        )
+    )?
+;
+
+
 backreference returns [Backreference ref] locals [Query.Pattern e, Query.Pattern p]
     @init{
         $e = null;
@@ -328,7 +349,7 @@ storedat returns [StoredAt filter] locals [String loc]
     WHITE_SPACE?
 ;
 
-conjunction returns [Conjunction c] locals [Conjunction dummy]
+conjunction returns [Conjunction c]
     @init{
         $c = new Conjunction();
     }
@@ -493,7 +514,7 @@ number_with_unit
 
 unit
 :
-    (~(WHITE_SPACE | WHICH | HAS_A | WITH | WHERE | DOT | AND | OR ))
+    (~(WHITE_SPACE | WHICH | HAS_A | WITH | WHERE | DOT | AND | OR | RPAREN ))
     (~(WHITE_SPACE))*
     |
     NUM SLASH (~(WHITE_SPACE))+
@@ -510,7 +531,7 @@ atom returns [Query.Pattern ep]
 :
     double_quoted {$ep = $double_quoted.ep;}
     | single_quoted {$ep = $single_quoted.ep;}
-    | (~(WHITE_SPACE | DOT ))+  {$ep = new Query.Pattern($text, Query.Pattern.TYPE_NORMAL);}
+    | (~(WHITE_SPACE | DOT | RPAREN | LPAREN ))+ {$ep = new Query.Pattern($text, Query.Pattern.TYPE_NORMAL);}
 ;
 
 single_quoted returns [Query.Pattern ep] locals [StringBuffer sb, int patternType]
diff --git a/src/test/java/org/caosdb/server/query/TestCQL.java b/src/test/java/org/caosdb/server/query/TestCQL.java
index cf54bf71b69ea5f539744bd4bbe30fd1c37edcf4..ff1be776b041490aac7c434acdee73c96a9e88f9 100644
--- a/src/test/java/org/caosdb/server/query/TestCQL.java
+++ b/src/test/java/org/caosdb/server/query/TestCQL.java
@@ -264,6 +264,13 @@ public class TestCQL {
   String queryMR56 = "FIND ENTITY WITH ((p0 = v0 OR p1=v1) AND p2=v2)";
 
   String versionedQuery1 = "FIND ANY VERSION OF ENTITY e1";
+  // https://gitlab.com/caosdb/caosdb-server/-/issues/131
+  String issue131a = "FIND ename WITH pname1.x AND pname2";
+  String issue131b = "FIND ename WITH (pname1.x < 10) AND (pname1.x)";
+  String issue131c = "FIND ename WITH pname2 AND pname1.x ";
+  String issue131d = "FIND ename WITH (pname1.x) AND pname2";
+  String issue131e = "FIND ename WITH (pname1.pname2 > 30) AND (pname1.pname2 < 40)";
+  String issue131f = "FIND ename WITH (pname1.pname2 > 30) AND pname1.pname2 < 40";
 
   @Test
   public void testQuery1()
@@ -4341,7 +4348,7 @@ public class TestCQL {
     assertEquals("THE GREATEST ID", conjunction.getChild(3).getText());
   }
 
-  /** String query31 = "FIND PROPERTIES WHICH ARE INSERTED TODAY"; */
+  /** String query31 = "FIND PROPERTIES WHICH WERE INSERTED TODAY"; */
   @Test
   public void testQuery31() {
     CQLLexer lexer;
@@ -6740,4 +6747,163 @@ public class TestCQL {
     // must not throw ParsingException
     new Query(this.queryIssue131).parse();
   }
+
+  /** String issue131a = "FIND ename WITH pname1.x AND pname2"; */
+  @Test
+  public void testIssue131a() {
+    CQLLexer lexer;
+    lexer = new CQLLexer(CharStreams.fromString(this.issue131a));
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+
+    System.out.println(sfq.toStringTree(parser));
+
+    assertTrue(sfq.filter instanceof Conjunction);
+    LinkedList<EntityFilterInterface> filters = ((Conjunction) sfq.filter).getFilters();
+    assertEquals(filters.size(), 2);
+    assertTrue(filters.get(0) instanceof POV);
+    assertTrue(filters.get(1) instanceof POV);
+    POV pov1 = ((POV) filters.get(0));
+    POV pov2 = ((POV) filters.get(1));
+    assertEquals("POV(pname1,null,null)", pov1.toString());
+    assertEquals("POV(pname2,null,null)", pov2.toString());
+    assertTrue(pov1.hasSubProperty());
+    assertFalse(pov2.hasSubProperty());
+    assertEquals("POV(x,null,null)", pov1.getSubProperty().getFilter().toString());
+  }
+
+  /** String issue131b = "FIND ename WITH (pname1.x < 10) AND (pname1.x)"; */
+  @Test
+  public void testIssue131b() {
+    CQLLexer lexer;
+    lexer = new CQLLexer(CharStreams.fromString(this.issue131b));
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+
+    System.out.println(sfq.toStringTree(parser));
+
+    assertTrue(sfq.filter instanceof Conjunction);
+    LinkedList<EntityFilterInterface> filters = ((Conjunction) sfq.filter).getFilters();
+    assertEquals(filters.size(), 2);
+    assertTrue(filters.get(0) instanceof POV);
+    assertTrue(filters.get(1) instanceof POV);
+    POV pov1 = ((POV) filters.get(0));
+    POV pov2 = ((POV) filters.get(1));
+    assertEquals("POV(pname1,null,null)", pov1.toString());
+    assertEquals("POV(pname1,null,null)", pov2.toString());
+    assertTrue(pov1.hasSubProperty());
+    assertTrue(pov2.hasSubProperty());
+    assertEquals("POV(x,<,10)", pov1.getSubProperty().getFilter().toString());
+    assertEquals("POV(x,null,null)", pov2.getSubProperty().getFilter().toString());
+  }
+
+  /** String issue131c = "FIND ename WITH pname2 AND pname1.x "; */
+  @Test
+  public void testIssue131c() {
+    CQLLexer lexer;
+    lexer = new CQLLexer(CharStreams.fromString(this.issue131c));
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+
+    System.out.println(sfq.toStringTree(parser));
+
+    assertTrue(sfq.filter instanceof Conjunction);
+    LinkedList<EntityFilterInterface> filters = ((Conjunction) sfq.filter).getFilters();
+    assertEquals(filters.size(), 2);
+    assertTrue(filters.get(0) instanceof POV);
+    assertTrue(filters.get(1) instanceof POV);
+    POV pov1 = ((POV) filters.get(0));
+    POV pov2 = ((POV) filters.get(1));
+    assertEquals("POV(pname2,null,null)", pov1.toString());
+    assertEquals("POV(pname1,null,null)", pov2.toString());
+    assertFalse(pov1.hasSubProperty());
+    assertTrue(pov2.hasSubProperty());
+    assertEquals("POV(x,null,null)", pov2.getSubProperty().getFilter().toString());
+  }
+
+  /** String issue131d = "FIND ename WITH (pname1.x) AND pname2"; */
+  @Test
+  public void testIssue131d() {
+    CQLLexer lexer;
+    lexer = new CQLLexer(CharStreams.fromString(this.issue131d));
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+
+    System.out.println(sfq.toStringTree(parser));
+
+    assertTrue(sfq.filter instanceof Conjunction);
+    LinkedList<EntityFilterInterface> filters = ((Conjunction) sfq.filter).getFilters();
+    assertEquals(filters.size(), 2);
+    assertTrue(filters.get(0) instanceof POV);
+    assertTrue(filters.get(1) instanceof POV);
+    POV pov1 = ((POV) filters.get(0));
+    POV pov2 = ((POV) filters.get(1));
+    assertEquals("POV(pname1,null,null)", pov1.toString());
+    assertEquals("POV(pname2,null,null)", pov2.toString());
+    assertTrue(pov1.hasSubProperty());
+    assertFalse(pov2.hasSubProperty());
+    assertEquals("POV(x,null,null)", pov1.getSubProperty().getFilter().toString());
+  }
+
+  /** String issue131e = "FIND ename WITH (pname1.pname2 > 30) AND (pname1.pname2 < 40)"; */
+  @Test
+  public void testIssue131e() {
+    CQLLexer lexer;
+    lexer = new CQLLexer(CharStreams.fromString(this.issue131e));
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+
+    System.out.println(sfq.toStringTree(parser));
+
+    assertTrue(sfq.filter instanceof Conjunction);
+    LinkedList<EntityFilterInterface> filters = ((Conjunction) sfq.filter).getFilters();
+    assertEquals(filters.size(), 2);
+    assertTrue(filters.get(0) instanceof POV);
+    assertTrue(filters.get(1) instanceof POV);
+    POV pov1 = ((POV) filters.get(0));
+    POV pov2 = ((POV) filters.get(1));
+    assertEquals("POV(pname1,null,null)", pov1.toString());
+    assertEquals("POV(pname1,null,null)", pov2.toString());
+    assertTrue(pov1.hasSubProperty());
+    assertTrue(pov2.hasSubProperty());
+    assertEquals("POV(pname2,>,30)", pov1.getSubProperty().getFilter().toString());
+    assertEquals("POV(pname2,<,40)", pov2.getSubProperty().getFilter().toString());
+  }
+
+  /** String issue131f = "FIND ename WITH (pname1.pname2 > 30) AND pname1.pname2 < 40"; */
+  @Test
+  public void testIssue131f() {
+    CQLLexer lexer;
+    lexer = new CQLLexer(CharStreams.fromString(this.issue131f));
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+
+    System.out.println(sfq.toStringTree(parser));
+
+    assertTrue(sfq.filter instanceof Conjunction);
+    LinkedList<EntityFilterInterface> filters = ((Conjunction) sfq.filter).getFilters();
+    assertEquals(filters.size(), 2);
+    assertTrue(filters.get(0) instanceof POV);
+    assertTrue(filters.get(1) instanceof POV);
+    POV pov1 = ((POV) filters.get(0));
+    POV pov2 = ((POV) filters.get(1));
+    assertEquals("POV(pname1,null,null)", pov1.toString());
+    assertEquals("POV(pname1,null,null)", pov2.toString());
+    assertTrue(pov1.hasSubProperty());
+    assertTrue(pov2.hasSubProperty());
+    assertEquals("POV(pname2,>,30)", pov1.getSubProperty().getFilter().toString());
+    assertEquals("POV(pname2,<,40)", pov2.getSubProperty().getFilter().toString());
+  }
 }