initial commit 2

This commit is contained in:
Senad Uka
2018-04-25 13:16:36 +02:00
parent c1520d169c
commit 99c10b75fb
167 changed files with 25057 additions and 0 deletions

133
data/datamysql/datamysql.go Normal file
View File

@@ -0,0 +1,133 @@
package datamysql
import (
"database/sql"
"fmt"
"sync"
"time"
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
"github.com/go-sql-driver/mysql"
)
var (
instance *Conn
once sync.Once
connErr error
)
// Conn is the MySQL connection manager
type Conn struct {
db *sql.DB
users *userRepo
rides *rideRepo
visit *visitRepo
provider *providerRepo
notification *notificationRepo
profile *profileRepo
organization *organizationRepo
}
// Begin starts a transaction
func (c *Conn) Begin() (contract.TransactionManager, error) {
tx, err := c.db.Begin()
if err != nil {
return nil, errors.Wrap(err)
}
return newTransaction(tx), nil
}
// Close closes the db connection
func (c *Conn) Close() (err error) {
return c.db.Close()
}
// Users returns the users set
func (c *Conn) Users() contract.UserRepo {
return c.users
}
// Rides returns the rides set
func (c *Conn) Rides() contract.RideRepo {
return c.rides
}
// Visits returns the rides set
func (c *Conn) Visits() contract.VisitRepo {
return c.visit
}
// Provider returns the rides set
func (c *Conn) Provider() contract.ProviderRepo {
return c.provider
}
// Provider returns the rides set
func (c *Conn) Profile() contract.ProfileRepo {
return c.profile
}
// Provider returns the rides set
func (c *Conn) Notification() contract.NotificationRepo {
return c.notification
}
// Provider returns the rides set
func (c *Conn) Organization() contract.OrganizationRepo {
return c.organization
}
// Instance returns an instance of a DataManager
func Instance(cfg *config.Config) (contract.DataManager, error) {
once.Do(func() {
db, err := sql.Open("mysql", getMySQLConfig(cfg).FormatDSN())
if err != nil {
connErr = errors.Wrap(err)
return
}
err = db.Ping()
if err != nil {
connErr = errors.Wrap(err)
return
}
connMaxLifetime := time.Duration(cfg.DB.MaxLifeInMinutes) * time.Minute
db.SetConnMaxLifetime(connMaxLifetime)
db.SetMaxIdleConns(cfg.DB.MaxIdleConns)
db.SetMaxOpenConns(cfg.DB.MaxOpenConns)
instance = new(Conn)
instance.db = db
instance.users = newUserRepo(db)
instance.rides = newRideRepo(db)
instance.visit = newVisitRepo(db)
instance.provider = newProviderRepo(db)
instance.notification = newNotificationRepo(db)
instance.profile = newProfileRepo(db)
instance.organization = newOrganizationRepo(db)
})
return instance, connErr
}
// getMySQLConfig returns the configuration for MySQL driver
func getMySQLConfig(cfg *config.Config) *mysql.Config {
loc, _ := time.LoadLocation("UTC")
return &mysql.Config{
Net: "tcp",
Addr: fmt.Sprintf("%s:%d", cfg.DB.Host, cfg.DB.Port),
DBName: cfg.DB.Name,
User: cfg.DB.User,
Passwd: cfg.DB.Pass,
ParseTime: true,
Strict: true,
Loc: loc,
}
}

View File

@@ -0,0 +1,140 @@
package datamysql
import (
"database/sql"
"fmt"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
uuid "github.com/satori/go.uuid"
)
// visitRepo maps methods to database
type notificationRepo struct {
conn executor
}
func newNotificationRepo(conn executor) *notificationRepo {
return &notificationRepo{
conn: conn,
}
}
func (c *notificationRepo) Create(notification entity.Notification) (entity.Notification, error) {
const (
statusQuery = `SELECT a.contact_type_id, b.ride_id, c.user_id, d.user_id created_user_id FROM tab_contact_type a, tab_ride b, tab_user c, tab_user d WHERE a.key = ? AND b.ride_uuid = ? AND c.user_uuid = ? AND d.user_uuid = ?;`
query = `INSERT INTO tab_notification(notification_uuid, ride_id, user_id, contact_type_id, contact, message, created_user_id, readed, notificaton_type) VALUES(?, ?, ?, ?, ?, ?, ?, 0, ?);`
)
retVal := notification
UUID, _ := uuid.NewV4()
retVal.UUID = UUID.String()
row := c.conn.QueryRow(statusQuery, retVal.Type, retVal.Ride.UUID, retVal.User.UUID, retVal.CreatedUser.UUID)
if err := row.Scan(&retVal.TypeID, &retVal.Ride.ID, &retVal.User.ID, &retVal.CreatedUser.ID); err != nil {
fmt.Println("Error to get base data: ", err.Error())
return retVal, err
}
results, err := c.conn.Exec(query, retVal.UUID, retVal.Ride.ID, retVal.User.ID, retVal.TypeID, retVal.Subject, retVal.Message, retVal.CreatedUser.ID, retVal.MessageType)
if err != nil {
return retVal, err
}
retVal.ID, err = results.LastInsertId()
if err != nil {
return retVal, err
}
return c.GetByID(retVal.ID)
}
func (c *notificationRepo) getQuery() string {
return `SELECT
a.notification_id,
a.notification_uuid,
a.ride_id,
a.user_id,
c.user_uuid,
c.name user_name,
CASE WHEN b.key = 'sms' THEN e.phone_number WHEN b.key = 'email' THEN e.email WHEN b.key = 'app' THEN c.user_uuid END to_address,
CASE WHEN b.key = 'sms' THEN f.phone_number WHEN b.key = 'email' THEN f.email WHEN b.key = 'app' THEN d.user_uuid END from_address,
a.contact_type_id,
b.key contact_type_key,
a.contact,
a.message,
a.create_at,
a.readed,
d.user_id created_user_id,
d.user_uuid created_user_uuid,
d.name created_user_name,
a.notificaton_type
FROM
tab_notification a
INNER JOIN tab_contact_type b
ON a.contact_type_id = b.contact_type_id
INNER JOIN tab_user c
ON a.user_id = c.user_id
INNER JOIN tab_user d
ON a.created_user_id = d.user_id
INNER JOIN tab_login e
ON c.user_id = e.user_id
INNER JOIN tab_login f
ON d.user_id = f.user_id`
}
func (c *notificationRepo) GetLastNotificationFromPhoneNumber(notificationType string, phoneNumber string, status string) (entity.Notification, error) {
const (
whereClause = ` WHERE
a.notificaton_type = ?
AND e.phone_number = ?
AND b.key = ?
ORDER BY a.notification_id DESC
LIMIT 1;`
)
finalQuery := c.getQuery() + whereClause
return c.parseEntity(c.conn.QueryRow(finalQuery, notificationType, phoneNumber, status))
}
func (c *notificationRepo) GetByUserUUIDAndReadStatus(userUUID string, status string, isRead bool) ([]entity.Notification, error) {
return c.parseSet(c.conn.Query(c.getQuery()+" WHERE a.readed = ? AND b.key = ? AND c.user_uuid = ?; ", isRead, status, userUUID))
}
func (c *notificationRepo) GetByUserUUID(userUUID string, status string) ([]entity.Notification, error) {
return c.parseSet(c.conn.Query(c.getQuery()+" WHERE b.key = ? AND c.user_uuid = ?; ", status, userUUID))
}
func (c *notificationRepo) ReadStatus(notificationUUID string, isRead bool) error {
const query = "UPDATE tab_notification SET readed = ? WHERE notification_uuid = ?"
_, err := c.conn.Exec(query, isRead, notificationUUID)
return err
}
func (c *notificationRepo) GetByID(ID int64) (entity.Notification, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE a.notification_id = ?; ", ID))
}
// parseSet parses a result set result to an entity array
func (c *notificationRepo) parseSet(rows *sql.Rows, err error) ([]entity.Notification, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Notification, 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 *notificationRepo) parseEntity(row scanner) (retVal entity.Notification, err error) {
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.Ride.ID, &retVal.User.ID, &retVal.User.UUID, &retVal.User.Name, &retVal.To, &retVal.From, &retVal.TypeID, &retVal.Type, &retVal.Subject, &retVal.Message, &retVal.Created, &retVal.Read, &retVal.CreatedUser.ID, &retVal.CreatedUser.UUID, &retVal.CreatedUser.Name, &retVal.MessageType)
return retVal, errors.Wrap(err)
}

View File

