@Override
  @SuppressWarnings("unchecked")
  public List<ProgramInstance> getProgramInstances(ProgramInstanceQueryParams params) {
    String hql = buildProgramInstanceHql(params);
    Query query = getQuery(hql);

    if (params.isPaging()) {
      query.setFirstResult(params.getOffset());
      query.setMaxResults(params.getPageSizeWithDefault());
    }

    return query.list();
  }
  private String buildProgramInstanceHql(ProgramInstanceQueryParams params) {
    String hql = "from ProgramInstance pi";
    SqlHelper hlp = new SqlHelper(true);

    if (params.hasLastUpdated()) {
      hql +=
          hlp.whereAnd()
              + "pi.lastUpdated >= '"
              + getMediumDateString(params.getLastUpdated())
              + "'";
    }

    if (params.hasTrackedEntityInstance()) {
      hql +=
          hlp.whereAnd()
              + "pi.entityInstance.uid = '"
              + params.getTrackedEntityInstance().getUid()
              + "'";
    }

    if (params.hasTrackedEntity()) {
      hql +=
          hlp.whereAnd()
              + "pi.entityInstance.trackedEntity.uid = '"
              + params.getTrackedEntity().getUid()
              + "'";
    }

    if (params.hasOrganisationUnits()) {
      if (params.isOrganisationUnitMode(OrganisationUnitSelectionMode.DESCENDANTS)) {
        String ouClause = "(";
        SqlHelper orHlp = new SqlHelper(true);

        for (OrganisationUnit organisationUnit : params.getOrganisationUnits()) {
          ouClause +=
              orHlp.or() + "pi.organisationUnit.path LIKE '" + organisationUnit.getPath() + "%'";
        }

        ouClause += ")";

        hql += hlp.whereAnd() + ouClause;
      } else {
        hql +=
            hlp.whereAnd()
                + "pi.organisationUnit.uid in ("
                + getQuotedCommaDelimitedString(getUids(params.getOrganisationUnits()))
                + ")";
      }
    }

    if (params.hasProgram()) {
      hql += hlp.whereAnd() + "pi.program.uid = '" + params.getProgram().getUid() + "'";
    }

    if (params.hasProgramStatus()) {
      hql += hlp.whereAnd() + "pi.status = '" + params.getProgramStatus() + "'";
    }

    if (params.hasFollowUp()) {
      hql += hlp.whereAnd() + "pi.followup = " + params.getFollowUp();
    }

    if (params.hasProgramStartDate()) {
      hql +=
          hlp.whereAnd()
              + "pi.enrollmentDate >= '"
              + getMediumDateString(params.getProgramStartDate())
              + "'";
    }

    if (params.hasProgramEndDate()) {
      hql +=
          hlp.whereAnd()
              + "pi.enrollmentDate <= '"
              + getMediumDateString(params.getProgramEndDate())
              + "'";
    }

    return hql;
  }