|
package main |
|
|
|
import ( |
|
"fmt" |
|
"github.com/jaswdr/faker" |
|
"log" |
|
"math/rand" |
|
"os" |
|
"sync/atomic" |
|
"time" |
|
) |
|
|
|
type User struct { |
|
id int |
|
name string |
|
orders []Order |
|
} |
|
|
|
type Order struct { |
|
id int32 |
|
products []Product |
|
date string |
|
} |
|
|
|
type Product struct { |
|
id int |
|
value float32 |
|
} |
|
|
|
type UserCreated struct { |
|
index int |
|
user User |
|
data []string |
|
} |
|
type OrderCreated struct { |
|
index int |
|
order Order |
|
data []string |
|
} |
|
|
|
const ( |
|
qtdUsersToGenerate = 10_000 |
|
maxRandomOrdersByUser = 100 |
|
maxRandomProductByOrder = 10 |
|
//-- |
|
maxRandomProductsId = 10 |
|
) |
|
|
|
var ( |
|
timeMinToRandomDateOrder, _ = time.Parse("20060102", "20100101") |
|
file = openNewFile() |
|
) |
|
|
|
func main() { |
|
startDate := time.Now() |
|
data, _ := generateData() |
|
fmt.Printf("Duration to generate: %d\n", time.Now().UnixMilli()-startDate.UnixMilli()) |
|
startDate2 := time.Now() |
|
shuffleAndWrite(data, file) |
|
fmt.Printf("Duration write: %d\n", time.Now().UnixMilli()-startDate2.UnixMilli()) |
|
fmt.Printf("Duration total: %d\n", time.Now().UnixMilli()-startDate.UnixMilli()) |
|
} |
|
|
|
func generateData() ([]string, []User) { |
|
users := make([]User, qtdUsersToGenerate) |
|
userCh := make(chan UserCreated) |
|
|
|
var usersString []string |
|
var sequentialOrderId int32 = 100 |
|
|
|
// start goroutines to create users with orders |
|
for userIndex := 0; userIndex < qtdUsersToGenerate; userIndex++ { |
|
go createUserWithOrders(&sequentialOrderId, userIndex, userIndex+1, userCh) |
|
} |
|
|
|
// wait all users be created |
|
for userIndex := 0; userIndex < qtdUsersToGenerate; userIndex++ { |
|
newUser := <-userCh |
|
users[newUser.index] = newUser.user |
|
usersString = append(usersString, newUser.data...) |
|
} |
|
return usersString, users |
|
} |
|
|
|
func createUserWithOrders(sequentialOrderId *int32, userIndex int, userId int, ch chan UserCreated) { |
|
var ordersData []string |
|
qtdOrdersByUser := randomInt(maxRandomOrdersByUser) |
|
orderCh := make(chan OrderCreated) |
|
|
|
user := User{ |
|
id: userId, |
|
name: newFaker().Person().Name(), |
|
orders: make([]Order, qtdOrdersByUser), |
|
} |
|
|
|
// start goroutines to create orders |
|
for orderIndex := 0; orderIndex < qtdOrdersByUser; orderIndex++ { |
|
orderId := atomic.AddInt32(sequentialOrderId, 1) |
|
go createOrderByUser(orderIndex, orderId, user, orderCh) |
|
} |
|
|
|
// listen all orders created |
|
for orderIndex := 0; orderIndex < qtdOrdersByUser; orderIndex++ { |
|
newOrder := <-orderCh |
|
user.orders[newOrder.index] = newOrder.order |
|
ordersData = append(ordersData, newOrder.data...) |
|
} |
|
ch <- UserCreated{index: userIndex, user: user, data: ordersData} |
|
} |
|
|
|
func createOrderByUser(orderIndex int, orderId int32, user User, ch chan OrderCreated) { |
|
var ordersString []string |
|
qtdProductsByOrder := randomInt(maxRandomProductByOrder) |
|
order := Order{ |
|
id: orderId, |
|
products: make([]Product, qtdProductsByOrder), |
|
date: newFaker().Time().TimeBetween(timeMinToRandomDateOrder, time.Now()).Format("20060102"), |
|
} |
|
for productIndex := 0; productIndex < qtdProductsByOrder; productIndex++ { |
|
product, orderString := createProductToOrder(order, user) |
|
order.products[productIndex] = product |
|
ordersString = append(ordersString, orderString) |
|
} |
|
ch <- OrderCreated{index: orderIndex, order: order, data: ordersString} |
|
} |
|
|
|
func createProductToOrder(order Order, user User) (Product, string) { |
|
product := Product{ |
|
id: randomInt(maxRandomProductsId), |
|
value: newFaker().Float32(2, 10, 2000), |
|
} |
|
orderString := fmt.Sprintf("%010d%45s%010d%010d%12.2f%s\n", |
|
user.id, user.name, order.id, product.id, product.value, order.date, |
|
) |
|
return product, orderString |
|
} |
|
|
|
func newFaker() faker.Faker { |
|
return faker.NewWithSeed(rand.NewSource(time.Now().UnixNano())) |
|
} |
|
|
|
func randomInt(max int) int { |
|
value := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(max) |
|
if value <= 0 { |
|
value = 1 |
|
} |
|
return value |
|
} |
|
|
|
func openNewFile() *os.File { |
|
file, err := os.OpenFile( |
|
fmt.Sprintf("./orders_%s.txt", time.Now().Format("20060102_150405")), |
|
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
return file |
|
} |
|
|
|
func shuffleAndWrite(data []string, file *os.File) { |
|
rand.New(rand.NewSource(time.Now().Unix())).Shuffle(len(data), func(i, j int) { data[i], data[j] = data[j], data[i] }) |
|
for _, dataValue := range data { |
|
_, _ = file.WriteString(dataValue) |
|
} |
|
} |