@@ -0,0 +1,482 @@
package datamysql
import (
"database/sql"
"fmt"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
uuid "github.com/satori/go.uuid"
)
// rideRepo maps methods to database
type organizationRepo struct {
conn executor
}
func newOrganizationRepo(conn executor) *organizationRepo {
return &organizationRepo{
conn: conn,
}
}
func (c *organizationRepo) getQuery() string {
const (
query = `SELECT
a.organization_id,
a.organization_uuid,
b.organization_type_id,
b.organization_type,
b.organization_type_key,
a.organization_name,
a.organization_description,
a.organization_reference_id,
a.organization_parent_id,
(a.main_organization = b'1') main_organization,
a.create_at,
a.update_at,
(a.active = b'1') active,
(a.suspended = b'1') suspended,
(a.blocked = b'1') blocked,
c.user_id created_user_id,
c.user_uuid created_user_uuid,
c.name created_user_name,
d.user_id updated_user_id,
d.user_uuid updated_user_uuid,
d.name updated_user_name
FROM
tab_organization a
INNER JOIN tab_organization_type b
ON a.organization_type_id = b.organization_type_id
INNER JOIN tab_user c
ON c.user_id = a.created_user
INNER JOIN tab_user d
ON d.user_id = a.updated_user `
)
return query
}
func (c *organizationRepo) getAddressQuery() string {
const query = `SELECT
a.organization_address_id,
a.organization_address_uuid,
a.internal_id,
a.name,
a.address,
a.desc,
a.lat,
a.long,
a.created,
a.created_user_id,
c.user_uuid created_user_uuid,
c.name created_user_name,
a.updated,
a.updated_user_id,
d.user_uuid updated_user_uuid,
d.name updated_user_name,
(a.active = b'1') active
FROM tab_organization_address a
INNER JOIN tab_organization b
ON b.organization_id = a.organization_id
INNER JOIN tab_user c
ON c.user_id = a.created_user_id
INNER JOIN tab_user d
ON d.user_id = a.updated_user_id `
return query
}
func (c *organizationRepo) getContactQuery() string {
const (
query = `SELECT
a.organization_contact_id,
a.organization_contact_uuid,
b.contact_type_id,
b.key contact_type_key,
b.name contact_type_name,
a.contact,
a.contact_name,
a.contact_desc,
a.created,
a.created_user_id,
d.user_uuid created_user_uuid,
d.name created_user_name,
a.updated,
a.updated_user_id,
e.user_uuid updated_user_uuid,
e.name updated_user_name,
(a.active = b'1') active
FROM tab_organization_contact a
INNER JOIN tab_contact_type b
ON a.contact_type_id = b.contact_type_id
INNER JOIN tab_organization c
ON c.organization_id = a.organization_id
INNER JOIN tab_user d
ON d.user_id = a.created_user_id
INNER JOIN tab_user e
ON e.user_id = a.updated_user_id `
)
return query
}
func (c *organizationRepo) getTypeQuery() string {
const (
query = `SELECT
organization_type_id,
organization_type,
organization_type_key,
description,
create_at,
update_at
FROM
tab_organization_type `
)
return query
}
// parseSet parses a result set result to an entity array
func (c *organizationRepo) parseSet(rows *sql.Rows, err error) ([]entity.Organization, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Organization, 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 *organizationRepo) parseEntity(row scanner) (retVal entity.Organization, err error) {
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.Type.ID, &retVal.Type.Name, &retVal.Type.Key, &retVal.Name, &retVal.Description, &retVal.ReferenceID, &retVal.ParentID, &retVal.Main, &retVal.Created, &retVal.Updated, &retVal.Active, &retVal.Suspended, &retVal.Blocked, &retVal.Author.ID, &retVal.Author.UUID, &retVal.Author.Name, &retVal.LastEditor.ID, &retVal.LastEditor.UUID, &retVal.LastEditor.Name)
return retVal, errors.Wrap(err)
}
// parseSet parses a result set result to an entity array
func (c *organizationRepo) parseContactSet(rows *sql.Rows, err error) ([]entity.OrganizationContact, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.OrganizationContact, 0)
for rows.Next() {
entity, err := c.parseContactEntity(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 *organizationRepo) parseContactEntity(row scanner) (retVal entity.OrganizationContact, err error) {
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.Type.ID, &retVal.Type.Key, &retVal.Type.Value, &retVal.Contact, &retVal.Name, &retVal.Description, &retVal.Created, &retVal.CreatedUser.ID, &retVal.CreatedUser.UUID, &retVal.CreatedUser.Name, &retVal.Updated, &retVal.UpdatedUser.ID, &retVal.UpdatedUser.UUID, &retVal.UpdatedUser.Name, &retVal.Active)
return retVal, errors.Wrap(err)
}
// parseSet parses a result set result to an entity array
func (c *organizationRepo) parseAddressSet(rows *sql.Rows, err error) ([]entity.OrganizationAddress, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.OrganizationAddress, 0)
for rows.Next() {
entity, err := c.parseAddressEntity(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 *organizationRepo) parseAddressEntity(row scanner) (retVal entity.OrganizationAddress, err error) {
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.InternalID, &retVal.Name, &retVal.Address, &retVal.Description, &retVal.Latitude, &retVal.Longitude, &retVal.Created, &retVal.CreatedUser.ID, &retVal.CreatedUser.UUID, &retVal.CreatedUser.Name, &retVal.Updated, &retVal.UpdatedUser.ID, &retVal.UpdatedUser.UUID, &retVal.UpdatedUser.Name, &retVal.Active)
return retVal, errors.Wrap(err)
}
// parseSet parses a result set result to an entity array
func (c *organizationRepo) parseTypeSet(rows *sql.Rows, err error) ([]entity.OrganizationType, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.OrganizationType, 0)
for rows.Next() {
entity, err := c.parseTypeEntity(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 *organizationRepo) parseTypeEntity(row scanner) (retVal entity.OrganizationType, err error) {
err = row.Scan(
&retVal.ID, &retVal.Name, &retVal.Key, &retVal.Description, &retVal.Created, &retVal.Updated)
return retVal, errors.Wrap(err)
}
func (c *organizationRepo) GetAllTypes() ([]entity.OrganizationType, error) {
return c.parseTypeSet(c.conn.Query(c.getTypeQuery()))
}
func (c *organizationRepo) GetTypeByKey(key string) (entity.OrganizationType, error) {
return c.parseTypeEntity(c.conn.QueryRow(c.getTypeQuery()+" WHERE organization_type_key=?", key))
}
func (c *organizationRepo) GetByType(organizationTypeKey string) ([]entity.Organization, error) {
if organizationTypeKey == "" {
return c.parseSet(c.conn.Query(c.getQuery()))
} else {
return c.parseSet(c.conn.Query(c.getQuery()+" WHERE b.organization_type_key = ? ", organizationTypeKey))
}
}
func (c *organizationRepo) GetByName(name string, searchType string) ([]entity.Organization, error) {
finalQuery := c.getQuery() + " WHERE a.organization_name LIKE ?"
switch searchType {
case "parent":
finalQuery += " AND a.organization_parent_id > 0; "
case "child":
finalQuery += " AND a.organization_parent_id = 0; "
}
name = "%" + name + "%"
fmt.Println(finalQuery)
return c.parseSet(c.conn.Query(finalQuery, name))
}
func (c *organizationRepo) GetByUUID(organizationUUID string) (entity.Organization, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE a.organization_uuid = ? ", organizationUUID))
}
func (c *organizationRepo) GetByID(organizationID int64) (entity.Organization, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE a.organization_id = ? ", organizationID))
}
func (c *organizationRepo) GetChildsByID(organizationID int64) ([]entity.Organization, error) {
return c.parseSet(c.conn.Query(c.getQuery()+" WHERE a.organization_parent_id = ? ", organizationID))
}
func (c *organizationRepo) GetContactsByOrganizationUUID(organizationUUID string) ([]entity.OrganizationContact, error) {
return c.parseContactSet(c.conn.Query(c.getContactQuery()+" WHERE a.active = 1 AND c.organization_uuid = ? ", organizationUUID))
}
func (c *organizationRepo) GetContactsByOrganizationID(organizationID int64) ([]entity.OrganizationContact, error) {
return c.parseContactSet(c.conn.Query(c.getContactQuery()+" WHERE a.active = 1 AND c.organization_id = ? ", organizationID))
}
func (c *organizationRepo) GetContactsByUUID(contactUUID string) (entity.OrganizationContact, error) {
return c.parseContactEntity(c.conn.QueryRow(c.getContactQuery()+" WHERE a.organization_contact_uuid = ? ", contactUUID))
}
func (c *organizationRepo) GetAddressByOrganizationUUID(organizationUUID string) ([]entity.OrganizationAddress, error) {
return c.parseAddressSet(c.conn.Query(c.getAddressQuery()+" WHERE a.active = 1 AND b.organization_uuid = ? ", organizationUUID))
}
func (c *organizationRepo) GetAddressByOrganizationID(organizationID int64) ([]entity.OrganizationAddress, error) {
return c.parseAddressSet(c.conn.Query(c.getAddressQuery()+" WHERE a.active = 1 AND b.organization_id = ? ", organizationID))
}
func (c *organizationRepo) GetAddressByUUID(contactUUID string) (entity.OrganizationAddress, error) {
return c.parseAddressEntity(c.conn.QueryRow(c.getAddressQuery()+" WHERE a.organization_address_uuid = ? ", contactUUID))
}
func (c *organizationRepo) SetParentOrganization(organizationID int64, parentOrganizationID int64) error {
const (
query = `UPDATE tab_organization SET organization_parent_id = ? WHERE organization_id = ?;`
)
_, err := c.conn.Exec(query, parentOrganizationID, organizationID)
if err != nil {
return err
} else {
return nil
}
}
func (c *organizationRepo) InactivateOrganizationAddress(address entity.OrganizationAddress) error {
const (
query = "UPDATE tab_organization_address SET active = 0, updated = CURRENT_TIMESTAMP, updated_user_id = ? WHERE organization_id = ? and organization_address_uuid = ?"
)
if address.Organization == nil {
return errors.NewNotFoundError()
}
organization, err := c.GetByUUID(address.Organization.UUID)
if err != nil {
return err
}
_, err = c.conn.Exec(query, address.UpdatedUser.ID, organization.ID, address.UUID)
if err != nil {
return err
} else {
return nil
}
}
func (c *organizationRepo) SetOrganizationAddress(address entity.OrganizationAddress) (entity.OrganizationAddress, error) {
const (
query = "INSERT INTO tab_organization_address(organization_address_uuid, organization_id, internal_id, `name`, address, `desc`, lat, `long`, created_user_id, updated_user_id) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
)
if address.Organization == nil {
return entity.OrganizationAddress{}, errors.NewNotFoundError()
}
organization, err := c.GetByUUID(address.Organization.UUID)
if err != nil {
return entity.OrganizationAddress{}, err
}
UUID, _ := uuid.NewV4()
result, err := c.conn.Exec(query, UUID.String(), organization.ID, address.InternalID, address.Name, address.Address, address.Description, address.Latitude, address.Longitude, address.CreatedUser.ID, address.UpdatedUser.ID)
if err != nil {
return entity.OrganizationAddress{}, err
}
address.ID, err = result.LastInsertId()
if err != nil {
return address, err
}
return address, nil
}
func (c *organizationRepo) InactivateOrganizationContact(contact entity.OrganizationContact) error {
const (
query = "UPDATE tab_organization_contact SET active = 0, updated = CURRENT_TIMESTAMP, updated_user_id = ? WHERE organization_id = ? and organization_contact_uuid = ?"
)
if contact.Organization == nil {
return errors.NewNotFoundError()
}
organization, err := c.GetByUUID(contact.Organization.UUID)
if err != nil {
return err
}
_, err = c.conn.Exec(query, contact.UpdatedUser.ID, organization.ID, contact.UUID)
if err != nil {
return err
} else {
return nil
}
}
func (c *organizationRepo) SetOrganizationContact(contact entity.OrganizationContact) (entity.OrganizationContact, error) {
const (
selectQuery = "SELECT a.contact_type_id, a.name, a.key FROM tab_contact_type a WHERE a.key = ?"
query = "INSERT INTO tab_organization_contact(organization_contact_uuid, organization_id, contact_type_id, contact, contact_name, contact_desc, created_user_id, updated_user_id) VALUES(?, ?, ?, ?, ?, ?, ?, ?);"
)
if contact.Organization == nil {
return entity.OrganizationContact{}, errors.NewNotFoundError()
}
organization, err := c.GetByUUID(contact.Organization.UUID)
if err != nil {
return entity.OrganizationContact{}, err
}
row := c.conn.QueryRow(selectQuery, contact.Type.Key)
err = row.Scan(&contact.Type.ID, &contact.Type.Value, &contact.Type.Key)
if err != nil {
return entity.OrganizationContact{}, err
}
UUID, _ := uuid.NewV4()
result, err := c.conn.Exec(query, UUID.String(), organization.ID, contact.Type.ID, contact.Contact, contact.Name, contact.Description, contact.CreatedUser.ID, contact.UpdatedUser.ID)
if err != nil {
return entity.OrganizationContact{}, err
}
contact.ID, err = result.LastInsertId()
if err != nil {
return contact, err
}
return contact, nil
}
func (c *organizationRepo) AddOrganization(organization entity.Organization) (entity.Organization, error) {
const (
queryOrgType = "SELECT a.organization_type_id FROM tab_organization_type a WHERE a.organization_type_key = ?;"
queryParentOrg = "SELECT a.organization_id FROM tab_organization a WHERE a.organization_uuid = ?;"
query = "INSERT INTO tab_organization(organization_uuid, organization_type_id, organization_name, organization_description, organization_reference_id, organization_parent_id, main_organization, created_user, updated_user) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?);"
)
row := c.conn.QueryRow(queryOrgType, organization.Type.Key)
err := row.Scan(&organization.Type.ID)
if err != nil {
return entity.Organization{}, err
}
if organization.Parent != nil && organization.Parent.UUID != "" {
row := c.conn.QueryRow(queryParentOrg, organization.Parent.UUID)
err := row.Scan(&organization.Parent.ID)
if err != nil {
return entity.Organization{}, err
}
organization.ParentID = organization.Parent.ID
}
UUID, _ := uuid.NewV4()
organization.UUID = UUID.String()
result, err := c.conn.Exec(query, organization.UUID, organization.Type.ID, organization.Name, organization.Description, organization.ReferenceID, organization.ParentID, false, organization.Author.ID, organization.LastEditor.ID)
if err != nil {
return entity.Organization{}, err
}
ID, err := result.LastInsertId()
if err != nil {
return entity.Organization{}, err
}
organization.ID = ID
if len(organization.Addresses) > 0 {
for i, a := range organization.Addresses {
a.Organization = &organization
address, err := c.SetOrganizationAddress(a)
if err != nil {
fmt.Println("Error to save addresses")
return entity.Organization{}, err
}
organization.Addresses[i] = address
}
}
if len(organization.Contacts) > 0 {
for i, ct := range organization.Contacts {
ct.Organization = &organization
contact, err := c.SetOrganizationContact(ct)
if err != nil {
fmt.Println("Error to save contacts")
return entity.Organization{}, err
}
organization.Contacts[i] = contact
}
}
return organization, nil
}

77
data/datamysql/profile.go Normal file
View File

@@ -0,0 +1,77 @@
package datamysql
import (
"database/sql"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
// rideRepo maps methods to database
type profileRepo struct {
conn executor
}
func newProfileRepo(conn executor) *profileRepo {
return &profileRepo{
conn: conn,
}
}
func (c *profileRepo) getQuery() string {
const (
query = `SELECT
a.profile_id,
a.name,
a.key,
a.description,
a.create_time,
a.update_time,
(a.active = b'1') active,
(a.visible = b'1') visible
FROM
tab_profile a `
)
return query
}
// parseSet parses a result set result to an entity array
func (c *profileRepo) parseSet(rows *sql.Rows, err error) ([]entity.Profile, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Profile, 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 *profileRepo) parseEntity(row scanner) (retVal entity.Profile, err error) {
err = row.Scan(
&retVal.ID, &retVal.Name, &retVal.Key, &retVal.Description, &retVal.Created, &retVal.Updated, &retVal.Active, &retVal.Visible)
return retVal, errors.Wrap(err)
}
func (c *profileRepo) GetAll() ([]entity.Profile, error) {
return c.parseSet(c.conn.Query(c.getQuery()))
}
func (c *profileRepo) GetByKey(key string) (entity.Profile, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+"WHERE a.active = 1 AND a.key = ?", key))
}
func (c *profileRepo) GetVisibles(visible bool) ([]entity.Profile, error) {
return c.parseSet(c.conn.Query(c.getQuery()+"WHERE a.active = 1 AND a.visible = ?", visible))
}
func (c *profileRepo) GetByOrganizationType(organizationTypeID int64) ([]entity.Profile, error) {
return c.parseSet(c.conn.Query(c.getQuery()+" INNER JOIN tab_organization_type_profile b ON a.profile_id = b.profile_id WHERE a.active = 1 AND a.visible = 1 AND b.organization_type_id = ?", organizationTypeID))
}

