init elowdb go-port commit
This commit is contained in:
537
examples/custom-json/main.go
Normal file
537
examples/custom-json/main.go
Normal file
@@ -0,0 +1,537 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"linedb/pkg/linedb"
|
||||
)
|
||||
|
||||
// User представляет пользователя
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
IsActive bool `json:"isActive"`
|
||||
Role string `json:"role"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
}
|
||||
|
||||
// Product представляет продукт
|
||||
type Product struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Price float64 `json:"price"`
|
||||
Category string `json:"category"`
|
||||
InStock bool `json:"inStock"`
|
||||
SellerID int `json:"sellerId"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Очищаем тестовые данные
|
||||
os.RemoveAll("./data/test-linedb-custom-json")
|
||||
|
||||
fmt.Println("=== LineDb Custom JSON Serialization Demo ===")
|
||||
|
||||
// Получаем номера тестов из аргументов командной строки
|
||||
testNumbers := parseTestNumbers()
|
||||
|
||||
// Выполняем тесты
|
||||
if len(testNumbers) == 0 {
|
||||
// Если номера не указаны, выполняем все тесты
|
||||
runAllTests()
|
||||
} else {
|
||||
// Выполняем только указанные тесты
|
||||
runSelectedTests(testNumbers)
|
||||
}
|
||||
|
||||
fmt.Println("\n=== Все тесты завершены ===")
|
||||
}
|
||||
|
||||
// parseTestNumbers парсит номера тестов из аргументов командной строки
|
||||
func parseTestNumbers() []int {
|
||||
if len(os.Args) < 2 {
|
||||
return []int{}
|
||||
}
|
||||
|
||||
// Получаем аргумент после имени программы
|
||||
arg := os.Args[1]
|
||||
|
||||
// Проверяем, что это не флаг помощи
|
||||
if arg == "-h" || arg == "--help" || arg == "help" {
|
||||
printUsage()
|
||||
return []int{}
|
||||
}
|
||||
|
||||
// Разбиваем по запятой
|
||||
parts := strings.Split(arg, ",")
|
||||
var numbers []int
|
||||
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
if part == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
num, err := strconv.Atoi(part)
|
||||
if err != nil {
|
||||
fmt.Printf("Ошибка: '%s' не является числом\n", part)
|
||||
printUsage()
|
||||
return []int{}
|
||||
}
|
||||
|
||||
// Проверяем диапазон
|
||||
if num < 1 || num > 4 {
|
||||
fmt.Printf("Ошибка: номер теста %d должен быть от 1 до 4\n", num)
|
||||
printUsage()
|
||||
return []int{}
|
||||
}
|
||||
|
||||
numbers = append(numbers, num)
|
||||
}
|
||||
|
||||
return numbers
|
||||
}
|
||||
|
||||
// printUsage выводит справку по использованию
|
||||
func printUsage() {
|
||||
fmt.Println("\nИспользование:")
|
||||
fmt.Println(" go run main.go # Запустить все тесты")
|
||||
fmt.Println(" go run main.go 1 # Запустить только тест 1")
|
||||
fmt.Println(" go run main.go 1,3 # Запустить тесты 1 и 3")
|
||||
fmt.Println(" go run main.go 2,3,4 # Запустить тесты 2, 3 и 4")
|
||||
fmt.Println(" go run main.go help # Показать эту справку")
|
||||
fmt.Println("\nДоступные тесты:")
|
||||
fmt.Println(" 1 - Использование go-json (по умолчанию)")
|
||||
fmt.Println(" 2 - Использование стандартного encoding/json")
|
||||
fmt.Println(" 3 - Использование кастомной функции сериализации")
|
||||
fmt.Println(" 4 - ID всегда первое поле")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// runAllTests запускает все тесты
|
||||
func runAllTests() {
|
||||
testDefaultJSON()
|
||||
testStandardJSON()
|
||||
testCustomJSON()
|
||||
testIDFirstField()
|
||||
}
|
||||
|
||||
// runSelectedTests запускает только выбранные тесты
|
||||
func runSelectedTests(numbers []int) {
|
||||
for _, num := range numbers {
|
||||
switch num {
|
||||
case 1:
|
||||
fmt.Println("1. Использование go-json (по умолчанию)")
|
||||
testDefaultJSON()
|
||||
case 2:
|
||||
fmt.Println("2. Использование стандартного encoding/json")
|
||||
testStandardJSON()
|
||||
case 3:
|
||||
fmt.Println("3. Использование кастомной функции сериализации")
|
||||
testCustomJSON()
|
||||
case 4:
|
||||
fmt.Println("4. ID всегда первое поле")
|
||||
testIDFirstField()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testDefaultJSON() {
|
||||
// Создаем опции инициализации с go-json (по умолчанию)
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-custom-json/default",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "username"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем пользователя
|
||||
user := map[string]any{
|
||||
"id": 1,
|
||||
"username": "default_user",
|
||||
"email": "default@example.com",
|
||||
"isActive": true,
|
||||
"role": "user",
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(user, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert user: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
result, err := db.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Пользователей в базе: %d\n", len(result))
|
||||
if len(result) > 0 {
|
||||
if record, ok := result[0].(map[string]any); ok {
|
||||
fmt.Printf(" ID: %v, Username: %s\n", record["id"], record["username"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testStandardJSON() {
|
||||
// Создаем функции сериализации с использованием стандартного encoding/json
|
||||
standardJSONMarshal := func(v any) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
standardJSONUnmarshal := func(data []byte, v any) error {
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
// Создаем опции инициализации со стандартным JSON
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-custom-json/standard",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "username"},
|
||||
JSONMarshal: standardJSONMarshal,
|
||||
JSONUnmarshal: standardJSONUnmarshal,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем пользователя
|
||||
user := map[string]any{
|
||||
"id": 2,
|
||||
"username": "standard_user",
|
||||
"email": "standard@example.com",
|
||||
"isActive": true,
|
||||
"role": "admin",
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(user, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert user: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
result, err := db.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Пользователей в базе: %d\n", len(result))
|
||||
if len(result) > 0 {
|
||||
if record, ok := result[0].(map[string]any); ok {
|
||||
fmt.Printf(" ID: %v, Username: %s\n", record["id"], record["username"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testCustomJSON() {
|
||||
// Создаем кастомные функции сериализации с дополнительной логикой
|
||||
customJSONMarshal := func(v any) ([]byte, error) {
|
||||
// Добавляем метаданные к сериализации
|
||||
data := map[string]any{
|
||||
"data": v,
|
||||
"timestamp": time.Now().Unix(),
|
||||
"version": "1.0",
|
||||
}
|
||||
return json.Marshal(data)
|
||||
}
|
||||
|
||||
customJSONUnmarshal := func(data []byte, v any) error {
|
||||
// Извлекаем данные из кастомного формата
|
||||
var wrapper map[string]any
|
||||
if err := json.Unmarshal(data, &wrapper); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Извлекаем основную часть данных
|
||||
if dataField, exists := wrapper["data"]; exists {
|
||||
// Сериализуем обратно в JSON и десериализуем в целевой тип
|
||||
dataBytes, err := json.Marshal(dataField)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(dataBytes, v)
|
||||
}
|
||||
|
||||
// Если нет поля data, пытаемся десериализовать как обычный JSON
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
// Создаем опции инициализации с кастомными функциями
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-custom-json/custom",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "username"},
|
||||
JSONMarshal: customJSONMarshal,
|
||||
JSONUnmarshal: customJSONUnmarshal,
|
||||
},
|
||||
{
|
||||
CollectionName: "products",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "name"},
|
||||
JSONMarshal: customJSONMarshal,
|
||||
JSONUnmarshal: customJSONUnmarshal,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем пользователя
|
||||
user := map[string]any{
|
||||
"id": 3,
|
||||
"username": "custom_user",
|
||||
"email": "custom@example.com",
|
||||
"isActive": true,
|
||||
"role": "moderator",
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Создаем продукт
|
||||
product := map[string]any{
|
||||
"id": 1,
|
||||
"name": "Custom Product",
|
||||
"price": 99.99,
|
||||
"category": "Electronics",
|
||||
"inStock": true,
|
||||
"sellerId": 1,
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(user, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert user: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := db.Insert(product, "products", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert product: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
users, err := db.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
products, err := db.Read("products", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read products: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Пользователей в базе: %d\n", len(users))
|
||||
fmt.Printf(" Продуктов в базе: %d\n", len(products))
|
||||
|
||||
if len(users) > 0 {
|
||||
if record, ok := users[0].(map[string]any); ok {
|
||||
fmt.Printf(" Пользователь ID: %v, Username: %s\n", record["id"], record["username"])
|
||||
}
|
||||
}
|
||||
|
||||
if len(products) > 0 {
|
||||
if record, ok := products[0].(map[string]any); ok {
|
||||
fmt.Printf(" Продукт ID: %v, Name: %s, Price: %v\n", record["id"], record["name"], record["price"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testIDFirstField() {
|
||||
// Создаем функции сериализации где id всегда первое поле
|
||||
idFirstJSONMarshal := func(v any) ([]byte, error) {
|
||||
if data, ok := v.(map[string]any); ok {
|
||||
var parts []string
|
||||
|
||||
// Сначала добавляем id если он есть
|
||||
if id, exists := data["id"]; exists {
|
||||
idBytes, err := json.Marshal(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf(`"id":%s`, string(idBytes)))
|
||||
}
|
||||
|
||||
// Затем добавляем все остальные поля в алфавитном порядке
|
||||
var keys []string
|
||||
for key := range data {
|
||||
if key != "id" {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
valueBytes, err := json.Marshal(data[key])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf(`"%s":%s`, key, string(valueBytes)))
|
||||
}
|
||||
|
||||
jsonStr := "{" + strings.Join(parts, ",") + "}"
|
||||
return []byte(jsonStr), nil
|
||||
}
|
||||
|
||||
// Если это не map, используем стандартную сериализацию
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
idFirstJSONUnmarshal := func(data []byte, v any) error {
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
// Создаем опции инициализации с функциями id-first
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-custom-json/id-first",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "username"},
|
||||
JSONMarshal: idFirstJSONMarshal,
|
||||
JSONUnmarshal: idFirstJSONUnmarshal,
|
||||
},
|
||||
{
|
||||
CollectionName: "products",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "name"},
|
||||
JSONMarshal: idFirstJSONMarshal,
|
||||
JSONUnmarshal: idFirstJSONUnmarshal,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем пользователя (id не первое поле в исходных данных)
|
||||
user := map[string]any{
|
||||
"username": "id_first_user",
|
||||
"email": "id_first@example.com",
|
||||
"id": 1,
|
||||
"isActive": true,
|
||||
"role": "user",
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Создаем продукт (id не первое поле в исходных данных)
|
||||
product := map[string]any{
|
||||
"name": "ID First Product",
|
||||
"price": 123.45,
|
||||
"id": 2,
|
||||
"category": "Books",
|
||||
"inStock": false,
|
||||
"sellerId": 1,
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(user, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert user: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := db.Insert(product, "products", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert product: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
users, err := db.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
products, err := db.Read("products", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read products: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Пользователей в базе: %d\n", len(users))
|
||||
fmt.Printf(" Продуктов в базе: %d\n", len(products))
|
||||
|
||||
if len(users) > 0 {
|
||||
if record, ok := users[0].(map[string]any); ok {
|
||||
fmt.Printf(" Пользователь ID: %v, Username: %s\n", record["id"], record["username"])
|
||||
}
|
||||
}
|
||||
|
||||
if len(products) > 0 {
|
||||
if record, ok := products[0].(map[string]any); ok {
|
||||
fmt.Printf(" Продукт ID: %v, Name: %s, Price: %v\n", record["id"], record["name"], record["price"])
|
||||
}
|
||||
}
|
||||
|
||||
// Показываем содержимое файла для демонстрации
|
||||
fmt.Println(" Проверьте файл ./data/test-linedb-custom-json/id-first/users.jsonl")
|
||||
fmt.Println(" Поле 'id' должно быть первым в JSON строке")
|
||||
}
|
||||
Reference in New Issue
Block a user