first init
This commit is contained in:
commit
d3a93ee716
2
Makefile
Normal file
2
Makefile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
build:
|
||||||
|
env GOOS=linux GOARCH=amd64 go build -o genTransitPoint.linux main.go
|
||||||
29
go.mod
Normal file
29
go.mod
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
module gen_transit_point
|
||||||
|
|
||||||
|
go 1.25.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/lib/pq v1.10.9
|
||||||
|
github.com/opentracing/opentracing-go v1.2.0
|
||||||
|
github.com/xuri/excelize/v2 v2.10.0
|
||||||
|
gorm.io/driver/postgres v1.6.0
|
||||||
|
gorm.io/gorm v1.31.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.6.0 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||||
|
github.com/richardlehane/msoleps v1.0.4 // indirect
|
||||||
|
github.com/tiendc/go-deepcopy v1.7.1 // indirect
|
||||||
|
github.com/xuri/efp v0.0.1 // indirect
|
||||||
|
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
|
||||||
|
golang.org/x/crypto v0.43.0 // indirect
|
||||||
|
golang.org/x/net v0.46.0 // indirect
|
||||||
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
|
golang.org/x/text v0.30.0 // indirect
|
||||||
|
)
|
||||||
57
go.sum
Normal file
57
go.sum
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
|
||||||
|
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||||
|
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
|
||||||
|
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
|
||||||
|
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||||
|
github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00=
|
||||||
|
github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
github.com/tiendc/go-deepcopy v1.7.1 h1:LnubftI6nYaaMOcaz0LphzwraqN8jiWTwm416sitff4=
|
||||||
|
github.com/tiendc/go-deepcopy v1.7.1/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=
|
||||||
|
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
|
||||||
|
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||||
|
github.com/xuri/excelize/v2 v2.10.0 h1:8aKsP7JD39iKLc6dH5Tw3dgV3sPRh8uRVXu/fMstfW4=
|
||||||
|
github.com/xuri/excelize/v2 v2.10.0/go.mod h1:SC5TzhQkaOsTWpANfm+7bJCldzcnU/jrhqkTi/iBHBU=
|
||||||
|
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
|
||||||
|
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
||||||
|
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||||
|
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||||
|
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
|
||||||
|
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
|
||||||
|
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||||
|
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||||
|
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||||
|
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
|
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||||
|
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
|
||||||
|
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
|
||||||
|
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
|
||||||
|
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||||
318
main.go
Normal file
318
main.go
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"gen_transit_point/model"
|
||||||
|
"gen_transit_point/utils"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
"github.com/opentracing/opentracing-go"
|
||||||
|
"github.com/xuri/excelize/v2"
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
"gorm.io/gorm/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitGormDB(host string, port int, user, pass, dbname string) (*gorm.DB, error) {
|
||||||
|
dsn := fmt.Sprintf(
|
||||||
|
"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
|
||||||
|
host, port, user, pass, dbname,
|
||||||
|
)
|
||||||
|
|
||||||
|
gormDB, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
|
||||||
|
PrepareStmt: true,
|
||||||
|
Logger: logger.Default.LogMode(logger.Warn),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup connection pooling
|
||||||
|
sqlDB, err := gormDB.DB()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sqlDB.SetMaxIdleConns(10)
|
||||||
|
sqlDB.SetMaxOpenConns(100)
|
||||||
|
sqlDB.SetConnMaxLifetime(time.Hour)
|
||||||
|
|
||||||
|
return gormDB, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ctx := context.Background()
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
dbhost := "127.0.0.1"
|
||||||
|
dbport := 5432
|
||||||
|
dbuser := "postgres"
|
||||||
|
dbpass := "postgres"
|
||||||
|
dbname := "oslogweb"
|
||||||
|
|
||||||
|
//prod
|
||||||
|
/* dbhost := "38.47.91.219"
|
||||||
|
dbport := 5454
|
||||||
|
dbuser := "postgres"
|
||||||
|
dbpass := "0n35p1r1t2025"
|
||||||
|
dbname := "oslogweb" */
|
||||||
|
|
||||||
|
gormDB, err := InitGormDB(dbhost, dbport, dbuser, dbpass, dbname)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Gagal init GORM: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlDB, err := gormDB.DB()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Gagal ambil sql.DB: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sqlDB.Ping(); err != nil {
|
||||||
|
log.Fatalf("Gagal ping database: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Koneksi ke DB berhasil ✅")
|
||||||
|
|
||||||
|
filename := "transit_point_indosps.xlsx"
|
||||||
|
f, err := excelize.OpenFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Gagal membuka file Excel: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
sheets := f.GetSheetList()
|
||||||
|
if len(sheets) == 0 {
|
||||||
|
log.Fatal("File Excel tidak memiliki sheet.")
|
||||||
|
}
|
||||||
|
|
||||||
|
sheetName := sheets[0]
|
||||||
|
|
||||||
|
fmt.Printf("Membaca sheet: %s\n", sheetName)
|
||||||
|
|
||||||
|
rows, err := f.GetRows(sheetName)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Gagal membaca baris: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
excelData := []model.TransitPoint{}
|
||||||
|
//skip header nya jadi init dari 1 bukan 0
|
||||||
|
for i := 1; i < len(rows); i++ {
|
||||||
|
row := rows[i]
|
||||||
|
if len(row) < 5 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
name := strings.TrimSpace(row[1])
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
address := strings.TrimSpace(row[2])
|
||||||
|
lat := strings.TrimSpace(row[3])
|
||||||
|
lon := strings.TrimSpace(row[4])
|
||||||
|
|
||||||
|
var latF, lonF float64
|
||||||
|
fmt.Sscanf(lat, "%f", &latF)
|
||||||
|
fmt.Sscanf(lon, "%f", &lonF)
|
||||||
|
|
||||||
|
excelData = append(excelData, model.TransitPoint{
|
||||||
|
CompanyID: 784,
|
||||||
|
Name: name,
|
||||||
|
Address: address,
|
||||||
|
Latitude: latF,
|
||||||
|
Longitude: lonF,
|
||||||
|
CreatedDate: utils.FormatToWithoutTZ(ctx, now),
|
||||||
|
CreatedBy: "system",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
names := []string{}
|
||||||
|
for _, p := range excelData {
|
||||||
|
names = append(names, fmt.Sprintf("'%s'", strings.ReplaceAll(p.Name, "'", "''")))
|
||||||
|
}
|
||||||
|
|
||||||
|
filter := fmt.Sprintf("AND a.company_id=784 AND a.name IN (%s)", strings.Join(names, ","))
|
||||||
|
data, err := GetTransitPoints(ctx, gormDB, filter)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Gagal GetTransitPoints: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dbMap := map[string]model.TransitPoint{}
|
||||||
|
for _, d := range data {
|
||||||
|
dbMap[d.Name] = *d
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range excelData {
|
||||||
|
geomWkt := GenerateGeomWkt(ctx, gormDB, p.Longitude, p.Latitude, float64(100))
|
||||||
|
p.GeomWkt = geomWkt
|
||||||
|
p.ModifiedBy = "system"
|
||||||
|
p.ModifiedDate = utils.FormatToWithoutTZ(ctx, now)
|
||||||
|
if existing, exists := dbMap[p.Name]; exists {
|
||||||
|
if existing.Address != p.Address || existing.Latitude != p.Latitude || existing.Longitude != p.Longitude {
|
||||||
|
_, err := UpdateTransitPointDB(ctx, gormDB, &p)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Gagal update %s: %v", p.Name, err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Berhasil update: %s\n", p.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err := InsertTransitPointDB(ctx, gormDB, &p)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Gagal insert %s: %v", p.Name, err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Berhasil insert: %s\n", p.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertTransitPointDB(ctx context.Context, db *gorm.DB, data *model.TransitPoint) (*model.TransitPoint, error) {
|
||||||
|
span, spanCtx := opentracing.StartSpanFromContext(ctx, "insertTransitPointDB")
|
||||||
|
defer span.Finish()
|
||||||
|
|
||||||
|
payload := data.BeforeCheck(spanCtx)
|
||||||
|
|
||||||
|
tx := db.WithContext(spanCtx).Begin().Scopes(payload.TableName(spanCtx))
|
||||||
|
if err := tx.Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if payload.GeomWkt.String != "" {
|
||||||
|
tx.Clauses(clause.Expr{SQL: "ST_GeomFromText(?, 4326)", Vars: []interface{}{payload.GeomWkt}})
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Create(&payload)
|
||||||
|
if err := tx.Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := tx.Commit().Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload.Convert(spanCtx), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateTransitPointDB(ctx context.Context, db *gorm.DB, data *model.TransitPoint) (*model.TransitPoint, error) {
|
||||||
|
span, spanCtx := opentracing.StartSpanFromContext(ctx, "updateTransitPointDB")
|
||||||
|
defer span.Finish()
|
||||||
|
|
||||||
|
payload := data.BeforeCheck(spanCtx)
|
||||||
|
|
||||||
|
tx := db.WithContext(spanCtx).Begin().Scopes(payload.TableName(spanCtx))
|
||||||
|
if err := tx.Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update GeomWkt jika ada
|
||||||
|
if payload.GeomWkt.String != "" {
|
||||||
|
tx = tx.Model(&payload).Clauses(clause.Expr{
|
||||||
|
SQL: "geom = ST_GeomFromText(?, 4326)",
|
||||||
|
Vars: []interface{}{payload.GeomWkt},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
tx = tx.Model(&payload).Where("id = ?", payload.ID).Updates(map[string]interface{}{
|
||||||
|
"address": payload.Address,
|
||||||
|
"latitude": payload.Latitude,
|
||||||
|
"longitude": payload.Longitude,
|
||||||
|
"modified_by": payload.ModifiedBy,
|
||||||
|
"modified_date": payload.ModifiedDate,
|
||||||
|
})
|
||||||
|
|
||||||
|
if tx.Error != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return nil, tx.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Commit().Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload.Convert(spanCtx), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateGeomWkt(ctx context.Context, db *gorm.DB, lon, lat, bufferRadius float64) string {
|
||||||
|
var value sql.NullString
|
||||||
|
tx := db.WithContext(ctx)
|
||||||
|
query := fmt.Sprintf("SELECT ST_AsText(ST_Buffer(ST_GeomFromText('POINT(%0.7f %0.7f)', 4326), 0.00001 * %v, 'quad_segs=2')) AS geom_text LIMIT 1", lon, lat, bufferRadius)
|
||||||
|
tx = tx.Raw(query)
|
||||||
|
tx.Row().Scan(&value)
|
||||||
|
return strings.TrimSpace(value.String)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTransitPoints(ctx context.Context, db *gorm.DB, filter string) ([]*model.TransitPoint, error) {
|
||||||
|
|
||||||
|
tx := db.WithContext(ctx)
|
||||||
|
query := fmt.Sprintf(`SELECT a.id,a.company_id,a.customer_id,a.customer_ids,a.trip_group_transit_point_id,a.status,a.blacklist
|
||||||
|
,a.latitude,a.longitude,a.register_date,a.unregister_date,a.created_date,a.modified_date
|
||||||
|
,a.name,a.code,a.geocode,a.address,a.created_by,a.modified_by,a.pic_name,a.pic_phone,a.pic_mobile
|
||||||
|
,a.transit_point_type,a.remark,a.coords,a.fax,a.mobile_no,a.phone,a.image,a.zip_code,a.geom
|
||||||
|
FROM m_transit_point AS a
|
||||||
|
WHERE a.name IS NOT NULL AND a.name <> ''
|
||||||
|
%v`, filter)
|
||||||
|
|
||||||
|
fmt.Printf("query : %v\n", query)
|
||||||
|
|
||||||
|
rows, err := tx.Raw(query).Rows()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
data := []*model.TransitPoint{}
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
dataScan := model.TransitPointDB{}
|
||||||
|
err := rows.Scan(
|
||||||
|
&dataScan.ID,
|
||||||
|
&dataScan.CompanyID,
|
||||||
|
&dataScan.CustomerID,
|
||||||
|
&dataScan.CustomerIDs,
|
||||||
|
&dataScan.TripGroupTransitPointID,
|
||||||
|
&dataScan.Status,
|
||||||
|
&dataScan.Blacklist,
|
||||||
|
&dataScan.Latitude,
|
||||||
|
&dataScan.Longitude,
|
||||||
|
&dataScan.RegisterDate,
|
||||||
|
&dataScan.UnregisterDate,
|
||||||
|
&dataScan.CreatedDate,
|
||||||
|
&dataScan.ModifiedDate,
|
||||||
|
&dataScan.Name,
|
||||||
|
&dataScan.Code,
|
||||||
|
&dataScan.Geocode,
|
||||||
|
&dataScan.Address,
|
||||||
|
&dataScan.CreatedBy,
|
||||||
|
&dataScan.ModifiedBy,
|
||||||
|
&dataScan.PicName,
|
||||||
|
&dataScan.PicPhone,
|
||||||
|
&dataScan.PicMobile,
|
||||||
|
&dataScan.TransitPointType,
|
||||||
|
&dataScan.Remark,
|
||||||
|
&dataScan.Coords,
|
||||||
|
&dataScan.Fax,
|
||||||
|
&dataScan.MobileNo,
|
||||||
|
&dataScan.Phone,
|
||||||
|
&dataScan.Image,
|
||||||
|
&dataScan.ZipCode,
|
||||||
|
&dataScan.GeomWkb,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := dataScan.Convert(ctx)
|
||||||
|
data = append(data, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
215
model/transitPoint.go
Normal file
215
model/transitPoint.go
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"gen_transit_point/utils"
|
||||||
|
|
||||||
|
"github.com/lib/pq"
|
||||||
|
"github.com/opentracing/opentracing-go"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TransitPoint struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
CompanyID int64 `json:"company_id"`
|
||||||
|
CustomerID int64 `json:"customer_id"`
|
||||||
|
CustomerIDs []int64 `json:"customer_ids"`
|
||||||
|
TripGroupTransitPointID *int64 `json:"trip_group_transit_point_id"`
|
||||||
|
Status bool `json:"status"`
|
||||||
|
Blacklist bool `json:"blacklist"`
|
||||||
|
Latitude float64 `json:"latitude"`
|
||||||
|
Longitude float64 `json:"longitude"`
|
||||||
|
RegisterDate string `json:"register_date"`
|
||||||
|
UnregisterDate string `json:"unregister_date"`
|
||||||
|
CreatedDate string `json:"created_date"`
|
||||||
|
ModifiedDate string `json:"modified_date"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
Geocode string `json:"geocode"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
CreatedBy string `json:"created_by"`
|
||||||
|
ModifiedBy string `json:"modified_by"`
|
||||||
|
PicName string `json:"pic_name"`
|
||||||
|
PicPhone string `json:"pic_phone"`
|
||||||
|
PicMobile string `json:"pic_mobile"`
|
||||||
|
TransitPointType string `json:"transit_point_type"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
Coords string `json:"coords"`
|
||||||
|
Fax string `json:"fax"`
|
||||||
|
MobileNo string `json:"mobile_no"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
Image string `json:"image"`
|
||||||
|
ZipCode string `json:"zip_code"`
|
||||||
|
GeomWkt string `json:"geom" gorm:"column:geom" validate:"required"`
|
||||||
|
GeomWkb string `json:"geom_wkb,omitempty" gorm:"-"`
|
||||||
|
CentroidLon float64 `json:"centroid_lon,omitempty" gorm:"-"`
|
||||||
|
CentroidLat float64 `json:"centroid_lat,omitempty" gorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransitPointDB struct {
|
||||||
|
ID sql.NullInt64 `json:"id"`
|
||||||
|
CompanyID sql.NullInt64 `json:"company_id"`
|
||||||
|
CustomerID sql.NullInt64 `json:"customer_id"`
|
||||||
|
CustomerIDs pq.Int64Array `json:"customer_ids" gorm:"type:bigint[];default:'{}'::bigint[]"`
|
||||||
|
TripGroupTransitPointID sql.NullInt64 `json:"trip_group_transit_point_id"`
|
||||||
|
Status sql.NullBool `json:"status"`
|
||||||
|
Blacklist sql.NullBool `json:"blacklist"`
|
||||||
|
Latitude sql.NullFloat64 `json:"latitude"`
|
||||||
|
Longitude sql.NullFloat64 `json:"longitude"`
|
||||||
|
RegisterDate sql.NullTime `json:"register_date"`
|
||||||
|
UnregisterDate sql.NullTime `json:"unregister_date"`
|
||||||
|
CreatedDate sql.NullTime `json:"created_date"`
|
||||||
|
ModifiedDate sql.NullTime `json:"modified_date"`
|
||||||
|
Name sql.NullString `json:"name"`
|
||||||
|
Code sql.NullString `json:"code"`
|
||||||
|
Geocode sql.NullString `json:"geocode"`
|
||||||
|
Address sql.NullString `json:"address"`
|
||||||
|
CreatedBy sql.NullString `json:"created_by"`
|
||||||
|
ModifiedBy sql.NullString `json:"modified_by"`
|
||||||
|
PicName sql.NullString `json:"pic_name"`
|
||||||
|
PicPhone sql.NullString `json:"pic_phone"`
|
||||||
|
PicMobile sql.NullString `json:"pic_mobile"`
|
||||||
|
TransitPointType sql.NullString `json:"transit_point_type"`
|
||||||
|
Remark sql.NullString `json:"remark"`
|
||||||
|
Coords sql.NullString `json:"coords"`
|
||||||
|
Fax sql.NullString `json:"fax"`
|
||||||
|
MobileNo sql.NullString `json:"mobile_no"`
|
||||||
|
Phone sql.NullString `json:"phone"`
|
||||||
|
Image sql.NullString `json:"image"`
|
||||||
|
ZipCode sql.NullString `json:"zip_code"`
|
||||||
|
GeomWkt sql.NullString `json:"geom_wkt" gorm:"column:geom"`
|
||||||
|
GeomWkb sql.NullString `json:"geom_wkb" gorm:"-"`
|
||||||
|
CentroidLon sql.NullFloat64 `json:"centroid_lon" gorm:"-"`
|
||||||
|
CentroidLat sql.NullFloat64 `json:"centroid_lat" gorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TransitPoint) BeforeCheck(ctx context.Context) *TransitPointDB {
|
||||||
|
checkLat := utils.ValidCoords(ctx, t.Latitude, utils.VALID_LATITUDE)
|
||||||
|
checkLon := utils.ValidCoords(ctx, t.Longitude, utils.VALID_LONGITUDE)
|
||||||
|
if !checkLat || !checkLon {
|
||||||
|
lat := t.Longitude
|
||||||
|
lon := t.Latitude
|
||||||
|
t.Latitude = lat
|
||||||
|
t.Longitude = lon
|
||||||
|
}
|
||||||
|
|
||||||
|
data := &TransitPointDB{
|
||||||
|
ID: utils.NewNullInt64(ctx, &t.ID),
|
||||||
|
CompanyID: utils.NewNullInt64(ctx, &t.CompanyID),
|
||||||
|
CustomerID: utils.NewNullInt64(ctx, &t.CustomerID),
|
||||||
|
CustomerIDs: pq.Int64Array(t.CustomerIDs),
|
||||||
|
TripGroupTransitPointID: utils.NewNullInt64(ctx, t.TripGroupTransitPointID),
|
||||||
|
Status: utils.NewNullBool(ctx, &t.Status),
|
||||||
|
Blacklist: utils.NewNullBool(ctx, &t.Blacklist),
|
||||||
|
Latitude: utils.NewNullFloat64(ctx, &t.Latitude),
|
||||||
|
Longitude: utils.NewNullFloat64(ctx, &t.Longitude),
|
||||||
|
RegisterDate: utils.NewNullStringTime(ctx, &t.RegisterDate),
|
||||||
|
UnregisterDate: utils.NewNullStringTime(ctx, &t.UnregisterDate),
|
||||||
|
CreatedDate: utils.NewNullStringTime(ctx, &t.CreatedDate),
|
||||||
|
ModifiedDate: utils.NewNullStringTime(ctx, &t.ModifiedDate),
|
||||||
|
Name: utils.NewNullString(ctx, &t.Name),
|
||||||
|
Code: utils.NewNullString(ctx, &t.Code),
|
||||||
|
Geocode: utils.NewNullString(ctx, &t.Geocode),
|
||||||
|
Address: utils.NewNullString(ctx, &t.Address),
|
||||||
|
CreatedBy: utils.NewNullString(ctx, &t.CreatedBy),
|
||||||
|
ModifiedBy: utils.NewNullString(ctx, &t.ModifiedBy),
|
||||||
|
PicName: utils.NewNullString(ctx, &t.PicName),
|
||||||
|
PicPhone: utils.NewNullString(ctx, &t.PicPhone),
|
||||||
|
PicMobile: utils.NewNullString(ctx, &t.PicMobile),
|
||||||
|
TransitPointType: utils.NewNullString(ctx, &t.TransitPointType),
|
||||||
|
Remark: utils.NewNullString(ctx, &t.Remark),
|
||||||
|
Coords: utils.NewNullString(ctx, &t.Coords),
|
||||||
|
Fax: utils.NewNullString(ctx, &t.Fax),
|
||||||
|
MobileNo: utils.NewNullString(ctx, &t.MobileNo),
|
||||||
|
Phone: utils.NewNullString(ctx, &t.Phone),
|
||||||
|
Image: utils.NewNullString(ctx, &t.Image),
|
||||||
|
ZipCode: utils.NewNullString(ctx, &t.ZipCode),
|
||||||
|
GeomWkt: utils.NewNullString(ctx, &t.GeomWkt),
|
||||||
|
GeomWkb: utils.NewNullString(ctx, &t.GeomWkb),
|
||||||
|
CentroidLon: utils.NewNullFloat64(ctx, &t.CentroidLon),
|
||||||
|
CentroidLat: utils.NewNullFloat64(ctx, &t.CentroidLat),
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TransitPointDB) TableName(ctx context.Context, alias ...string) func(db *gorm.DB) *gorm.DB {
|
||||||
|
span, spanCtx := opentracing.StartSpanFromContext(ctx, "tableName")
|
||||||
|
defer span.Finish()
|
||||||
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
|
db = t.NamingStrategy(spanCtx, db)
|
||||||
|
table := db.Statement.Config.NamingStrategy.TableName("transit_point")
|
||||||
|
if len(alias) > 0 && alias[0] != "" {
|
||||||
|
return db.Table(fmt.Sprintf("%s AS %s", table, alias[0]))
|
||||||
|
}
|
||||||
|
return db.Table(table)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TransitPointDB) NamingStrategy(ctx context.Context, tx *gorm.DB) *gorm.DB {
|
||||||
|
span, spanCtx := opentracing.StartSpanFromContext(ctx, "namingStrategy")
|
||||||
|
defer span.Finish()
|
||||||
|
tx.Statement.Context = spanCtx
|
||||||
|
tx.Config.NamingStrategy = schema.NamingStrategy{
|
||||||
|
TablePrefix: "m_",
|
||||||
|
SingularTable: true,
|
||||||
|
}
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TransitPointDB) Convert(ctx context.Context) *TransitPoint {
|
||||||
|
data := &TransitPoint{
|
||||||
|
ID: t.ID.Int64,
|
||||||
|
CompanyID: t.CompanyID.Int64,
|
||||||
|
CustomerID: t.CustomerID.Int64,
|
||||||
|
CustomerIDs: []int64(t.CustomerIDs),
|
||||||
|
TripGroupTransitPointID: &t.TripGroupTransitPointID.Int64,
|
||||||
|
Status: t.Status.Bool,
|
||||||
|
Blacklist: t.Blacklist.Bool,
|
||||||
|
Latitude: t.Latitude.Float64,
|
||||||
|
Longitude: t.Longitude.Float64,
|
||||||
|
RegisterDate: utils.FormatToWithoutTZ(ctx, t.RegisterDate.Time),
|
||||||
|
UnregisterDate: utils.FormatToWithoutTZ(ctx, t.UnregisterDate.Time),
|
||||||
|
CreatedDate: utils.FormatToWithoutTZ(ctx, t.CreatedDate.Time),
|
||||||
|
ModifiedDate: utils.FormatToWithoutTZ(ctx, t.ModifiedDate.Time),
|
||||||
|
Name: t.Name.String,
|
||||||
|
Code: t.Code.String,
|
||||||
|
Geocode: t.Geocode.String,
|
||||||
|
Address: t.Address.String,
|
||||||
|
CreatedBy: t.CreatedBy.String,
|
||||||
|
ModifiedBy: t.ModifiedBy.String,
|
||||||
|
PicName: t.PicName.String,
|
||||||
|
PicPhone: t.PicPhone.String,
|
||||||
|
PicMobile: t.PicMobile.String,
|
||||||
|
TransitPointType: t.TransitPointType.String,
|
||||||
|
Remark: t.Remark.String,
|
||||||
|
Coords: t.Coords.String,
|
||||||
|
Fax: t.Fax.String,
|
||||||
|
MobileNo: t.MobileNo.String,
|
||||||
|
Phone: t.Phone.String,
|
||||||
|
Image: t.Image.String,
|
||||||
|
ZipCode: t.ZipCode.String,
|
||||||
|
//GeomWkb: t.GeomWkb.String,
|
||||||
|
GeomWkt: t.GeomWkt.String,
|
||||||
|
//CentroidLon: t.CentroidLon.Float64,
|
||||||
|
//CentroidLat: t.CentroidLat.Float64,
|
||||||
|
}
|
||||||
|
checkLat := utils.ValidCoords(ctx, data.Latitude, utils.VALID_LATITUDE)
|
||||||
|
checkLon := utils.ValidCoords(ctx, data.Longitude, utils.VALID_LONGITUDE)
|
||||||
|
if !checkLat || !checkLon {
|
||||||
|
lat := data.Longitude
|
||||||
|
lon := data.Latitude
|
||||||
|
data.Latitude = lat
|
||||||
|
data.Longitude = lon
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if data.Latitude == 0 || data.Longitude == 0 {
|
||||||
|
data.Latitude = data.CentroidLat
|
||||||
|
data.Longitude = data.CentroidLon
|
||||||
|
} */
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
BIN
transit_point_indosps.xlsx
Normal file
BIN
transit_point_indosps.xlsx
Normal file
Binary file not shown.
6
utils/constant.go
Normal file
6
utils/constant.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
const (
|
||||||
|
VALID_LATITUDE = "latitude"
|
||||||
|
VALID_LONGITUDE = "longitude"
|
||||||
|
)
|
||||||
257
utils/convert.go
Normal file
257
utils/convert.go
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TIME_LAYOUT_DATE = "2006-01-02"
|
||||||
|
TIME_LAYOUT_DB_WITHOUT_TZ = "2006-01-02 15:04:05"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConvertSecondToDHMS struct {
|
||||||
|
Days int64 `json:"days"`
|
||||||
|
Hours int64 `json:"hours"`
|
||||||
|
Minutes int64 `json:"minutes"`
|
||||||
|
Seconds int64 `json:"seconds"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatToDate(ctx context.Context, t time.Time) string {
|
||||||
|
if t.IsZero() {
|
||||||
|
return "1900-01-01"
|
||||||
|
}
|
||||||
|
return t.Format(TIME_LAYOUT_DATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatToWithoutTZ(ctx context.Context, t time.Time) string {
|
||||||
|
if t.IsZero() {
|
||||||
|
return "1900-01-01 00:00:00"
|
||||||
|
}
|
||||||
|
return t.Format(TIME_LAYOUT_DB_WITHOUT_TZ)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullFromFormatWithoutTZ(ctx context.Context, v *string) *time.Time {
|
||||||
|
var value *time.Time
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
check := strings.TrimSpace(*v)
|
||||||
|
if check == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(check, "1900-01-01") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch check {
|
||||||
|
case "1900-01-01", "0001-01-01", "1900-01-01 00:00:00", "0001-01-01 00:00:00":
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
result, _ := time.Parse(time.RFC3339, strings.ReplaceAll(check, " ", "T")+"+07:00")
|
||||||
|
if !result.IsZero() {
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullInt64(ctx context.Context, v *int64) sql.NullInt64 {
|
||||||
|
if v == nil {
|
||||||
|
return sql.NullInt64{}
|
||||||
|
}
|
||||||
|
if *v <= 0 {
|
||||||
|
return sql.NullInt64{}
|
||||||
|
}
|
||||||
|
return sql.NullInt64{Int64: *v, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullInt32(ctx context.Context, v *int32) sql.NullInt32 {
|
||||||
|
if v == nil {
|
||||||
|
return sql.NullInt32{}
|
||||||
|
}
|
||||||
|
if *v <= 0 {
|
||||||
|
return sql.NullInt32{}
|
||||||
|
}
|
||||||
|
return sql.NullInt32{Int32: *v, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullInt16(ctx context.Context, v *int16) sql.NullInt16 {
|
||||||
|
if v == nil {
|
||||||
|
return sql.NullInt16{}
|
||||||
|
}
|
||||||
|
if *v <= 0 {
|
||||||
|
return sql.NullInt16{}
|
||||||
|
}
|
||||||
|
return sql.NullInt16{Int16: *v, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullFloat64(ctx context.Context, v *float64) sql.NullFloat64 {
|
||||||
|
if v == nil {
|
||||||
|
return sql.NullFloat64{}
|
||||||
|
}
|
||||||
|
return sql.NullFloat64{Float64: *v, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullString(ctx context.Context, v *string) sql.NullString {
|
||||||
|
if v == nil {
|
||||||
|
return sql.NullString{}
|
||||||
|
}
|
||||||
|
s := strings.TrimSpace(*v)
|
||||||
|
if len(s) <= 0 {
|
||||||
|
return sql.NullString{}
|
||||||
|
}
|
||||||
|
return sql.NullString{String: s, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullTime(ctx context.Context, v *time.Time) sql.NullTime {
|
||||||
|
if v == nil {
|
||||||
|
return sql.NullTime{}
|
||||||
|
}
|
||||||
|
|
||||||
|
value := *v
|
||||||
|
if value.IsZero() {
|
||||||
|
return sql.NullTime{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sql.NullTime{Time: value, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullStringTime(ctx context.Context, v *string) sql.NullTime {
|
||||||
|
if v == nil {
|
||||||
|
return sql.NullTime{}
|
||||||
|
}
|
||||||
|
s := strings.TrimSpace(*v)
|
||||||
|
|
||||||
|
result, _ := time.Parse(time.RFC3339, s)
|
||||||
|
if !result.IsZero() {
|
||||||
|
return sql.NullTime{Time: result, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
values := strings.Split(s, " ")
|
||||||
|
if len(values) <= 0 {
|
||||||
|
return sql.NullTime{}
|
||||||
|
} else if len(values) == 2 {
|
||||||
|
dateTime := strings.ReplaceAll(s, " ", "T")
|
||||||
|
result, _ = time.Parse(time.RFC3339, dateTime+"+07:00")
|
||||||
|
} else if len(values) == 1 {
|
||||||
|
date := strings.TrimSpace(values[0])
|
||||||
|
result, _ = time.Parse(time.RFC3339, date+"T00:00:00+07:00")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.IsZero() {
|
||||||
|
return sql.NullTime{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sql.NullTime{Time: result, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullBool(ctx context.Context, v *bool) sql.NullBool {
|
||||||
|
if v == nil {
|
||||||
|
return sql.NullBool{}
|
||||||
|
}
|
||||||
|
|
||||||
|
check := *v
|
||||||
|
value := sql.NullBool{Bool: check, Valid: true}
|
||||||
|
value.Scan(false)
|
||||||
|
if check {
|
||||||
|
value.Scan(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func HashToMD5(ctx context.Context, password string) string {
|
||||||
|
var result string
|
||||||
|
value := strings.TrimSpace(password)
|
||||||
|
if value != "" {
|
||||||
|
hashed := []byte(value)
|
||||||
|
result = fmt.Sprintf("%x", md5.Sum(hashed))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConvertSecondToDHMS(ctx context.Context, n int64) ConvertSecondToDHMS {
|
||||||
|
day := int64(n / (24 * 3600))
|
||||||
|
n = n % (24 * 3600)
|
||||||
|
hour := int64(n / 3600)
|
||||||
|
n %= 3600
|
||||||
|
minutes := int64(n / 60)
|
||||||
|
n %= 60
|
||||||
|
seconds := n
|
||||||
|
result := ConvertSecondToDHMS{
|
||||||
|
Days: day,
|
||||||
|
Hours: hour,
|
||||||
|
Minutes: minutes,
|
||||||
|
Seconds: seconds,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetToHMS(ctx context.Context, data ConvertSecondToDHMS) string {
|
||||||
|
hours := "00"
|
||||||
|
if data.Hours >= 0 && data.Hours < 10 {
|
||||||
|
hours = fmt.Sprintf("0%d", data.Hours)
|
||||||
|
} else {
|
||||||
|
hours = fmt.Sprintf("%d", data.Hours)
|
||||||
|
}
|
||||||
|
minutes := "00"
|
||||||
|
if data.Minutes >= 0 && data.Minutes < 10 {
|
||||||
|
minutes = fmt.Sprintf("0%d", data.Minutes)
|
||||||
|
} else if data.Minutes >= 10 && data.Minutes <= 59 {
|
||||||
|
minutes = fmt.Sprintf("%d", data.Minutes)
|
||||||
|
}
|
||||||
|
seconds := "00"
|
||||||
|
if data.Seconds >= 0 && data.Seconds < 10 {
|
||||||
|
seconds = fmt.Sprintf("0%d", data.Seconds)
|
||||||
|
} else if data.Seconds >= 10 && data.Seconds <= 59 {
|
||||||
|
seconds = fmt.Sprintf("%d", data.Seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s:%s:%s", hours, minutes, seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetToSummaryHMS(ctx context.Context, data ConvertSecondToDHMS, withFormat bool) string {
|
||||||
|
result := ""
|
||||||
|
if data.Days >= 0 {
|
||||||
|
totalHours := (data.Days * 24) + data.Hours
|
||||||
|
hours := "00"
|
||||||
|
if totalHours >= 0 && totalHours < 10 {
|
||||||
|
hours = fmt.Sprintf("0%d", totalHours)
|
||||||
|
} else {
|
||||||
|
hours = fmt.Sprintf("%d", totalHours)
|
||||||
|
}
|
||||||
|
minutes := "00"
|
||||||
|
if data.Minutes >= 0 && data.Minutes < 10 {
|
||||||
|
minutes = fmt.Sprintf("0%d", data.Minutes)
|
||||||
|
} else if data.Minutes >= 10 && data.Minutes <= 59 {
|
||||||
|
minutes = fmt.Sprintf("%d", data.Minutes)
|
||||||
|
}
|
||||||
|
seconds := "00"
|
||||||
|
if data.Seconds >= 0 && data.Seconds < 10 {
|
||||||
|
seconds = fmt.Sprintf("0%d", data.Seconds)
|
||||||
|
} else if data.Seconds >= 10 && data.Seconds <= 59 {
|
||||||
|
seconds = fmt.Sprintf("%d", data.Seconds)
|
||||||
|
}
|
||||||
|
result = fmt.Sprintf("%s:%s:%s", hours, minutes, seconds)
|
||||||
|
if withFormat {
|
||||||
|
result = fmt.Sprintf("%sH %sM %sS", hours, minutes, seconds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToFixed(num float64, precision int) float64 {
|
||||||
|
output := math.Pow(10, float64(precision))
|
||||||
|
return math.Round(num*output) / output
|
||||||
|
}
|
||||||
19
utils/helper.go
Normal file
19
utils/helper.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ValidCoords(ctx context.Context, value float64, key string) bool {
|
||||||
|
switch key {
|
||||||
|
case VALID_LATITUDE:
|
||||||
|
if value >= -90 && value <= 90 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case VALID_LONGITUDE:
|
||||||
|
if value >= -180 && value <= 180 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user