421
data/datamysql/provider.go Normal file
View File

@@ -0,0 +1,421 @@
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,
a.provider_internal_id_suffix,
a.provider_muk_id,
a.organization_name,
a.gender,
a.accept_new_patients,
a.provider_name,
a.first_name,
a.last_name,
a.middle_name,
a.provider_title,
a.street_name1,
a.street_name2,
a.city_name,
a.state,
a.zipcode,
a.country,
a.latitude,
a.longitude,
a.phone_number,
a.create_at,
a.update_at,
a.active,
a.enabled,
a.created_user,
(3959 * acos (
cos ( radians(?) )
* cos( radians( a.latitude ) )
* cos( radians( a.longitude ) - radians(?) )
+ sin ( radians(?) )
* sin( radians( a.latitude ) )
)) 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) 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) 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)
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
}

826
data/datamysql/ride.go Normal file
View File

@@ -0,0 +1,826 @@
package datamysql
import (
"database/sql"
"fmt"
"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 rideRepo struct {
conn executor
}
func newRideRepo(conn executor) *rideRepo {
return &rideRepo{
conn: conn,
}
}
func (c *rideRepo) getQuery() string {
const query = `SELECT
a.ride_id,
a.ride_uuid,
b.user_id,
b.user_uuid,
b.name,
b.member,
c.ride_status_id,
c.ride_status,
c.key ride_status_key,
d.ride_type_id,
d.value ride_type,
d.key ride_type_key,
a.notes,
e.first_name,
e.last_name,
e.image_url,
e.phone_number,
e.internal_user_id,
IFNULL(f.name, '') driver_name,
IFNULL(f.phone_number, '') driver_phone_number,
IFNULL(f.image_url, '') driver_image_url,
IFNULL(f.rating, '') driver_rating,
IFNULL(g.color, '') vehicle_color,
IFNULL(g.image_url, '') vehicle_image_url,
IFNULL(g.license_plate, '') vehicle_license_plate,
IFNULL(g.license_plate_state, '') vehicle_license_state,
IFNULL(g.make, '') vehicle_make,
IFNULL(g.model, '') vehicle_model,
IFNULL(g.year, 0) vehicle_year,
h.origin_name,
h.origin_address,
h.origin_lat,
h.origin_lng,
h.destination_name,
h.destination_address,
h.destination_lat,
h.destination_lng,
IFNULL(h.route_kml, '') route_kml,
IFNULL(h.distance, 0) distance,
IFNULL(h.duration, 0) duration,
IFNULL(h.eta, 0) eta,
a.pickup_time,
a.visit_date,
a.visit_time,
a.ride_internal_id,
a.visit_id,
i.visit_uuid,
IFNULL(i.pickup_id, '') visit_pickup_id,
IFNULL(i.pickup_address_id, 0) pickup_address_id,
IFNULL(i.address_id, 0) address_id,
IFNULL(i.provider_id, 0) provider_id,
IFNULL(o.provider_uuid, '') provider_uuid,
IFNULL(o.provider_internal_id, '') provider_internal_id,
IFNULL(o.provider_muk_id, '') provider_muk_id,
IFNULL(o.provider_name, '') provider_name,
-- i.pickup_name visit_pickup_name,
-- i.pickup_address visit_pickup_address,
-- i.pickup_lat visit_pickup_lat,
-- i.pickup_lng visit_pickup_lng,
-- IFNULL(i.destination_id, '') visit_destination_id,
-- i.destination_name visit_destination_name,
-- i.destination_address visit_destination_address,
-- i.destination_lat visit_destination_lat,
-- i.destination_lng visit_destination_lng,
IFNULL(i.visit_external_id, '') visit_external_id,
i.created_user_id,
j.user_uuid created_user_uuid,
j.name created_name,
IFNULL(k.phone_number, '') created_user_phone_number,
IFNULL(k.email, '') created_user_email,
IFNULL(l.phone_number, '') user_phone_number,
IFNULL(l.email, '') user_email,
a.create_date,
a.update_date,
m.trip_type_id,
m.trip_type_key,
m.trip_type,
n.trip_type_id visit_trip_type_id,
n.trip_type_key visit_trip_type_key,
n.trip_type visit_trip_type_key,
i.return_date
FROM tab_ride a
INNER JOIN tab_user b
ON a.user_id = b.user_id
INNER JOIN tab_ride_status c
ON c.ride_status_id = a.ride_status_id
INNER JOIN tab_ride_type d
ON d.ride_type_id = a.ride_type_id
INNER JOIN tab_ride_passenger e
ON e.ride_id = a.ride_id
LEFT JOIN tab_ride_driver f
ON f.ride_id = a.ride_id
LEFT JOIN tab_ride_vehicle g
ON g.ride_id = a.ride_id
INNER JOIN tab_ride_route h
ON h.ride_id = a.ride_id
INNER JOIN tab_visit i
ON i.visit_id = a.visit_id
INNER JOIN tab_user j
ON j.user_id = i.created_user_id
INNER JOIN tab_login k
ON k.user_id = j.user_id
INNER JOIN tab_login l
ON l.user_id = a.user_id
INNER JOIN tab_trip_type m
ON m.trip_type_id = a.trip_type_id
INNER JOIN tab_trip_type n
ON n.trip_type_id = i.trip_type_id
INNER JOIN tab_provider o
ON i.provider_id = o.provider_id `
return query
}
func (c *rideRepo) 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_visit_provider o ON a.ride_id = o.ride_id`
where = fmt.Sprintf(` AND (o.organization_uuid = '%s' OR o.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 *rideRepo) Update(hook entity.WebhookResponse, user entity.User) (retVal entity.Ride, err error) {
oldRide, err := c.GetByUUID(hook.Ride.UUID, user)
if err != nil {
return retVal, err
}
retVal, err = c.updateHeader(hook.Ride)
if err != nil {
return retVal, err
}
retVal, err = c.updateLocation(hook.Ride)
if err != nil {
return retVal, err
}
// retVal, err = c.updatePassenger(hook.Ride)
// if err != nil {
// return retVal, err
// }
if oldRide.Driver.Name != "" {
retVal, err = c.updateDriver(hook.Ride)
} else {
retVal, err = c.saveDriver(hook.Ride)
}
if err != nil {
return retVal, err
}
if oldRide.Vehicle.LicensePlate != "" {
retVal, err = c.updateVehicle(hook.Ride)
} else {
retVal, err = c.saveVehicle(hook.Ride)
}
if err != nil {
return retVal, err
}
go func() {
err := c.saveHistory(hook)
if err != nil {
fmt.Println("Error to save history: " + err.Error())
}
}()
return retVal, nil
}
func (c *rideRepo) updateVehicle(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = `UPDATE tab_ride_vehicle
SET
color = ?,
image_url = ?,
license_plate = ?,
license_plate_state = ?,
make = ?,
model = ?,
year = ?
WHERE ride_id = ?;`
)
retVal = ride
_, err = c.conn.Exec(query, ride.Vehicle.Color, ride.Vehicle.ImageURL, ride.Vehicle.LicensePlate, ride.Vehicle.LicensePlateState, ride.Vehicle.Make, ride.Vehicle.Model, ride.Vehicle.Year, ride.ID)
if err != nil {
return retVal, err
}
return retVal, nil
}
func (c *rideRepo) updateDriver(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = `UPDATE tab_ride_driver
SET
name = ?,
image_url = ?,
phone_number = ?,
rating = ?
WHERE ride_id = ?;`
)
retVal = ride
_, err = c.conn.Exec(query, ride.Driver.Name, ride.Driver.ImageURL, ride.Driver.PhoneNumber, ride.Driver.Rating, ride.ID)
if err != nil {
return retVal, err
}
return retVal, nil
}
func (c *rideRepo) updatePassenger(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = `UPDATE tab_ride_passenger
SET
first_name = ?,
last_name = ?,
image_url = ?,
phone_number = ?,
internal_user_id = ?
WHERE ride_id = ?;`
)
retVal = ride
_, err = c.conn.Exec(query, ride.Passenger.FirstName, ride.Passenger.LastName, ride.Passenger.ImageURL, ride.Passenger.PhoneNumber, ride.Passenger.InternalID, ride.ID)
if err != nil {
return retVal, err
}
return retVal, nil
}
func (c *rideRepo) updateLocation(ride entity.Ride) (retVal entity.Ride, err error) {
query := `UPDATE tab_ride_route
SET
origin_address = ?,
origin_lat = ?,
origin_lng = ?,
destination_address = ?,
destination_lat = ?,
destination_lng = ?,
route_kml = ?,
distance = ?,
duration = ?,
eta = ?`
where := ` WHERE ride_id = ?;`
retVal = ride
params := make([]interface{}, 0)
params = append(params, ride.Route.Origin.Address, ride.Route.Origin.Latitude, ride.Route.Origin.Longitude, ride.Route.Destination.Address, ride.Route.Destination.Latitude, ride.Route.Destination.Longitude, ride.Route.RouteKML, ride.Route.Distance, ride.Route.Duration, ride.Route.ETA)
if retVal.Route.Origin.Name != "" {
query += " , origin_name = ? "
params = append(params, ride.Route.Origin.Name)
}
if retVal.Route.Destination.Name != "" {
query += " , destination_name = ? "
params = append(params, ride.Route.Destination.Name)
}
params = append(params, ride.ID)
_, err = c.conn.Exec(query+where, params...)
if err != nil {
return retVal, err
}
return retVal, nil
}
func (c *rideRepo) updateHeader(ride entity.Ride) (retVal entity.Ride, err error) {
const (
statusQuery = "SELECT ride_status_id FROM tab_ride_status WHERE `key` = ?"
query = `UPDATE tab_ride
SET
ride_status_id = ?,
ride_type_id = ?,
ride_internal_id = ?,
request_date = ?,
request_ms = ?,
generate_date = ?,
generate_ms = ?,
route_kml = ?,
notes = ?,
primetime_percentage = ?,
pickup_time = ?,
visit_date = ?,
visit_time = ?,
visit_id = ?
WHERE ride_uuid = ?;`
)
row := c.conn.QueryRow(statusQuery, ride.Status.Key)
err = row.Scan(&ride.Status.ID)
if err != nil {
fmt.Println("Error to get status")
return retVal, err
}
retVal = ride
_, err = c.conn.Exec(query, ride.Status.ID, ride.Type.ID, ride.InternalID, ride.RequestDate, ride.RequestMiliseconds, ride.GenerateDate, ride.GenerateMiliseconds, ride.Route.RouteKML, ride.Note, ride.PrimetimePercentage, ride.PickupTime, ride.VisitDate, ride.VisitTime, ride.Visit.ID, ride.UUID)
if err != nil {
return retVal, err
}
return ride, nil
}
func (c *rideRepo) Save(ride entity.Ride) (retVal entity.Ride, err error) {
retVal, err = c.saveHeader(ride)
if err != nil {
fmt.Println("Error to save header")
return retVal, err
}
retVal, err = c.saveLocation(retVal)
if err != nil {
fmt.Println("Error to save location")
return retVal, err
}
retVal, err = c.savePassenger(retVal)
if err != nil {
fmt.Println("Error to save passenger")
return retVal, err
}
retVal, err = c.saveDriver(retVal)
if err != nil {
fmt.Println("Error to save driver")
return retVal, err
}
retVal, err = c.saveVehicle(retVal)
if err != nil {
fmt.Println("Error to save vehicle")
return retVal, err
}
go func() {
hook := entity.WebhookResponse{
Ride: retVal,
}
err = c.saveHistory(hook)
if err != nil {
fmt.Println("Error to save history: ", err.Error())
}
}()
return retVal, err
}
func (c *rideRepo) saveHistory(hook entity.WebhookResponse) error {
rideHistoryID, err := c.saveHistoryHeader(hook)
if err != nil {
fmt.Println("Error to save header history")
return err
}
if err = c.saveLocationHistory(rideHistoryID, hook.Ride.Route); err != nil {
fmt.Println("Error to save location history")
return err
}
if err = c.savePassengerHistory(rideHistoryID, hook.Ride.Passenger); err != nil {
fmt.Println("Error to save passenger history")
return err
}
if err = c.saveDriverHistory(rideHistoryID, hook.Ride.Driver); err != nil {
fmt.Println("Error to save driver history")
return err
}
if err = c.saveVehicleHistory(rideHistoryID, hook.Ride.Vehicle); err != nil {
fmt.Println("Error to save vehicle history")
return err
}
return nil
}
func (c *rideRepo) saveVehicleHistory(rideHistoryID int64, vehicle entity.RideVehicle) error {
const (
query = "INSERT INTO tab_ride_vehicle_history(ride_history_id,color,image_url,license_plate,license_plate_state,make,model,`year`) VALUES(?,?,?,?,?,?,?,?);"
)
if vehicle.Make != "" && vehicle.Model != "" && vehicle.Color != "" && vehicle.Year > 0 {
_, err := c.conn.Exec(query, rideHistoryID, vehicle.Color, vehicle.ImageURL, vehicle.LicensePlate, vehicle.LicensePlateState, vehicle.Make, vehicle.Model, vehicle.Year)
if err != nil {
return err
}
}
return nil
}
func (c *rideRepo) saveDriverHistory(rideHistoryID int64, driver entity.RideDriver) error {
const (
query = "INSERT INTO tab_ride_driver_history(ride_history_id,name,image_url,phone_number,rating) VALUES(?,?,?,?,?);"
)
if driver.Name != "" && driver.PhoneNumber != "" {
_, err := c.conn.Exec(query, rideHistoryID, driver.Name, driver.ImageURL, driver.PhoneNumber, driver.Rating)
if err != nil {
return err
}
}
return nil
}
func (c *rideRepo) savePassengerHistory(rideHistoryID int64, passenger entity.RidePassenger) error {
const (
query = "INSERT INTO tab_ride_passenger_history(ride_history_id,first_name,last_name,image_url,phone_number,internal_user_id) VALUES(?,?,?,?,?,?)"
)
_, err := c.conn.Exec(query, rideHistoryID, passenger.FirstName, passenger.LastName, "", passenger.PhoneNumber, passenger.InternalID)
if err != nil {
return err
}
return nil
}
func (c *rideRepo) saveLocationHistory(rideHistoryID int64, route entity.RideRoute) error {
const (
query = `INSERT INTO tab_ride_route_history(ride_history_id,origin_name,origin_address,origin_lat,origin_lng,destination_name,destination_address,destination_lat,destination_lng,route_kml,distance,duration,eta)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?);`
)
if route.Origin.Latitude != 0 && route.Origin.Longitude != 0 && route.Destination.Latitude != 0 && route.Destination.Longitude != 0 {
_, err := c.conn.Exec(query, rideHistoryID, route.Origin.Name, route.Origin.Address, route.Origin.Latitude, route.Origin.Longitude, route.Destination.Name, route.Destination.Address, route.Destination.Latitude, route.Destination.Longitude, route.RouteKML, route.Distance, route.Duration, route.ETA)
if err != nil {
return err
}
}
return nil
}
func (c *rideRepo) saveHistoryHeader(hook entity.WebhookResponse) (int64, error) {
const (
query = `INSERT INTO tab_ride_history(ride_history_uuid,ride_id,event_id,href,occurred_at,event_type,ride_internal_id,ride_status_id,ride_type_id,request_date,request_ms,generate_date,generate_ms,route_kml,notes, primetime_percentage, pickup_time, visit_date, visit_time, visit_id)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);`
)
UUID, _ := uuid.NewV4()
sUUID := UUID.String()
if hook.OccurredAt.IsZero() {
hook.OccurredAt = time.Now()
}
results, err := c.conn.Exec(query, sUUID, hook.Ride.ID, hook.EventID, hook.HREF, hook.OccurredAt, hook.EventType, hook.Ride.InternalID, hook.Ride.Status.ID, hook.Ride.Type.ID, hook.Ride.RequestDate, hook.Ride.RequestMiliseconds, hook.Ride.GenerateDate, hook.Ride.GenerateMiliseconds, hook.Ride.Route.RouteKML, hook.Ride.Note, hook.Ride.PrimetimePercentage, hook.Ride.PickupTime, hook.Ride.VisitDate, hook.Ride.VisitTime, hook.Ride.Visit.ID)
if err != nil {
return 0, err
}
return results.LastInsertId()
}
func (c *rideRepo) saveHeader(ride entity.Ride) (retVal entity.Ride, err error) {
const (
dataQuery = `SELECT
a.user_id user_id,
a.name,
a.member,
b.ride_status_id,
b.ride_status,
c.ride_type_id,
c.value ride_type,
d.user_id created_user_id,
d.name created_name,
IFNULL(d.member, '') created_member,
e.trip_type_id,
e.trip_type_key,
e.trip_type
FROM tab_user a,
tab_ride_status b,
tab_ride_type c,
tab_user d,
tab_trip_type e
WHERE
a.user_uuid = ?
AND b.key = ?
AND c.key = ?
AND d.user_uuid = ?
AND e.trip_type_key = ?;`
query = `INSERT INTO tab_ride(ride_uuid, user_id, ride_status_id, ride_type_id, ride_internal_id, request_date, request_ms, generate_date, generate_ms, notes, primetime_percentage, pickup_time, visit_date, visit_time, visit_id, created_user_id, trip_type_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`
)
retVal = ride
UUID, _ := uuid.NewV4()
retVal.UUID = UUID.String()
if retVal.Status.Key == "" {
retVal.Status.Key = "accepted"
}
if retVal.Type.Key == "" {
retVal.Type.Key = "lyft"
}
row := c.conn.QueryRow(dataQuery, retVal.User.UUID, retVal.Status.Key, retVal.Type.Key, retVal.CreatedUser.UUID, retVal.TripType.Key)
if err = row.Scan(&retVal.User.ID, &retVal.User.Name, &retVal.User.Member, &retVal.Status.ID, &retVal.Status.Value, &retVal.Type.ID, &retVal.Type.Value, &retVal.CreatedUser.ID, &retVal.CreatedUser.Name, &retVal.CreatedUser.Member, &retVal.TripType.ID, &retVal.TripType.Key, &retVal.TripType.Value); err != nil {
fmt.Println("Error to get base data: ", err.Error())
return retVal, err
}
results, err := c.conn.Exec(query, retVal.UUID, retVal.User.ID, retVal.Status.ID, retVal.Type.ID, retVal.InternalID, retVal.RequestDate, retVal.RequestMiliseconds, retVal.GenerateDate, retVal.GenerateMiliseconds, retVal.Note, retVal.PrimetimePercentage, retVal.PickupTime, retVal.VisitDate, retVal.VisitTime, retVal.Visit.ID, retVal.CreatedUser.ID, retVal.TripType.ID)
if err != nil {
fmt.Println("Error: ", err.Error())
return retVal, err
}
var ID int64
ID, err = results.LastInsertId()
if err != nil {
fmt.Println("Error Getting the ID: ", err.Error())
return retVal, err
}
retVal.ID = ID
return retVal, nil
}
func (c *rideRepo) saveLocation(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = `INSERT INTO tab_ride_route(ride_id,origin_name,origin_address,origin_lat,origin_lng,destination_name,destination_address,destination_lat,destination_lng,route_kml,distance,duration,eta)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?);`
)
retVal = ride
results, err := c.conn.Exec(query, retVal.ID, retVal.Route.Origin.Name, retVal.Route.Origin.Address, retVal.Route.Origin.Latitude, retVal.Route.Origin.Longitude, retVal.Route.Destination.Name, retVal.Route.Destination.Address, retVal.Route.Destination.Latitude, retVal.Route.Destination.Longitude, retVal.Route.RouteKML, retVal.Route.Distance, retVal.Route.Duration, retVal.Route.ETA)
if err != nil {
return retVal, err
}
var ID int64
ID, err = results.LastInsertId()
if err != nil {
fmt.Println("Error Getting the ID: ", err.Error())
return retVal, err
}
retVal.Route.ID = ID
return retVal, nil
}
func (c *rideRepo) savePassenger(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = `INSERT INTO tab_ride_passenger(ride_id,first_name,last_name,image_url,phone_number,internal_user_id)
VALUES(?,?,?,?,?,?);`
)
retVal = ride
results, err := c.conn.Exec(query, retVal.ID, ride.Passenger.FirstName, ride.Passenger.LastName, ride.Passenger.ImageURL, ride.Passenger.PhoneNumber, ride.Passenger.InternalID)
if err != nil {
return retVal, err
}
var ID int64
ID, err = results.LastInsertId()
if err != nil {
fmt.Println("Error Getting the ID: ", err.Error())
return retVal, err
}
retVal.Passenger.ID = ID
return retVal, nil
}
func (c *rideRepo) saveDriver(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = "INSERT INTO tab_ride_driver(ride_id,`name`,image_url,phone_number,rating) VALUES(?,?,?,?,?);"
)
retVal = ride
if retVal.Driver.Name != "" && retVal.Driver.PhoneNumber != "" {
results, err := c.conn.Exec(query, retVal.ID, ride.Driver.Name, ride.Driver.ImageURL, ride.Driver.PhoneNumber, ride.Driver.Rating)
if err != nil {
return retVal, err
}
var ID int64
ID, err = results.LastInsertId()
if err != nil {
fmt.Println("Error Getting the ID: ", err.Error())
return retVal, err
}
retVal.Driver.ID = ID
}
return retVal, nil
}
func (c *rideRepo) saveVehicle(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = "INSERT INTO tab_ride_vehicle(ride_id,color,image_url,license_plate,license_plate_state,make,model,`year`) VALUES(?,?,?,?,?,?,?,?);"
)
retVal = ride
if retVal.Vehicle.Color != "" && retVal.Vehicle.LicensePlate != "" && retVal.Vehicle.Make != "" && retVal.Vehicle.Model != "" && retVal.Vehicle.Year > 0 {
results, err := c.conn.Exec(query, retVal.ID, ride.Vehicle.Color, ride.Vehicle.ImageURL, ride.Vehicle.LicensePlate, ride.Vehicle.LicensePlateState, ride.Vehicle.Make, ride.Vehicle.Model, ride.Vehicle.Year)
if err != nil {
return retVal, err
}
var ID int64
ID, err = results.LastInsertId()
if err != nil {
fmt.Println("Error Getting the ID: ", err.Error())
return retVal, err
}
retVal.Vehicle.ID = ID
}
return retVal, nil
}
func (c *rideRepo) GetByUUID(uuid string, user entity.User) (entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Ride{}, err
}
query = c.getQuery() + query + " WHERE a.ride_uuid = ? " + where
return c.parseEntity(c.conn.QueryRow(query, uuid))
}
func (c *rideRepo) GetByID(id int64, user entity.User) (entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Ride{}, err
}
query = c.getQuery() + query + " WHERE a.ride_id = ? " + where
return c.parseEntity(c.conn.QueryRow(query, id))
}
func (c *rideRepo) GetByUUIDAndUserUUID(UUID string, userUUID string) (entity.Ride, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE a.ride_uuid = ? AND b.user_uuid = ?", UUID, userUUID))
}
func (c *rideRepo) GetLastRideByPhoneNumber(phoneNumber string) (entity.Ride, error) {
query := c.getQuery() + ` WHERE c.ride_status IN ('accepted', 'arrived', 'scheduled', 'pending')
AND l.phone_number = ?
ORDER BY a.create_date DESC
LIMIT 1;`
return c.parseEntity(c.conn.QueryRow(query, phoneNumber))
}
func (c *rideRepo) GetLastRideByDriversNumber(phoneNumber string) (entity.Ride, error) {
query := c.getQuery() + ` WHERE c.ride_status IN ('accepted', 'arrived', 'scheduled', 'pending')
AND IFNULL(f.phone_number, '') = ?
ORDER BY a.create_date DESC
LIMIT 1;`
return c.parseEntity(c.conn.QueryRow(query, phoneNumber))
}
func (c *rideRepo) GetByInternalID(internalID string) (entity.Ride, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE a.ride_internal_id = ?", internalID))
}
func (c *rideRepo) GetByInternalPassengerID(internalPassengerID string) (entity.Ride, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE e.internal_user_id = ?", internalPassengerID))
}
func (c *rideRepo) GetByUserID(userID int64, user entity.User) ([]entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getQuery() + query + " WHERE b.user_id = ? " + where
return c.parseSet(c.conn.Query(query, userID))
}
func (c *rideRepo) GetByUserUUID(userUUID string, user entity.User) ([]entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getQuery() + query + " WHERE b.user_uuid = ? " + where
return c.parseSet(c.conn.Query(query, userUUID))
}
func (c *rideRepo) GetByVisitUUID(visitUUID string, user entity.User) ([]entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getQuery() + query + " WHERE b.user_id = ? " + where
return c.parseSet(c.conn.Query(query, visitUUID))
}
func (c *rideRepo) GetByVisitUUIDAndTripType(visitUUID string, tripTypeKey string, user entity.User) (entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Ride{}, err
}
query = c.getQuery() + query + " WHERE i.visit_uuid = ? AND m.trip_type_key = ? " + where
return c.parseEntity(c.conn.QueryRow(query, visitUUID, tripTypeKey))
}
func (c *rideRepo) parseSet(rows *sql.Rows, err error) ([]entity.Ride, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Ride, 0)
for rows.Next() {
entity, err := c.parseEntity(rows)
if err != nil {
return nil, errors.Wrap(err)
}
result = append(result, entity)
}
return result, nil
}
func (c *rideRepo) parseEntity(row scanner) (r entity.Ride, err error) {
var returnDate mysql.NullTime
err = row.Scan(&r.ID, &r.UUID, &r.User.ID, &r.User.UUID, &r.User.Name, &r.User.Member, &r.Status.ID, &r.Status.Value, &r.Status.Key, &r.Type.ID, &r.Type.Value, &r.Type.Key, &r.Note, &r.Passenger.FirstName, &r.Passenger.LastName, &r.Passenger.ImageURL, &r.Passenger.PhoneNumber, &r.Passenger.InternalID, &r.Driver.Name, &r.Driver.PhoneNumber, &r.Driver.ImageURL, &r.Driver.Rating, &r.Vehicle.Color, &r.Vehicle.ImageURL, &r.Vehicle.LicensePlate, &r.Vehicle.LicensePlateState, &r.Vehicle.Make, &r.Vehicle.Model, &r.Vehicle.Year, &r.Route.Origin.Name, &r.Route.Origin.Address, &r.Route.Origin.Latitude, &r.Route.Origin.Longitude, &r.Route.Destination.Name, &r.Route.Destination.Address, &r.Route.Destination.Latitude, &r.Route.Destination.Longitude, &r.Route.RouteKML, &r.Route.Distance, &r.Route.Duration, &r.Route.ETA, &r.PickupTime, &r.VisitDate, &r.VisitTime, &r.InternalID, &r.Visit.ID, &r.Visit.UUID, &r.Visit.Pickup.ID, &r.Visit.PickupAddressID, &r.Visit.DestinationAddressID, &r.Visit.Provider.ProviderID, &r.Visit.Provider.ProviderUUID, &r.Visit.Provider.InternalID, &r.Visit.Provider.MukID, &r.Visit.Provider.Name, &r.Visit.ExternalID, &r.Visit.CreatedUser.ID, &r.Visit.CreatedUser.UUID, &r.Visit.CreatedUser.Name, &r.Visit.CreatedUser.PhoneNumber, &r.Visit.CreatedUser.Email, &r.User.PhoneNumber, &r.User.Email, &r.Created, &r.Updated, &r.TripType.ID, &r.TripType.Key, &r.TripType.Value, &r.Visit.TripType.ID, &r.Visit.TripType.Key, &r.Visit.TripType.Value, &returnDate)
if err != nil {
return r, errors.Wrap(err)
}
r.CreatedUser = r.Visit.CreatedUser
if returnDate.Valid {
r.Visit.ReturnDate = &returnDate.Time
}
return r, nil
}
func (c *rideRepo) UpdateStatus(rideUUID string, status string) error {
const (
statusQuery = "SELECT ride_status_id FROM tab_ride_status WHERE `key` = ?"
query = "UPDATE tab_ride SET ride_status_id = ? WHERE ride_uuid = ?"
)
var rideStatusID int64
row := c.conn.QueryRow(statusQuery, status)
err := row.Scan(&rideStatusID)
if err != nil {
return err
}
_, err = c.conn.Exec(query, rideStatusID, rideUUID)
if err != nil {
return err
}
return nil
}
func (c *rideRepo) GetAll(user entity.User) ([]entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getQuery() + query + " WHERE 1 = 1 AND b.active = 1 " + where
return c.parseSet(c.conn.Query(query))
}

