Filtering records by exact value of a single field
This commit is contained in:
@@ -676,10 +676,10 @@
|
||||
],
|
||||
"get": [
|
||||
{
|
||||
"name": "filter",
|
||||
"type": "string",
|
||||
"name": "query",
|
||||
"required": false,
|
||||
"title": "Search query"
|
||||
"title": "Filtering condition"
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
|
||||
@@ -160,9 +160,9 @@
|
||||
"Parameters": {
|
||||
"get": [
|
||||
{
|
||||
"name": "query",
|
||||
"name": "filter",
|
||||
"required": false,
|
||||
"title": "Search query",
|
||||
"title": "Filtering condition",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -3,12 +3,13 @@ package repository
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/crusttech/crust/crm/repository/ql"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
"gopkg.in/Masterminds/squirrel.v1"
|
||||
|
||||
"github.com/crusttech/crust/crm/types"
|
||||
)
|
||||
@@ -20,7 +21,7 @@ type (
|
||||
FindByID(id uint64) (*types.Record, error)
|
||||
|
||||
Report(moduleID uint64, metrics, dimensions, filter string) (results interface{}, err error)
|
||||
Find(moduleID uint64, query string, page int, perPage int, sort string) (*FindResponse, error)
|
||||
Find(moduleID uint64, filter string, sort string, page int, perPage int) (*FindResponse, error)
|
||||
|
||||
Create(mod *types.Record) (*types.Record, error)
|
||||
Update(mod *types.Record) (*types.Record, error)
|
||||
@@ -30,7 +31,7 @@ type (
|
||||
}
|
||||
|
||||
FindResponseMeta struct {
|
||||
Query string `json:"query,omitempty"`
|
||||
Filter string `json:"filter,omitempty"`
|
||||
Page int `json:"page"`
|
||||
PerPage int `json:"perPage"`
|
||||
Count int `json:"count"`
|
||||
@@ -101,7 +102,7 @@ func (r *record) Report(moduleID uint64, metrics, dimensions, filter string) (re
|
||||
}
|
||||
}
|
||||
|
||||
func (r *record) Find(moduleID uint64, query string, page int, perPage int, sort string) (*FindResponse, error) {
|
||||
func (r *record) Find(moduleID uint64, filter string, sort string, page int, perPage int) (*FindResponse, error) {
|
||||
if page < 0 {
|
||||
page = 0
|
||||
}
|
||||
@@ -116,22 +117,58 @@ func (r *record) Find(moduleID uint64, query string, page int, perPage int, sort
|
||||
}
|
||||
response := &FindResponse{
|
||||
Meta: FindResponseMeta{
|
||||
Filter: filter,
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
Query: query,
|
||||
Sort: sort,
|
||||
},
|
||||
Records: make([]*types.Record, 0),
|
||||
}
|
||||
|
||||
query = "%" + query + "%"
|
||||
// Create query for fetching and counting records.
|
||||
query := squirrel.
|
||||
Select().
|
||||
From("crm_record").
|
||||
Where("module_id = ?", moduleID).
|
||||
Where(squirrel.Eq{"deleted_at": nil})
|
||||
|
||||
sqlSelect := "SELECT * FROM crm_record"
|
||||
sqlCount := "SELECT count(*) FROM crm_record"
|
||||
sqlWhere := "WHERE module_id=? and deleted_at IS NULL"
|
||||
sqlOrder := "ORDER BY id DESC"
|
||||
sqlLimit := fmt.Sprintf("LIMIT %d, %d", page*perPage, perPage)
|
||||
// Parse filters.
|
||||
p := ql.NewParser()
|
||||
p.OnIdent = ql.MakeIdentWrapHandler(jsonWrap, "created_at", "updated_at", "id", "user_id")
|
||||
|
||||
where, err := p.ParseExpression(filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Append filtering to query.
|
||||
query = query.Where(where)
|
||||
|
||||
// Create count SQL sentences.
|
||||
count := query.Column(squirrel.Alias(squirrel.Expr("COUNT(*)"), "count"))
|
||||
|
||||
sqlSelect, argsSelect, err := count.ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Execute count query.
|
||||
if err := r.db().Get(&response.Meta.Count, sqlSelect, argsSelect...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return empty response if count of records is zero.
|
||||
if response.Meta.Count == 0 {
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// Create query for fetching records.
|
||||
query = query.
|
||||
Column("*").
|
||||
Limit(uint64(perPage)).
|
||||
Offset(uint64(page))
|
||||
|
||||
// Append Sorting.
|
||||
chuncks := strings.Split(sort, ",")
|
||||
if len(chuncks) > 0 {
|
||||
|
||||
@@ -195,37 +232,35 @@ func (r *record) Find(moduleID uint64, query string, page int, perPage int, sort
|
||||
orderFields = append(orderFields, field+" "+order)
|
||||
}
|
||||
|
||||
sqlOrder = "ORDER BY " + strings.Join(orderFields, ", ")
|
||||
query = query.OrderBy(orderFields...)
|
||||
}
|
||||
|
||||
// One possibility to order by field value without JSON, is query written bellow with FIELD over column names and order by value:
|
||||
// SELECT * FROM crm_record
|
||||
// LEFT JOIN crm_record ON crm_record.id = crm_record_column.record_id"
|
||||
// WHERE column_name in ('name', 'email')
|
||||
// ORDER BY FIELD(column_name, 'email', 'name'), column_value;
|
||||
/*
|
||||
p = ql.NewParser()
|
||||
p.OnIdent = ql.MakeIdentWrapHandler(jsonWrap, "id", "module_id", "user_id", "created_at", "updated_at")
|
||||
|
||||
// Possibility to order with JSON:
|
||||
// SELECT *,
|
||||
// JSON_UNQUOTE(JSON_EXTRACT(json, REPLACE(JSON_UNQUOTE(JSON_SEARCH(json, 'all', 'email')), '.name', '.value'))) as emailField
|
||||
// FROM crm_record
|
||||
// ORDER by emailField asc;
|
||||
order, err := p.ParseExpression(sort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch true {
|
||||
case query != "":
|
||||
sqlWhere = sqlWhere + " AND id in (select distinct record_id from crm_record_column where column_value like ?)"
|
||||
if err := r.db().Get(&response.Meta.Count, sqlCount+" "+sqlWhere, moduleID, query); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := r.db().Select(&response.Records, sqlSelect+" "+sqlWhere+" "+sqlOrder+" "+sqlLimit, moduleID, query); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
if err := r.db().Get(&response.Meta.Count, sqlCount+" "+sqlWhere, moduleID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := r.db().Select(&response.Records, sqlSelect+" "+sqlWhere+" "+sqlOrder+" "+sqlLimit, moduleID); err != nil {
|
||||
sqlOrder, argsOrder, err := order.ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query = query.OrderBy(sqlOrder)
|
||||
*/
|
||||
|
||||
// Create actual fetch SQL sentences.
|
||||
sqlSelect, argsSelect, err = query.ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Append order args to select args and execute actual query.
|
||||
// argsSelect = append(argsSelect, argsOrder...)
|
||||
if err := r.db().Select(&response.Records, sqlSelect, argsSelect...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
|
||||
@@ -58,7 +58,7 @@ func (s *Module) RecordReport(ctx context.Context, r *request.ModuleRecordReport
|
||||
}
|
||||
|
||||
func (s *Module) RecordList(ctx context.Context, r *request.ModuleRecordList) (interface{}, error) {
|
||||
return s.content.With(ctx).Find(r.ModuleID, r.Query, r.Page, r.PerPage, r.Sort)
|
||||
return s.content.With(ctx).Find(r.ModuleID, r.Filter, r.Page, r.PerPage, r.Sort)
|
||||
}
|
||||
|
||||
func (s *Module) RecordRead(ctx context.Context, r *request.ModuleRecordRead) (interface{}, error) {
|
||||
|
||||
@@ -320,7 +320,7 @@ var _ RequestFiller = NewModuleRecordReport()
|
||||
|
||||
// Module record/list request parameters
|
||||
type ModuleRecordList struct {
|
||||
Query string
|
||||
Filter string
|
||||
Page int
|
||||
PerPage int
|
||||
Sort string
|
||||
@@ -358,9 +358,9 @@ func (m *ModuleRecordList) Fill(r *http.Request) (err error) {
|
||||
post[name] = string(param[0])
|
||||
}
|
||||
|
||||
if val, ok := get["query"]; ok {
|
||||
if val, ok := get["filter"]; ok {
|
||||
|
||||
m.Query = val
|
||||
m.Filter = val
|
||||
}
|
||||
if val, ok := get["page"]; ok {
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ type (
|
||||
FindByID(recordID uint64) (*types.Record, error)
|
||||
|
||||
Report(moduleID uint64, metrics, dimensions, filter string) (interface{}, error)
|
||||
Find(moduleID uint64, query string, page int, perPage int, sort string) (*repository.FindResponse, error)
|
||||
Find(moduleID uint64, filter string, sort string, page int, perPage int) (*repository.FindResponse, error)
|
||||
|
||||
Create(record *types.Record) (*types.Record, error)
|
||||
Update(record *types.Record) (*types.Record, error)
|
||||
@@ -68,8 +68,8 @@ func (s *record) Report(moduleID uint64, metrics, dimensions, filter string) (in
|
||||
return s.repository.Report(moduleID, metrics, dimensions, filter)
|
||||
}
|
||||
|
||||
func (s *record) Find(moduleID uint64, query string, page int, perPage int, sort string) (*repository.FindResponse, error) {
|
||||
response, err := s.repository.Find(moduleID, query, page, perPage, sort)
|
||||
func (s *record) Find(moduleID uint64, filter string, sort string, page int, perPage int) (*repository.FindResponse, error) {
|
||||
response, err := s.repository.Find(moduleID, filter, sort, page, perPage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ func TestRecord(t *testing.T) {
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
mr, err := repository.Find(module.ID, "", 0, 20, "id desc")
|
||||
mr, err := repository.Find(module.ID, "", "id desc", 0, 20)
|
||||
assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
assert(t, len(mr.Records) == 2, "Expected two record, got %d", len(mr.Records))
|
||||
assert(t, mr.Meta.Count == 2, "Expected Meta.Count == 2, got %d", mr.Meta.Count)
|
||||
@@ -193,7 +193,7 @@ func TestRecord(t *testing.T) {
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
mr, err := repository.Find(module.ID, "", 0, 20, "name asc, email desc")
|
||||
mr, err := repository.Find(module.ID, "", "name asc, email desc", 0, 20)
|
||||
assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
assert(t, len(mr.Records) == 2, "Expected two record, got %d", len(mr.Records))
|
||||
assert(t, mr.Meta.Count == 2, "Expected Meta.Count == 2, got %d", mr.Meta.Count)
|
||||
@@ -204,7 +204,7 @@ func TestRecord(t *testing.T) {
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
mr, err := repository.Find(module.ID, "", 0, 20, "created_at desc")
|
||||
mr, err := repository.Find(module.ID, "", "created_at desc", 0, 20)
|
||||
assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
assert(t, len(mr.Records) == 2, "Expected two record, got %d", len(mr.Records))
|
||||
assert(t, mr.Meta.Count == 2, "Expected Meta.Count == 2, got %d", mr.Meta.Count)
|
||||
@@ -215,19 +215,19 @@ func TestRecord(t *testing.T) {
|
||||
|
||||
// fetch all records by query
|
||||
{
|
||||
mr, err := repository.Find(module.ID, "petric", 0, 20, "id desc")
|
||||
mr, err := repository.Find(module.ID, "name='Tit Petric'", "id desc", 0, 20)
|
||||
assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
assert(t, len(mr.Records) == 1, "Expected one record, got %d", len(mr.Records))
|
||||
assert(t, mr.Meta.Count == 1, "Expected Meta.Count == 1, got %d", mr.Meta.Count)
|
||||
assert(t, mr.Meta.Page == 0, "Expected Meta.Page == 0, got %d", mr.Meta.Page)
|
||||
assert(t, mr.Meta.PerPage == 20, "Expected Meta.PerPage == 20, got %d", mr.Meta.PerPage)
|
||||
assert(t, mr.Meta.Query == "petric", "Expected Meta.Query == petric, got '%s'", mr.Meta.Query)
|
||||
assert(t, mr.Meta.Filter == "name='Tit Petric'", "Expected Meta.Filter == name='Tit Petric', got '%s'", mr.Meta.Filter)
|
||||
assert(t, mr.Meta.Sort == "id desc", "Expected Meta.Sort == id desc, got '%s'", mr.Meta.Sort)
|
||||
}
|
||||
|
||||
// fetch all records by query
|
||||
{
|
||||
mr, err := repository.Find(module.ID, "niall", 0, 20, "id asc")
|
||||
mr, err := repository.Find(module.ID, "niall", "id asc", 0, 20)
|
||||
assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
assert(t, len(mr.Records) == 0, "Expected no records, got %d", len(mr.Records))
|
||||
}
|
||||
@@ -243,7 +243,7 @@ func TestRecord(t *testing.T) {
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
mr, err := repository.Find(module.ID, "", 0, 20, "")
|
||||
mr, err := repository.Find(module.ID, "", "", 0, 20)
|
||||
assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
assert(t, len(mr.Records) == 0, "Expected no record, got %d", len(mr.Records))
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ CRM module definitions
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| query | string | GET | Search query | N/A | NO |
|
||||
| filter | string | GET | Filtering condition | N/A | NO |
|
||||
| page | int | GET | Page number (0 based) | N/A | NO |
|
||||
| perPage | int | GET | Returned items per page (default 50) | N/A | NO |
|
||||
| sort | string | GET | Sort field (default id desc) | N/A | NO |
|
||||
|
||||
Reference in New Issue
Block a user