Files
old-svijetlastrana/data/datamysql/provider.go
2018-05-22 12:40:22 +02:00

454 lines
14 KiB
Go

package datamysql
import (
"database/sql"
"fmt"
"strconv"
"time"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
"github.com/go-sql-driver/mysql"
uuid "github.com/satori/go.uuid"
)
// rideRepo maps methods to database
type providerRepo struct {
conn executor
}
func newProviderRepo(conn executor) *providerRepo {
return &providerRepo{
conn: conn,
}
}
func (c *providerRepo) getProfileQuery(user entity.User) (query string, where string, err error) {
if len(user.Profiles) > 0 {
for _, p := range user.Profiles {
switch p.Key {
case "AD", "BCBSIAD", "BDCAD", "PLANAD":
return
case "SP", "SPT":
switch p.Organization.Type.Key {
case "techsupport", "bcbsi", "bcbsa", "plan":
return
case "provider":
query = ` INNER JOIN viw_organization_provider c
ON a.provider_id = c.provider_id `
where = fmt.Sprintf(` AND (c.organization_uuid = '%s' OR c.parent_organization_uuid = '%s') `, p.Organization.UUID, p.Organization.UUID)
return
}
}
}
if query == "" && where == "" {
return "", "", fmt.Errorf("Invalid Query")
} else {
return
}
} else {
return "", "", fmt.Errorf("User has no profile to search")
}
}
func (c *providerRepo) getSelectQueryBaseKey() string {
return `SELECT
a.provider_key_id,
a.provider_id,
a.internal_id,
a.internal_id_suffix,
a.location_seq_num,
a.plan_code,
a.product_id,
a.treatment_category_code,
a.active,
a.enabled,
a.create_at,
a.update_at,
a.created_user
FROM tab_provider_key a `
}
func (c *providerRepo) getSelectQueryBase() string {
return `SELECT DISTINCT
a.provider_id,
a.provider_uuid,
a.provider_internal_id,
IFNULL(a.provider_internal_id_suffix, '') provider_internal_id_suffix,
IFNULL(a.provider_muk_id, '') provider_muk_id,
IFNULL(a.organization_name, '') organization_name,
IFNULL(a.gender, '') gender,
IFNULL(a.accept_new_patients, '') accept_new_patients,
IFNULL(a.provider_name, '') provider_name,
IFNULL(a.first_name, '') first_name,
IFNULL(a.last_name, '') last_name,
IFNULL(a.middle_name, '') middle_name,
IFNULL(a.provider_title, '') provider_title,
IFNULL(a.street_name1, '') street_name1,
IFNULL(a.street_name2, '') street_name2,
IFNULL(a.city_name, '') city_name,
IFNULL(a.state, '') state,
IFNULL(a.zipcode, '') zipcode,
IFNULL(a.country, '') country,
IFNULL(a.latitude, 0) latitude,
IFNULL(a.longitude, 0) longitude,
IFNULL(a.phone_number, '') phone_number,
a.create_at,
a.update_at,
a.active,
a.enabled,
a.created_user,
(3959 * acos (
cos ( radians(?) )
* cos( radians( IFNULL(a.latitude, 0) ) )
* cos( radians( IFNULL(a.longitude, 0) ) - radians(?) )
+ sin ( radians(?) )
* sin( radians( IFNULL(a.latitude, 0) ) )
)) AS distance_in_miles
FROM
tab_provider a
INNER JOIN tab_provider_key b
ON a.provider_id = b.provider_id `
}
func (c *providerRepo) GetAll(user entity.User) ([]entity.Provider, error) {
lat := 41.886406
long := -87.624225
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getSelectQueryBase() + query + " WHERE 1 = 1 " + where
providers, err := c.parseSet(c.conn.Query(query, lat, long, lat))
if err != nil {
return nil, err
}
return c.getKeys("", "", providers)
}
func (c *providerRepo) GetByUUID(providerUUID string, user entity.User) (entity.Provider, error) {
lat := 41.886406
long := -87.624225
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Provider{}, err
}
query = c.getSelectQueryBase() + query + " WHERE a.provider_uuid = ? " + where
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, providerUUID))
}
func (c *providerRepo) GetByMukID(mukID string, user entity.User) (entity.Provider, error) {
lat := 41.886406
long := -87.624225
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Provider{}, err
}
query = c.getSelectQueryBase() + query + " WHERE a.provider_muk_id = ? " + where
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, mukID))
}
func (c *providerRepo) GetByNPI(NPI string, user entity.User) (entity.Provider, error) {
lat := 41.886406
long := -87.624225
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Provider{}, err
}
query = c.getSelectQueryBase() + query + " WHERE a.provider_internal_id = ? " + where
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, NPI))
}
func (c *providerRepo) Get(query string, lat float64, long float64, distance int64, planCode string, productID string, mukID string, internalID string, sort string, user entity.User) ([]entity.Provider, error) {
filter := " WHERE 1 = 1 "
params := make([]interface{}, 0)
if lat == 0 && long == 0 {
lat = 41.886406
long = -87.624225
}
params = append(params, lat, long, lat)
if query != "" && (mukID == "" && internalID == "") {
filter += " AND (a.provider_name LIKE ? OR a.street_name1 LIKE ? OR a.street_name2 LIKE ? OR a.zipcode LIKE ?) "
// MATCH(a.provider_internal_id, a.provider_internal_id_suffix, a.provider_muk_id, a.provider_name, a.street_name1, a.street_name2, a.city_name, a.state, a.zipcode, a.country, a.phone_number) AGAINST (?)
query = "%" + query + "%"
params = append(params, query, query, query, query)
}
if planCode != "" {
filter += " AND b.plan_code = ? "
params = append(params, planCode)
}
if productID != "" {
filter += " AND b.product_id = ? "
params = append(params, productID)
}
if mukID != "" {
filter += " AND a.provider_muk_id = ? "
params = append(params, mukID)
}
if internalID != "" {
filter += " AND a.provider_internal_id = ? "
params = append(params, internalID)
}
final := " HAVING distance_in_miles < ? "
params = append(params, distance)
if sort == "name" {
final += " ORDER BY a.provider_name ASC "
} else if sort == "distance" {
final += " ORDER BY distance_in_miles ASC "
}
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getSelectQueryBase() + query + filter + where + final
providers, err := c.parseSet(c.conn.Query(query, params...))
if err != nil {
return nil, err
}
if len(providers) > 0 {
return c.getKeys(planCode, productID, providers)
} else {
return providers, nil
}
}
func (c *providerRepo) getKeys(planCode string, productID string, providers []entity.Provider) ([]entity.Provider, error) {
var params []interface{}
var queryParams = " WHERE a.provider_id IN ("
for _, p := range providers {
queryParams += "?,"
params = append(params, p.ProviderID)
}
queryParams = queryParams[0 : len(queryParams)-1]
queryParams += ") "
if planCode != "" {
queryParams += " AND a.plan_code = ? "
params = append(params, planCode)
}
if productID != "" {
queryParams += " AND a.product_id = ? "
params = append(params, productID)
}
keys, err := c.parseKeySet(c.conn.Query(c.getSelectQueryBaseKey()+queryParams, params...))
if err != nil {
return nil, err
}
sortedResults := make(map[string][]entity.ProviderKey)
for _, k := range keys {
sortedKey := fmt.Sprintf("provider%v", k.Provider.ProviderID)
sortedResults[sortedKey] = append(sortedResults[sortedKey], k)
}
for i := range providers {
sortedKey := fmt.Sprintf("provider%v", providers[i].ProviderID)
providers[i].Keys = sortedResults[sortedKey]
}
return providers, nil
}
// parseSet parses a result set result to an entity array
func (c *providerRepo) parseKeySet(rows *sql.Rows, err error) ([]entity.ProviderKey, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.ProviderKey, 0)
for rows.Next() {
entity, err := c.parseKeyEntity(rows)
if err != nil {
return nil, errors.Wrap(err)
}
result = append(result, entity)
}
return result, nil
}
// parseEntity parses a result to an entity
func (c *providerRepo) parseKeyEntity(row scanner) (retVal entity.ProviderKey, err error) {
err = row.Scan(
&retVal.ProviderKeyID, &retVal.Provider.ProviderID, &retVal.InternalID, &retVal.InternalSuffixID, &retVal.LocationSeqNumber, &retVal.PlanCode, &retVal.ProductID, &retVal.TreatmentCategoryCode, &retVal.Active, &retVal.Enabled, &retVal.CreateDate, &retVal.UpdateDate, &retVal.CreatedUser.ID)
return retVal, errors.Wrap(err)
}
// parseSet parses a result set result to an entity array
func (c *providerRepo) parseSet(rows *sql.Rows, err error) ([]entity.Provider, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Provider, 0)
for rows.Next() {
entity, err := c.parseEntity(rows)
if err != nil {
return nil, errors.Wrap(err)
}
result = append(result, entity)
}
return result, nil
}
// parseEntity parses a result to an entity
func (c *providerRepo) parseEntity(row scanner) (retVal entity.Provider, err error) {
err = row.Scan(
&retVal.ProviderID, &retVal.ProviderUUID, &retVal.InternalID, &retVal.InternalSuffixID, &retVal.MukID, &retVal.OrganizatioName, &retVal.Gender, &retVal.AcceptNewPatients, &retVal.Name, &retVal.FirstName, &retVal.LastName, &retVal.MiddleName, &retVal.Title, &retVal.Address.StreetAddress1, &retVal.Address.StreetAddress2, &retVal.Address.CityName, &retVal.Address.State, &retVal.Address.ZipCode, &retVal.Address.Country, &retVal.Address.Latitude, &retVal.Address.Longitude, &retVal.Address.PhoneNumber, &retVal.CreateDate, &retVal.UpdateDate, &retVal.Active, &retVal.Enabled, &retVal.CreatedUser.ID, &retVal.Distance)
if err == sql.ErrNoRows {
return retVal, nil
} else {
return retVal, errors.Wrap(err)
}
}
func (c *providerRepo) Save(providers []entity.ProviderResponse, user entity.User) ([]entity.Provider, error) {
var savedProviders = make([]entity.Provider, 0)
for _, p := range providers {
provider, err := c.saveProvider(p, user)
if err != nil {
if driverErr, ok := err.(*mysql.MySQLError); ok {
if driverErr.Number != 1062 {
return nil, err
}
} else {
return nil, err
}
} else {
savedProviders = append(savedProviders, provider)
}
}
return savedProviders, nil
}
func (c *providerRepo) saveProvider(provider entity.ProviderResponse, user entity.User) (entity.Provider, error) {
const (
query = `INSERT INTO tab_provider(provider_uuid,provider_internal_id,provider_internal_id_suffix,provider_muk_id,organization_name,gender,accept_new_patients,provider_name,first_name,last_name,middle_name,provider_title,street_name1,street_name2,city_name,state,zipcode,country,latitude,longitude,phone_number,created_user)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);`
)
UUID, _ := uuid.NewV4()
lat, _ := strconv.ParseFloat(provider.Latitude, 64)
long, _ := strconv.ParseFloat(provider.Longitude, 64)
p := entity.Provider{
ProviderUUID: UUID.String(),
InternalID: provider.FivePartKeyGroups[0].ProviderNum,
InternalSuffixID: provider.FivePartKeyGroups[0].ProviderNumSuffix,
MukID: provider.MukID,
OrganizatioName: provider.OrgName,
Gender: provider.Gender,
AcceptNewPatients: provider.AcceptNewPatients,
Name: provider.ProviderName,
FirstName: provider.FirstName,
MiddleName: provider.MiddleName,
LastName: provider.LastName,
Title: provider.ProviderTitle,
Address: entity.ProviderAddress{
StreetAddress1: provider.StreetName1,
StreetAddress2: provider.StreetName2,
CityName: provider.CityName,
State: provider.State,
ZipCode: provider.ZipCode,
Country: provider.Country,
Latitude: lat,
Longitude: long,
PhoneNumber: provider.PhoneNumber,
},
CreateDate: time.Now(),
UpdateDate: time.Now(),
Active: true,
Enabled: true,
}
result, err := c.conn.Exec(query, p.ProviderUUID, p.InternalID, p.InternalSuffixID, p.MukID, p.OrganizatioName, p.Gender, p.AcceptNewPatients, p.Name, p.FirstName, p.LastName, p.MiddleName, p.Title, p.Address.StreetAddress1, p.Address.StreetAddress2, p.Address.CityName, p.Address.State, p.Address.ZipCode, p.Address.Country, p.Address.Latitude, p.Address.Longitude, p.Address.PhoneNumber, 1)
if err != nil {
if driverErr, ok := err.(*mysql.MySQLError); ok {
if driverErr.Number != 1062 {
return entity.Provider{}, err
} else {
tempProvider, err := c.GetByMukID(p.MukID, user)
if err != nil {
return entity.Provider{}, err
}
p.ProviderID = tempProvider.ProviderID
}
}
} else {
p.ProviderID, err = result.LastInsertId()
if err != nil {
return entity.Provider{}, err
}
}
var providerKeys []entity.ProviderKey
for _, fk := range provider.FivePartKeyGroups {
key, err := c.saveKeys(p.ProviderID, fk)
if err != nil {
return p, err
}
providerKeys = append(providerKeys, key)
}
p.Keys = providerKeys
return p, nil
}
func (c *providerRepo) saveKeys(ProviderID int64, fk entity.PartKeyGroup) (entity.ProviderKey, error) {
const (
query = `INSERT INTO tab_provider_key (provider_id, internal_id, internal_id_suffix, location_seq_num, plan_code, product_id, treatment_category_code, created_user)
VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE provider_id = ?, internal_id = ?, internal_id_suffix = ?, location_seq_num = ?, plan_code = ?, product_id = ?, treatment_category_code = ?, created_user = ?;`
)
key := entity.ProviderKey{
InternalID: fk.ProviderNum,
InternalSuffixID: fk.ProviderNumSuffix,
TreatmentCategoryCode: fk.TreatmentCategoryCode,
ProductID: fk.ProductID,
PlanCode: fk.PlanCode,
LocationSeqNumber: fk.LocationSeqNum,
Provider: entity.Provider{
ProviderID: ProviderID,
},
}
result, err := c.conn.Exec(query, key.Provider.ProviderID, key.InternalID, key.InternalSuffixID, key.LocationSeqNumber, key.PlanCode, key.ProductID, key.TreatmentCategoryCode, 1, key.Provider.ProviderID, key.InternalID, key.InternalSuffixID, key.LocationSeqNumber, key.PlanCode, key.ProductID, key.TreatmentCategoryCode, 1)
if err != nil {
return key, err
}
key.ProviderKeyID, err = result.LastInsertId()
if err != nil {
return key, err
}
return key, nil
}