View File

@@ -0,0 +1,87 @@
package datamysql
import (
"database/sql"
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
type transaction struct {
tx *sql.Tx
users *userRepo
rides *rideRepo
visits *visitRepo
provider *providerRepo
notification *notificationRepo
profile *profileRepo
organization *organizationRepo
}
func newTransaction(tx *sql.Tx) *transaction {
t := new(transaction)
t.tx = tx
t.users = newUserRepo(tx)
t.rides = newRideRepo(tx)
t.visits = newVisitRepo(tx)
t.provider = newProviderRepo(tx)
return t
}
// Users returns the users set
func (t transaction) Users() contract.UserRepo {
return t.users
}
// Rides returns the rides set
func (t transaction) Rides() contract.RideRepo {
return t.rides
}
// Rides returns the rides set
func (t transaction) Visits() contract.VisitRepo {
return t.visits
}
// Provider returns the rides set
func (t transaction) Provider() contract.ProviderRepo {
return t.provider
}
// Provider returns the rides set
func (t transaction) Profile() contract.ProfileRepo {
return t.profile
}
// Provider returns the rides set
func (t transaction) Notification() contract.NotificationRepo {
return t.notification
}
// Provider returns the rides set
func (t transaction) Organization() contract.OrganizationRepo {
return t.organization
}
func (t *transaction) Commit() error {
err := t.tx.Commit()
if err != nil {
return errors.Wrap(err)
}
return nil
}
func (t *transaction) Rollback() error {
err := t.tx.Rollback()
if err != nil {
return errors.Wrap(err)
}
return nil
}

825
data/datamysql/user.go Normal file
View File

@@ -0,0 +1,825 @@
package datamysql
import (
"database/sql"
"fmt"
"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"
)
// userRepo maps methods to database
type userRepo struct {
conn executor
}
func newUserRepo(conn executor) *userRepo {
return &userRepo{
conn: conn,
}
}
func (c *userRepo) GetByUUID(uuid string, profile string) (entity.User, error) {
params := make([]interface{}, 0)
params = append(params, uuid)
finalQuery := c.getQuery() + " AND a.user_uuid = ? "
if profile == "US" {
finalQuery += " AND e.key = ? "
params = append(params, profile)
}
user, err := c.parseSet(c.conn.Query(finalQuery, params...))
if err != nil {
return entity.User{}, err
}
if len(user) > 0 {
retVal := user[0]
retVal.Contacts, err = c.GetContacts(retVal.ID)
if err != nil {
return entity.User{}, err
}
retVal.Addresses = nil
retVal.Addresses, err = c.getAddressByUserID(retVal.ID)
if err != nil {
return entity.User{}, err
}
return retVal, nil
} else {
return entity.User{}, nil
}
}
func (c *userRepo) GetContacts(userID int64) ([]entity.ContactInfo, error) {
const (
query = `
SELECT
a.contact_id,
a.contact,
a.user_id,
b.contact_type_id,
b.key contact_type_key,
b.name contact_type_name
FROM tab_contact a
INNER JOIN tab_contact_type b
ON a.contact_type_id = b.contact_type_id
WHERE a.user_id = ?;
`
)
rows, err := c.conn.Query(query, userID)
if err != nil {
return nil, err
}
retVal := make([]entity.ContactInfo, 0)
for rows.Next() {
contact := entity.ContactInfo{}
err = rows.Scan(&contact.ID, &contact.Value, &contact.UserID, &contact.Type.ID, &contact.Type.Key, &contact.Type.Value)
if err != nil {
return nil, err
}
retVal = append(retVal, contact)
}
return retVal, nil
}
func (c *userRepo) GetUsersByProfile(profile string) ([]entity.User, error) {
query := c.getQuery()
if profile == "" {
query += "AND e.key <> 'US' "
return c.parseSet(c.conn.Query(query))
} else {
return c.parseSet(c.conn.Query(query+"AND e.key = ? AND a.active = 1 ", profile))
}
}
func (c *userRepo) parseSet(rows *sql.Rows, err error) ([]entity.User, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.User, 0)
var lastUser entity.User
for rows.Next() {
entity, err := c.parseEntity(rows)
if err != nil {
return nil, errors.Wrap(err)
}
if entity.UUID == lastUser.UUID {
lastUser.Profiles = append(lastUser.Profiles, entity.Profiles...)
} else {
if lastUser.UUID != "" {
result = append(result, lastUser)
}
lastUser = entity
}
}
result = append(result, lastUser)
return result, nil
}
func (c *userRepo) GetContactType() (retVal []entity.ContactType, err error) {
const (
query = `
SELECT
a.contact_type_id,
a.key,
a.name
FROM tab_contact_type a
WHERE a.visible = 1 `
)
rows, err := c.conn.Query(query)
if err != nil {
return nil, err
}
retVal = make([]entity.ContactType, 0)
for rows.Next() {
var contactType entity.ContactType
err = rows.Scan(&contactType.ID, &contactType.Key, &contactType.Value)
if err != nil {
return nil, err
}
retVal = append(retVal, contactType)
}
return retVal, nil
}
// parseEntity parses a result to an entity
func (c *userRepo) parseEntity(row scanner) (retVal entity.User, err error) {
var profile entity.Profile
var birthDate mysql.NullTime
var homeAddress entity.Address
var workAddress entity.Address
err = row.Scan(&retVal.ID, &retVal.UUID, &retVal.Name, &retVal.Member, &birthDate, &retVal.LoginID, &retVal.LoginUUID, &retVal.Email, &retVal.PhoneNumber, &retVal.LoginKey, &retVal.Gender, &retVal.Active, &retVal.Created, &retVal.Updated, &profile.ID, &profile.Name, &profile.Key, &profile.Active, &profile.Blocked, &profile.Suspended, &profile.Created, &profile.Updated, &profile.Organization.ID, &profile.Organization.UUID, &profile.Organization.Type.ID, &profile.Organization.Type.Name, &profile.Organization.Type.Key, &profile.Organization.Type.Description, &profile.Organization.Name, &profile.Organization.Description, &profile.Organization.ReferenceID, &profile.Organization.ParentID, &profile.Organization.Main,
&homeAddress.ID, &homeAddress.UUID, &homeAddress.AddressType.ID, &homeAddress.AddressType.Key, &homeAddress.AddressType.Name, &homeAddress.Name, &homeAddress.Address, &homeAddress.Latitude, &homeAddress.Longitude,
&workAddress.ID, &workAddress.UUID, &workAddress.AddressType.ID, &workAddress.AddressType.Key, &workAddress.AddressType.Name, &workAddress.Name, &workAddress.Address, &workAddress.Latitude, &workAddress.Longitude)
if err != nil {
if err != sql.ErrNoRows {
return retVal, errors.Wrap(err)
}
}
if birthDate.Valid {
retVal.BirthDate = birthDate.Time
}
retVal.Profiles = append(retVal.Profiles, profile)
if homeAddress.ID > 0 {
retVal.Addresses = append(retVal.Addresses, homeAddress)
}
if workAddress.ID > 0 {
retVal.Addresses = append(retVal.Addresses, workAddress)
}
return retVal, errors.Wrap(err)
}
func (c *userRepo) FullLogin(loginType string, key string, pass string, profile string) (user entity.User, err error) {
return c.login(loginType, key, pass, profile)
}
//Login return a user based on email and password with the default `User` profile
func (c *userRepo) Login(email string, pass string) (user entity.User, err error) {
return c.FullLogin("email", email, pass, "US")
}
func (c *userRepo) getQuery() string {
const (
query = `SELECT
a.user_id,
a.user_uuid,
a.name,
IFNULL(a.member, '') member,
a.birth_date,
b.login_id,
b.login_uuid,
IFNULL(b.email, '') email,
IFNULL(b.phone_number, '') phone_number,
b.key login_key,
IFNULL(a.gender, 'U') gender,
(IFNULL(a.active, b'0') = b'1') active,
a.create_time,
a.update_time,
e.profile_id,
e.name profile_name,
e.key profile_key,
(IFNULL(c.active, b'0') = b'1') profile_active,
(IFNULL(c.blocked, b'0') = b'1') profile_blocked,
(IFNULL(c.suspended, b'0') = b'1') profile_suspended,
c.create_date profile_createat,
c.update_date profile_updateat,
IFNULL(f.organization_id, 0) organization_id,
IFNULL(f.organization_uuid, '') organization_uuid,
IFNULL(f.organization_type_id, 0) organization_type_id,
IFNULL(g.organization_type, '') organization_type,
IFNULL(g.organization_type_key, '') organization_type_key,
IFNULL(g.description, '') organization_type_desc,
IFNULL(f.organization_name, '') organization_name,
IFNULL(f.organization_description, '') organization_desc,
IFNULL(f.organization_reference_id, 0) organization_reference_id,
IFNULL(f.organization_parent_id, 0) organization_parent_id,
(IFNULL(f.main_organization, b'0') = b'1') main_organization,
IFNULL(h.address_id, 0) home_address_id,
IFNULL(h.address_uuid, '') home_address_uuid,
IFNULL(h.address_type_id, 0) home_address_type_id,
IFNULL(h.address_type_key, '') home_address_type_key,
IFNULL(h.address_type_name, '') home_address_type_name,
IFNULL(h.name, '') home_name,
IFNULL(h.address, '') home_address,
IFNULL(h.lat, 0) home_lat,
IFNULL(h.long, 0) home_long,
IFNULL(i.address_id, 0) work_address_id,
IFNULL(i.address_uuid, '') work_address_uuid,
IFNULL(i.address_type_id, 0) work_address_type_id,
IFNULL(i.address_type_key, '') work_address_type_key,
IFNULL(i.address_type_name, '') work_address_type_name,
IFNULL(i.name, '') work_name,
IFNULL(i.address, '') work_address,
IFNULL(i.lat, 0) work_lat,
IFNULL(i.long, 0) work_long
FROM
tab_user a
INNER JOIN
tab_login b ON a.user_id = b.user_id
INNER JOIN
tab_profile_login c ON c.login_id = b.login_id
INNER JOIN
tab_profile e ON e.profile_id = c.profile_id
LEFT JOIN
tab_organization f ON f.organization_id = IFNULL(c.organization_id, 0)
LEFT JOIN
tab_organization_type g ON IFNULL(g.organization_type_id, 0) = IFNULL(f.organization_type_id, 0)
LEFT JOIN
viw_address_home h ON a.user_id = h.user_id
LEFT JOIN
viw_address_work i ON a.user_id = i.user_id
WHERE
a.active = b.active
AND b.active = c.active
AND c.active = e.active `
)
return query
}
func (c *userRepo) login(loginType string, key string, pass string, profile string) (user entity.User, err error) {
if loginType == "" {
return user, errors.NewNullArgumentError("loginType")
}
if loginType != "phone_number" && loginType != "email" {
return user, errors.NewValidationError("loginType", "invalid")
}
query := fmt.Sprintf(c.getQuery()+`
AND a.active = 1
AND b.%s = ?
AND b.password = sha2(?, 512) `, loginType)
users, err := c.parseSet(c.conn.Query(query, key, pass))
if err != nil {
return user, errors.Wrap(err)
}
return users[0], nil
}
func (c *userRepo) Create(user entity.User) (retVal entity.User, err error) {
retVal = user
if retVal.Member != "" {
retVal, err = c.getUserByMember(retVal)
if err != nil {
return retVal, err
}
}
if retVal.ID == 0 || retVal.Member == "" {
userID, guid, err := c.createUser(user)
if err != nil {
return retVal, err
}
retVal.UUID = guid
retVal.ID = userID
}
retVal, err = c.getUserLogin(retVal)
if err != nil {
return retVal, err
}
if retVal.LoginID == 0 {
loginID, loginGUID, err := c.createLogin(retVal)
if err != nil {
return retVal, err
}
retVal.LoginUUID = loginGUID
retVal.LoginID = loginID
}
for _, p := range user.Profiles {
companyProfileID, err := c.getCompanyProfile(p.Key)
if err != nil {
return retVal, err
}
if len(user.Organizations) > 0 {
for _, o := range user.Organizations {
err = c.addProfileToUser(retVal.LoginID, companyProfileID, o)
if err != nil {
return retVal, err
}
}
} else {
err = c.addProfileToUser(retVal.LoginID, companyProfileID, entity.Organization{})
if err != nil {
return retVal, err
}
}
}
if retVal.Email != "" {
contact := entity.ContactInfo{
Type: entity.ContactType{Key: "email"},
Value: retVal.Email,
UserID: retVal.ID,
}
contact, err = c.addContactInfo(contact)
if err != nil {
return retVal, err
}
}
if retVal.PhoneNumber != "" {
contact := entity.ContactInfo{
Type: entity.ContactType{Key: "phone"},
Value: retVal.PhoneNumber,
UserID: retVal.ID,
}
contact, err = c.addContactInfo(contact)
if err != nil {
return retVal, err
}
}
return c.GetByUUID(retVal.UUID, "")
}
func (c *userRepo) SaveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
return c.addContactInfo(contact)
}
func (c *userRepo) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
const (
query = `INSERT INTO tab_contact(contact_type_id, user_id, contact)
SELECT a.contact_type_id, ? user_id, ? contact
FROM
tab_contact_type a
LEFT JOIN tab_contact b
ON a.contact_type_id = b.contact_type_id
AND b.user_id = ?
AND b.contact = ?
WHERE a.key = ?
AND b.contact_id IS NULL;`
)
result, err := c.conn.Exec(query, contact.UserID, contact.Value, contact.UserID, contact.Value, contact.Type.Key)
if err != nil {
return contact, err
}
retVal := contact
retVal.ID, err = result.LastInsertId()
if err != nil {
return contact, err
}
return retVal, nil
}
func (c *userRepo) addContactInfo(contact entity.ContactInfo) (entity.ContactInfo, error) {
const (
query = `INSERT INTO tab_contact(contact_type_id, user_id, contact)
SELECT a.contact_type_id, ? user_id, ? contact
FROM
tab_contact_type a
LEFT JOIN tab_contact b
ON a.contact_type_id = b.contact_type_id
AND b.user_id = ?
AND b.contact = ?
WHERE a.key = ?
AND b.contact_id IS NULL;`
)
result, err := c.conn.Exec(query, contact.UserID, contact.Value, contact.UserID, contact.Value, contact.Type.Key)
if err != nil {
return contact, err
}
retVal := contact
retVal.ID, err = result.LastInsertId()
if err != nil {
return contact, err
}
return retVal, nil
}
func (c *userRepo) getUserByLoginAndProfile(loginID int64) (user entity.User, err error) {
finalQuery := c.getQuery() + " AND a.active = 1 AND b.login_Id = ? "
users, err := c.parseSet(c.conn.Query(finalQuery, loginID))
if err != nil {
return user, errors.Wrap(err)
}
return users[0], nil
}
func (c *userRepo) addProfileToUser(loginID int64, profileID int64, organization entity.Organization) error {
const query = "INSERT INTO tab_profile_login(profile_id, login_id, active, blocked, suspended, organization_id) VALUES(?, ?, 1, 0, 0, ?) ON DUPLICATE KEY UPDATE profile_id = ?, login_id = ?, organization_id = ?;"
const checkQuery = "SELECT COUNT(1) has_profile FROM tab_profile_login a WHERE a.login_id = ? AND a.profile_id = ? AND IFNULL(a.organization_id, 0) = ?;"
var total int64
row := c.conn.QueryRow(checkQuery, loginID, profileID, organization.ID)
err := row.Scan(&total)
if err != nil && err != sql.ErrNoRows {
return err
}
if total < 1 {
_, err := c.conn.Exec(query, profileID, loginID, organization.ID, profileID, loginID, toNullInt64(organization.ID))
if err != nil {
return err
}
}
return nil
}
func (c *userRepo) getUserByMember(u entity.User) (user entity.User, err error) {
user = u
users, err := c.parseSet(c.conn.Query(c.getQuery()+" AND a.active = 1 AND e.key = 'US' AND IFNULL(a.member, '') = ?;", u.Member))
if err != nil {
return user, errors.Wrap(err)
}
if users[0].ID != 0 {
user = users[0]
}
return user, nil
}
func (c *userRepo) getCompanyProfile(profile string) (int64, error) {
const (
query = "SELECT a.profile_id FROM tab_profile a WHERE a.key = ?;"
)
var companyProfileID int64
row := c.conn.QueryRow(query, profile)
err := row.Scan(&companyProfileID)
if err != nil {
return 0, err
}
return companyProfileID, nil
}
func (c *userRepo) getUserLogin(u entity.User) (user entity.User, err error) {
const (
query = "SELECT login_id, login_uuid, user_id, IFNULL(phone_number, '') phone_number, IFNULL(email, '') email, `key`, `password` FROM tab_login WHERE user_id = ?"
)
row := c.conn.QueryRow(query, user.Member)
err = row.Scan(&user.LoginID, &user.LoginUUID, &user.ID, &user.PhoneNumber, &user.Email, &user.LoginKey, &user.Pass)
if err != nil {
if err == sql.ErrNoRows {
return u, nil
} else {
return user, err
}
}
return user, nil
}
func (c *userRepo) createLogin(user entity.User) (int64, string, error) {
const (
query = "INSERT INTO tab_login (login_uuid, user_id, phone_number, email, `key`, `password`) VALUES(?, ?, ?, ?, ?, sha2(?, 512)) ON DUPLICATE KEY UPDATE login_uuid = ?, user_id = ?, phone_number = ?, email = ?, `key` = ?, `password` = sha2(?, 512);"
)
guid, _ := uuid.NewV4()
key, _ := uuid.NewV4()
result, err := c.conn.Exec(query, guid.String(), user.ID, toNullString(user.PhoneNumber), toNullString(user.Email), key.String(), user.Pass, guid.String(), user.ID, user.PhoneNumber, user.Email, key.String(), user.Pass)
if err != nil {
return 0, "", err
}
loginID, err := result.LastInsertId()
if err != nil {
return 0, "", err
}
return loginID, guid.String(), nil
}
func (c *userRepo) createUser(user entity.User) (int64, string, error) {
const (
query = "INSERT INTO tab_user(user_uuid, `name`, member, birth_date, gender) VALUES(?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE user_uuid = ?, `name` = ?, member = ?, birth_date = ?, gender = ?;"
)
guid, _ := uuid.NewV4()
result, err := c.conn.Exec(query, guid.String(), user.Name, toNullString(user.Member), toNullTime(user.BirthDate), toNullString(user.Gender), guid.String(), user.Name, toNullString(user.Member), toNullTime(user.BirthDate), toNullString(user.Gender))
if err != nil {
return 0, "", err
}
userID, err := result.LastInsertId()
if err != nil {
return 0, "", err
}
return userID, guid.String(), nil
}
func (c *userRepo) RemoveAddress(addressUUID string) error {
const (
query = "UPDATE tab_address SET active = 0 WHERE address_uuid = ?"
)
_, err := c.conn.Exec(query, addressUUID)
return err
}
func (c *userRepo) SaveAddress(address entity.Address) (entity.Address, error) {
const (
query = "INSERT INTO tab_address(address_uuid,address_type_id,address_origin_id,user_id,internal_id,`name`,address,lat,`long`,created_user_id) VALUES (?,?,?,?,?,?,?,?,?,?);"
)
address, err := c.getAddressSecondaryData(address)
if err != nil {
return address, err
}
uuid, _ := uuid.NewV4()
address.UUID = uuid.String()
result, err := c.conn.Exec(query, address.UUID, address.AddressType.ID, address.Origin.ID, address.User.ID, address.InternalID, address.Name, address.Address, address.Latitude, address.Longitude, address.CreatedUser.ID)
if err != nil {
return address, err
}
addressID, err := result.LastInsertId()
if err != nil {
return address, err
}
return c.getAddressByID(addressID)
}
func (c *userRepo) getAddressByUserID(userID int64) ([]entity.Address, error) {
const (
query = `SELECT
a.address_id,
a.address_uuid,
a.address_type_id,
d.key address_type_key,
d.name address_type_name,
a.address_origin_id,
e.key address_origin_key,
e.name address_origin_name,
b.user_id,
b.user_uuid,
b.name user_name,
a.internal_id,
a.name,
a.address,
a.lat,
a.long,
c.user_id created_user_id,
c.user_uuid created_user_uuid,
c.name created_user_name
FROM
tab_address a
INNER JOIN tab_user b
ON a.user_id = b.user_id
INNER JOIN tab_user c
ON a.created_user_id = c.user_id
INNER JOIN tab_address_type d
ON a.address_type_id = d.address_type_id
INNER JOIN tab_address_origin e
ON a.address_origin_id = e.address_origin_id
WHERE
a.user_id = ? and a.active = 1;`
)
var addresses []entity.Address
rows, err := c.conn.Query(query, userID)
if err != nil {
return nil, err
}
for rows.Next() {
var address entity.Address
err := rows.Scan(&address.ID, &address.UUID, &address.AddressType.ID, &address.AddressType.Key, &address.AddressType.Name,
&address.Origin.ID, &address.Origin.Key, &address.Origin.Name, &address.User.ID, &address.User.UUID, &address.User.Name,
&address.InternalID, &address.Name, &address.Address, &address.Latitude, &address.Longitude, &address.CreatedUser.ID,
&address.CreatedUser.UUID, &address.CreatedUser.Name)
if err != nil {
return nil, err
}
addresses = append(addresses, address)
}
return addresses, nil
}
func (c *userRepo) getAddressByID(addressID int64) (entity.Address, error) {
const (
query = `SELECT
a.address_id,
a.address_uuid,
a.address_type_id,
d.key address_type_key,
d.name address_type_name,
a.address_origin_id,
e.key address_origin_key,
e.name address_origin_name,
b.user_id,
b.user_uuid,
b.name user_name,
a.internal_id,
a.name,
a.address,
a.lat,
a.long,
c.user_id created_user_id,
c.user_uuid created_user_uuid,
c.name created_user_name
FROM
tab_address a
INNER JOIN tab_user b
ON a.user_id = b.user_id
INNER JOIN tab_user c
ON a.created_user_id = c.user_id
INNER JOIN tab_address_type d
ON a.address_type_id = d.address_type_id
INNER JOIN tab_address_origin e
ON a.address_origin_id = e.address_origin_id
WHERE
a.address_id = ?;`
)
var address entity.Address
row := c.conn.QueryRow(query, addressID)
err := row.Scan(&address.ID, &address.UUID, &address.AddressType.ID, &address.AddressType.Key, &address.AddressType.Name,
&address.Origin.ID, &address.Origin.Key, &address.Origin.Name, &address.User.ID, &address.User.UUID, &address.User.Name,
&address.InternalID, &address.Name, &address.Address, &address.Latitude, &address.Longitude, &address.CreatedUser.ID,
&address.CreatedUser.UUID, &address.CreatedUser.Name)
if err != nil {
return entity.Address{}, err
}
return address, nil
}
func (c *userRepo) GetAddressByUUID(addressUUID string) (entity.Address, error) {
const (
query = `SELECT
a.address_id,
a.address_uuid,
a.address_type_id,
d.key address_type_key,
d.name address_type_name,
a.address_origin_id,
e.key address_origin_key,
e.name address_origin_name,
b.user_id,
b.user_uuid,
b.name user_name,
a.internal_id,
a.name,
a.address,
a.lat,
a.long,
c.user_id created_user_id,
c.user_uuid created_user_uuid,
c.name created_user_name
FROM
tab_address a
INNER JOIN tab_user b
ON a.user_id = b.user_id
INNER JOIN tab_user c
ON a.created_user_id = c.user_id
INNER JOIN tab_address_type d
ON a.address_type_id = d.address_type_id
INNER JOIN tab_address_origin e
ON a.address_origin_id = e.address_origin_id
WHERE
a.address_uuid = ?;`
)
var address entity.Address
row := c.conn.QueryRow(query, addressUUID)
err := row.Scan(&address.ID, &address.UUID, &address.AddressType.ID, &address.AddressType.Key, &address.AddressType.Name,
&address.Origin.ID, &address.Origin.Key, &address.Origin.Name, &address.User.ID, &address.User.UUID, &address.User.Name,
&address.InternalID, &address.Name, &address.Address, &address.Latitude, &address.Longitude, &address.CreatedUser.ID,
&address.CreatedUser.UUID, &address.CreatedUser.Name)
if err != nil {
return entity.Address{}, err
}
return address, nil
}
func (c *userRepo) getAddressSecondaryData(address entity.Address) (entity.Address, error) {
const (
query = `SELECT
a.user_id,
a.user_uuid,
a.name user_name,
b.user_id created_user_id,
b.user_uuid created_user_uuid,
b.name created_user_name,
c.address_type_id,
c.key address_type_key,
c.name address_type_name,
d.address_origin_id,
d.key address_origin_key,
d.name address_origin_name
FROM
tab_user a,
tab_user b,
tab_address_type c,
tab_address_origin d
WHERE
a.user_uuid = ?
AND b.user_uuid = ?
AND c.key = ?
AND d.key = ?;`
)
row := c.conn.QueryRow(query, address.User.UUID, address.CreatedUser.UUID, address.AddressType.Key, address.Origin.Key)
err := row.Scan(&address.User.ID, &address.User.UUID, &address.User.Name, &address.CreatedUser.ID, &address.CreatedUser.UUID, &address.CreatedUser.Name, &address.AddressType.ID, &address.AddressType.Key, &address.AddressType.Name, &address.Origin.ID, &address.Origin.Key, &address.Origin.Name)
if err != nil {
return address, err
}
return address, nil
}
// GetAll returns a list of all active cards
func (c *userRepo) GetAll() (list []entity.User, err error) {
return c.parseSet(c.conn.Query(c.getQuery() + " WHERE a.active = 1 "))
}
// GetByID returns a single card data by its ID
func (c *userRepo) GetByID(userID int64) (retVal entity.User, err error) {
user, err := c.parseSet(c.conn.Query(c.getQuery()+" AND a.user_id = ? ", userID))
if err != nil {
return entity.User{}, err
}
if len(user) > 0 {
retVal := user[0]
retVal.Contacts, err = c.GetContacts(retVal.ID)
if err != nil {
return entity.User{}, err
}
retVal.Addresses = nil
retVal.Addresses, err = c.getAddressByUserID(retVal.ID)
if err != nil {
return entity.User{}, err
}
return retVal, nil
} else {
return retVal, nil
}
}
func toNullString(s string) sql.NullString {
return sql.NullString{String: s, Valid: s != ""}
}
func toNullInt64(i int64) sql.NullInt64 {
return sql.NullInt64{Int64: i, Valid: i > 0}
}
func toNullTime(date time.Time) mysql.NullTime {
return mysql.NullTime{Time: date, Valid: !date.IsZero()}
}

15
data/datamysql/utils.go Normal file
View File

@@ -0,0 +1,15 @@
package datamysql
import (
"database/sql"
)
type scanner interface {
Scan(dest ...interface{}) error
}
type executor interface {
Exec(query string, args ...interface{}) (sql.Result, error)
QueryRow(query string, args ...interface{}) *sql.Row
Query(query string, args ...interface{}) (*sql.Rows, error)
}

210
data/datamysql/visit.go Normal file
View File

@@ -0,0 +1,210 @@
package datamysql
import (
"database/sql"
"fmt"
"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"
)
// visitRepo maps methods to database
type visitRepo struct {
conn executor
}
func newVisitRepo(conn executor) *visitRepo {
return &visitRepo{
conn: conn,
}
}
func (c *visitRepo) 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_visit_provider f
ON f.visit_id = a.visit_id `
where = fmt.Sprintf(` AND (f.organization_uuid = '%s' OR f.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 *visitRepo) getQuery() string {
return `SELECT
a.visit_id,
a.visit_uuid,
a.visit_status_id,
b.visit_status_key,
b.visit_status,
a.user_id,
c.user_uuid,
c.name user_name,
c.member user_member,
c.birth_date user_birth_date,
c.gender user_gender,
a.visit_datetime,
a.pickup_datetime,
IFNULL(a.notes, '') notes,
a.created_user_id,
d.user_uuid created_user_uuid,
d.name created_user_name,
a.created_date,
a.updated_date,
IFNULL(a.visit_duration, 0) visit_duration,
a.visit_external_id,
e.trip_type_id,
e.trip_type_key,
e.trip_type,
IFNULL(a.pickup_id, '') visit_pickup_id,
IFNULL(a.pickup_address_id, 0) pickup_address_id,
IFNULL(a.address_id, 0) address_id,
IFNULL(a.provider_id, 0) provider_id,
IFNULL(f.provider_uuid, '') provider_uuid,
IFNULL(f.provider_internal_id, '') provider_internal_id,
IFNULL(f.provider_muk_id, '') provider_muk_id,
IFNULL(f.provider_name, '') provider_name
FROM
tab_visit a
INNER JOIN tab_visit_status b
ON a.visit_status_id = b.visit_status_id
INNER JOIN tab_user c
ON c.user_id = a.user_id
INNER JOIN tab_user d
ON d.user_id = a.created_user_id
INNER JOIN tab_trip_type e
ON e.trip_type_id = a.trip_type_id
INNER JOIN tab_provider f
ON f.provider_id = a.provider_id `
}
func (c *visitRepo) GetAll(user entity.User) ([]entity.Visit, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getQuery() + query + " WHERE 1 = 1 and c.active = 1 " + where
return c.parseSet(c.conn.Query(query))
}
func (c *visitRepo) GetByUUID(visitUUID string, user entity.User) (entity.Visit, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Visit{}, err
}
query = c.getQuery() + query + " WHERE a.visit_uuid = ? " + where
return c.parseEntity(c.conn.QueryRow(query, visitUUID))
}
func (c *visitRepo) GetByID(visitID int64, user entity.User) (entity.Visit, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Visit{}, err
}
query = c.getQuery() + query + " WHERE a.visit_id = ? " + where
return c.parseEntity(c.conn.QueryRow(query, visitID))
}
// parseSet parses a result set result to an entity array
func (c *visitRepo) parseSet(rows *sql.Rows, err error) ([]entity.Visit, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Visit, 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 *visitRepo) parseEntity(row scanner) (retVal entity.Visit, err error) {
var birthDate mysql.NullTime
var gender sql.NullString
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.Status.ID, &retVal.Status.Key, &retVal.Status.Value, &retVal.User.ID, &retVal.User.UUID, &retVal.User.Name, &retVal.User.Member, &birthDate, &gender, &retVal.VisitDatetime, &retVal.PickupDatetime, &retVal.Notes, &retVal.CreatedUser.ID, &retVal.CreatedUser.UUID, &retVal.CreatedUser.Name, &retVal.Created, &retVal.Updated, &retVal.VisitDuration, &retVal.ExternalID, &retVal.TripType.ID, &retVal.TripType.Key, &retVal.TripType.Value, &retVal.Pickup.ID, &retVal.PickupAddressID, &retVal.DestinationAddressID, &retVal.Provider.ProviderID, &retVal.Provider.ProviderUUID, &retVal.Provider.InternalID, &retVal.Provider.MukID, &retVal.Provider.Name)
if birthDate.Valid {
retVal.User.BirthDate = birthDate.Time
}
if gender.Valid {
retVal.User.Gender = gender.String
} else {
retVal.User.Gender = "U"
}
return retVal, errors.Wrap(err)
}
func (c *visitRepo) Create(visit entity.Visit) (entity.Visit, error) {
const (
statusQuery = `SELECT a.visit_status_id, a.visit_status_key, a.visit_status, b.user_id, b.name user_name, c.user_id create_user_id, c.name create_user_name, d.trip_type_id, d.trip_type_key, d.trip_type FROM tab_visit_status a, tab_user b, tab_user c, tab_trip_type d WHERE a.visit_status_key = ? AND b.user_uuid = ? AND c.user_uuid = ? AND d.trip_type_key = ?;`
query = `INSERT INTO tab_visit(visit_uuid, visit_status_id, user_id, visit_datetime, pickup_datetime, notes, created_user_id, visit_duration, visit_external_id, return_date, trip_type_id, pickup_id, pickup_address_id, address_id, provider_id)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`
)
retVal := visit
returnDate := mysql.NullTime{
Valid: (retVal.ReturnDate != nil),
}
if retVal.ReturnDate != nil {
returnDate.Time = *retVal.ReturnDate
}
UUID, _ := uuid.NewV4()
retVal.UUID = UUID.String()
if retVal.Status.Key == "" {
retVal.Status.Key = "accepted"
}
row := c.conn.QueryRow(statusQuery, retVal.Status.Key, retVal.User.UUID, retVal.CreatedUser.UUID, retVal.TripType.Key)
if err := row.Scan(&retVal.Status.ID, &retVal.Status.Key, &retVal.Status.Value, &retVal.User.ID, &retVal.User.Name, &retVal.CreatedUser.ID, &retVal.CreatedUser.Name, &retVal.TripType.ID, &retVal.TripType.Key, &retVal.TripType.Value); err != nil {
fmt.Println("Error to get base data: ", err.Error())
return retVal, err
}
results, err := c.conn.Exec(query, retVal.UUID, retVal.Status.ID, retVal.User.ID, retVal.VisitDatetime, retVal.PickupDatetime, retVal.Notes, retVal.CreatedUser.ID, toNullInt64(retVal.VisitDuration), retVal.ExternalID, returnDate, retVal.TripType.ID, retVal.Pickup.ID, retVal.PickupAddressID, retVal.DestinationAddressID, retVal.Provider.ProviderID)
if err != nil {
return retVal, err
}
retVal.ID, err = results.LastInsertId()
if err != nil {
return retVal, err
}
fmt.Println("Visit ID: ", retVal.ID)
return retVal, nil
}