init elowdb go-port commit
This commit is contained in:
203
examples/README.md
Normal file
203
examples/README.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# Примеры использования LineDb
|
||||
|
||||
Этот каталог содержит примеры использования библиотеки LineDb, переведенные с TypeScript тестов.
|
||||
|
||||
## Структура примеров
|
||||
|
||||
### 1. `basic/` - Базовые операции
|
||||
|
||||
Простой пример демонстрирующий основные CRUD операции:
|
||||
|
||||
- Создание базы данных
|
||||
- Вставка данных
|
||||
- Чтение данных
|
||||
- Фильтрация
|
||||
- Обновление и удаление
|
||||
|
||||
### 2. `delete/` - Операции удаления
|
||||
|
||||
Примеры на основе теста `LineDbv2.delete.vi.test.ts`:
|
||||
|
||||
- Удаление одной записи по ID
|
||||
- Удаление по текстовому фильтру
|
||||
- Удаление нескольких записей по массиву
|
||||
- Удаление по частичному совпадению
|
||||
- Удаление из партиционированных коллекций
|
||||
- Обработка краевых случаев
|
||||
- Тест производительности
|
||||
|
||||
### 3. `insert/` - Операции вставки
|
||||
|
||||
Примеры на основе теста `LineDbv2.insert.vi.test.ts`:
|
||||
|
||||
- Вставка одной записи
|
||||
- Вставка массива записей
|
||||
- Автоматическая генерация ID
|
||||
- Вставка в партиционированные коллекции
|
||||
- Проверка уникальности
|
||||
- Работа с разными типами данных
|
||||
- Массовая вставка
|
||||
- Работа с несколькими коллекциями
|
||||
|
||||
### 4. `integration/` - Интеграционные тесты
|
||||
|
||||
Примеры на основе теста `LineDbv2.integration.vi.test.ts`:
|
||||
|
||||
- Базовые CRUD операции
|
||||
- Сложные запросы и фильтрация
|
||||
- Работа с несколькими коллекциями
|
||||
- Тест производительности
|
||||
- HTTP API сервер
|
||||
|
||||
### 5. `custom-json/` - Настраиваемые функции сериализации JSON
|
||||
|
||||
Демонстрирует использование настраиваемых функций сериализации и десериализации JSON:
|
||||
|
||||
- Использование go-json (по умолчанию)
|
||||
- Использование стандартного encoding/json
|
||||
- Кастомные функции сериализации с дополнительной логикой
|
||||
|
||||
## Запуск примеров
|
||||
|
||||
### Базовый пример
|
||||
|
||||
```bash
|
||||
cd examples/basic
|
||||
go run main.go
|
||||
```
|
||||
|
||||
### Примеры удаления
|
||||
|
||||
```bash
|
||||
cd examples/delete
|
||||
go run main.go
|
||||
```
|
||||
|
||||
### Примеры вставки
|
||||
|
||||
```bash
|
||||
cd examples/insert
|
||||
go run main.go
|
||||
```
|
||||
|
||||
### Интеграционные тесты
|
||||
|
||||
```bash
|
||||
cd examples/integration
|
||||
go run main.go
|
||||
```
|
||||
|
||||
### Настраиваемые функции JSON
|
||||
|
||||
```bash
|
||||
cd examples/custom-json
|
||||
go run main.go
|
||||
```
|
||||
|
||||
## Особенности примеров
|
||||
|
||||
### Партиционирование
|
||||
|
||||
Примеры демонстрируют работу с партиционированными коллекциями, где данные автоматически распределяются по файлам на основе значения определенного поля.
|
||||
|
||||
### Кэширование
|
||||
|
||||
Показана работа с кэшем для улучшения производительности чтения данных.
|
||||
|
||||
### Фильтрация
|
||||
|
||||
Демонстрируются различные способы фильтрации:
|
||||
|
||||
- Объектные фильтры
|
||||
- Строковые фильтры
|
||||
- Частичное совпадение
|
||||
- Строгое сравнение
|
||||
|
||||
### Производительность
|
||||
|
||||
Примеры включают тесты производительности для массовых операций.
|
||||
|
||||
### HTTP API
|
||||
|
||||
Интеграционный пример включает простой HTTP сервер с REST API для работы с базой данных.
|
||||
|
||||
### Настраиваемые функции сериализации JSON
|
||||
|
||||
Библиотека поддерживает настраиваемые функции сериализации и десериализации JSON:
|
||||
|
||||
```go
|
||||
// Функции сериализации по умолчанию (используют go-json)
|
||||
func defaultJSONMarshal(v any) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func defaultJSONUnmarshal(data []byte, v any) error {
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
// Настройка в опциях коллекции
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users",
|
||||
JSONMarshal: customMarshalFunction,
|
||||
JSONUnmarshal: customUnmarshalFunction,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
По умолчанию используется библиотека [go-json](https://github.com/goccy/go-json), но вы можете указать любые функции сериализации, соответствующие сигнатурам:
|
||||
|
||||
- `func(any) ([]byte, error)` для Marshal
|
||||
- `func([]byte, any) error` для Unmarshal
|
||||
|
||||
## Структуры данных
|
||||
|
||||
Примеры используют следующие основные структуры данных:
|
||||
|
||||
```go
|
||||
// Пользователь
|
||||
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"`
|
||||
}
|
||||
|
||||
// Продукт
|
||||
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"`
|
||||
}
|
||||
|
||||
// Заказ
|
||||
type Order struct {
|
||||
ID int `json:"id"`
|
||||
UserID int `json:"userId"`
|
||||
ProductID int `json:"productId"`
|
||||
Quantity int `json:"quantity"`
|
||||
TotalPrice float64 `json:"totalPrice"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
```
|
||||
|
||||
## Конфигурация
|
||||
|
||||
Каждый пример создает свою тестовую папку и настраивает базу данных с соответствующими коллекциями и индексами. После выполнения примеры автоматически очищают тестовые данные.
|
||||
|
||||
## Примечания
|
||||
|
||||
- Все примеры написаны на русском языке для лучшего понимания
|
||||
- Примеры демонстрируют реальные сценарии использования
|
||||
- Код включает обработку ошибок и логирование
|
||||
- Производительность измеряется и выводится в консоль
|
||||
124
examples/basic/main.go
Normal file
124
examples/basic/main.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"linedb/pkg/linedb"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Age int `json:"age"`
|
||||
Created string `json:"created"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Создаем опции инициализации
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 5 * time.Minute,
|
||||
DBFolder: "./data",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users",
|
||||
AllocSize: 512,
|
||||
IndexedFields: []string{"id", "email", "name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
if err := db.Init(false, initOptions); err != nil {
|
||||
log.Fatalf("Failed to init database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем тестовых пользователей
|
||||
users := []any{
|
||||
map[string]any{
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"age": 30,
|
||||
"created": time.Now().Format(time.RFC3339),
|
||||
},
|
||||
map[string]any{
|
||||
"name": "Jane Smith",
|
||||
"email": "jane@example.com",
|
||||
"age": 25,
|
||||
"created": time.Now().Format(time.RFC3339),
|
||||
},
|
||||
map[string]any{
|
||||
"name": "Bob Johnson",
|
||||
"email": "bob@example.com",
|
||||
"age": 35,
|
||||
"created": time.Now().Format(time.RFC3339),
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем пользователей
|
||||
if err := db.Insert(users, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Fatalf("Failed to insert users: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("Users inserted successfully!")
|
||||
|
||||
// Читаем всех пользователей
|
||||
allUsers, err := db.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read users: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Total users: %d\n", len(allUsers))
|
||||
for i, user := range allUsers {
|
||||
fmt.Printf("User %d: %+v\n", i+1, user)
|
||||
}
|
||||
|
||||
// Ищем пользователя по email
|
||||
filter := map[string]any{"email": "john@example.com"}
|
||||
foundUsers, err := db.ReadByFilter(filter, "users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to filter users: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Found %d users with email john@example.com\n", len(foundUsers))
|
||||
for _, user := range foundUsers {
|
||||
fmt.Printf("Found user: %+v\n", user)
|
||||
}
|
||||
|
||||
// Обновляем пользователя
|
||||
updateData := map[string]any{"age": 31}
|
||||
updateFilter := map[string]any{"email": "john@example.com"}
|
||||
updatedUsers, err := db.Update(updateData, "users", updateFilter, linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to update user: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Updated %d users\n", len(updatedUsers))
|
||||
|
||||
// Удаляем пользователя
|
||||
deleteFilter := map[string]any{"email": "bob@example.com"}
|
||||
deletedUsers, err := db.Delete(deleteFilter, "users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to delete user: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Deleted %d users\n", len(deletedUsers))
|
||||
|
||||
// Читаем оставшихся пользователей
|
||||
remainingUsers, err := db.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read remaining users: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Remaining users: %d\n", len(remainingUsers))
|
||||
for i, user := range remainingUsers {
|
||||
fmt.Printf("Remaining user %d: %+v\n", i+1, user)
|
||||
}
|
||||
}
|
||||
162
examples/custom-json/custom_json_test.go
Normal file
162
examples/custom-json/custom_json_test.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"linedb/pkg/linedb"
|
||||
)
|
||||
|
||||
func TestCustomJSONSerialization(t *testing.T) {
|
||||
// Тестируем стандартный JSON
|
||||
standardJSONMarshal := func(v any) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
standardJSONUnmarshal := func(data []byte, v any) error {
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
// Тестируем кастомный JSON с метаданными
|
||||
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 {
|
||||
dataBytes, err := json.Marshal(dataField)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(dataBytes, v)
|
||||
}
|
||||
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
// Тестируем функции сериализации
|
||||
testData := map[string]any{
|
||||
"id": 1,
|
||||
"name": "test",
|
||||
"age": 25,
|
||||
}
|
||||
|
||||
// Тест стандартного JSON
|
||||
standardData, err := standardJSONMarshal(testData)
|
||||
if err != nil {
|
||||
t.Fatalf("Standard JSON marshal failed: %v", err)
|
||||
}
|
||||
|
||||
var standardResult map[string]any
|
||||
if err := standardJSONUnmarshal(standardData, &standardResult); err != nil {
|
||||
t.Fatalf("Standard JSON unmarshal failed: %v", err)
|
||||
}
|
||||
|
||||
if standardResult["name"] != "test" {
|
||||
t.Errorf("Expected 'test', got %v", standardResult["name"])
|
||||
}
|
||||
|
||||
// Тест кастомного JSON
|
||||
customData, err := customJSONMarshal(testData)
|
||||
if err != nil {
|
||||
t.Fatalf("Custom JSON marshal failed: %v", err)
|
||||
}
|
||||
|
||||
var customResult map[string]any
|
||||
if err := customJSONUnmarshal(customData, &customResult); err != nil {
|
||||
t.Fatalf("Custom JSON unmarshal failed: %v", err)
|
||||
}
|
||||
|
||||
if customResult["name"] != "test" {
|
||||
t.Errorf("Expected 'test', got %v", customResult["name"])
|
||||
}
|
||||
|
||||
fmt.Println("✓ Custom JSON serialization test passed")
|
||||
}
|
||||
|
||||
func TestJSONLFileWithCustomSerialization(t *testing.T) {
|
||||
// Создаем функции сериализации
|
||||
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 {
|
||||
dataBytes, err := json.Marshal(dataField)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(dataBytes, v)
|
||||
}
|
||||
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
// Создаем JSONLFile с кастомными функциями
|
||||
options := linedb.JSONLFileOptions{
|
||||
CollectionName: "test",
|
||||
JSONMarshal: customJSONMarshal,
|
||||
JSONUnmarshal: customJSONUnmarshal,
|
||||
}
|
||||
|
||||
file := linedb.NewJSONLFile("./test-custom.jsonl", "", options)
|
||||
|
||||
// Инициализируем файл
|
||||
if err := file.Init(true, linedb.LineDbAdapterOptions{}); err != nil {
|
||||
t.Fatalf("Failed to init file: %v", err)
|
||||
}
|
||||
|
||||
// Тестовые данные
|
||||
testData := map[string]any{
|
||||
"id": 1,
|
||||
"name": "test_user",
|
||||
"age": 25,
|
||||
}
|
||||
|
||||
// Записываем данные
|
||||
if err := file.Write(testData, linedb.LineDbAdapterOptions{}); err != nil {
|
||||
t.Fatalf("Failed to write data: %v", err)
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
result, err := file.Read(linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read data: %v", err)
|
||||
}
|
||||
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("Expected 1 record, got %d", len(result))
|
||||
}
|
||||
|
||||
if record, ok := result[0].(map[string]any); ok {
|
||||
if record["name"] != "test_user" {
|
||||
t.Errorf("Expected 'test_user', got %v", record["name"])
|
||||
}
|
||||
} else {
|
||||
t.Fatal("Failed to cast result to map")
|
||||
}
|
||||
|
||||
fmt.Println("✓ JSONLFile with custom serialization test passed")
|
||||
}
|
||||
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 строке")
|
||||
}
|
||||
1
examples/custom-json/test-custom.jsonl
Normal file
1
examples/custom-json/test-custom.jsonl
Normal file
@@ -0,0 +1 @@
|
||||
{"data":{"age":25,"id":1,"name":"test_user"},"timestamp":1754969067,"version":"1.0"}
|
||||
@@ -0,0 +1 @@
|
||||
{"id":2,"category":"Books","createdAt":1754974225,"inStock":false,"name":"ID First Product","price":123.45,"sellerId":1}
|
||||
@@ -0,0 +1 @@
|
||||
{"id":1,"createdAt":1754974225,"email":"id_first@example.com","isActive":true,"role":"user","username":"id_first_user"}
|
||||
@@ -0,0 +1 @@
|
||||
{"createdAt":1754974225,"email":"standard@example.com","id":2,"isActive":true,"role":"admin","username":"standard_user"}
|
||||
641
examples/delete/delete.go
Normal file
641
examples/delete/delete.go
Normal file
@@ -0,0 +1,641 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"linedb/pkg/linedb"
|
||||
)
|
||||
|
||||
// testDeleteOneRecordByID тестирует удаление одной записи по ID
|
||||
func testDeleteOneRecordByID() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-delete",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "username"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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": "test_user",
|
||||
"email": "test@example.com",
|
||||
"isActive": true,
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(user, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert user: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
users, err := db.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей до удаления: %d\n", len(users))
|
||||
|
||||
// Удаляем запись по ID
|
||||
deleted, err := db.Delete(map[string]any{"id": 1}, "users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete user: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Удалено записей: %d\n", len(deleted))
|
||||
|
||||
// Проверяем результат
|
||||
users, err = db.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users after delete: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей после удаления: %d\n", len(users))
|
||||
}
|
||||
|
||||
// testDeleteOneRecordByTextFilter тестирует удаление одной записи по текстовому фильтру
|
||||
func testDeleteOneRecordByTextFilter() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-delete",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "products",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем тестовые данные
|
||||
product := map[string]any{
|
||||
"id": 1,
|
||||
"name": "Test Product",
|
||||
"price": 99.99,
|
||||
"category": "Electronics",
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(product, "products", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert product: %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(products))
|
||||
|
||||
// Удаляем запись по текстовому фильтру
|
||||
deleted, err := db.Delete("name == 'Test Product'", "products", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete product: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Удалено записей: %d\n", len(deleted))
|
||||
|
||||
// Проверяем результат
|
||||
products, err = db.Read("products", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read products after delete: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей после удаления: %d\n", len(products))
|
||||
}
|
||||
|
||||
// testDeleteMultipleRecordsByArray тестирует удаление нескольких записей по массиву данных
|
||||
func testDeleteMultipleRecordsByArray() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-delete",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "orders",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "status"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем массив тестовых данных
|
||||
orders := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"status": "pending",
|
||||
"amount": 100.0,
|
||||
"customerId": 1,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"status": "completed",
|
||||
"amount": 200.0,
|
||||
"customerId": 2,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 3,
|
||||
"status": "pending",
|
||||
"amount": 150.0,
|
||||
"customerId": 1,
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(orders, "orders", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert orders: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
ordersData, err := db.Read("orders", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read orders: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей до удаления: %d\n", len(ordersData))
|
||||
|
||||
// Удаляем несколько записей по массиву фильтров
|
||||
deleteFilters := []any{
|
||||
map[string]any{"id": 1},
|
||||
map[string]any{"id": 2},
|
||||
}
|
||||
deleted, err := db.Delete(deleteFilters, "orders", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete orders: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Удалено записей: %d\n", len(deleted))
|
||||
|
||||
// Проверяем результат
|
||||
ordersData, err = db.Read("orders", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read orders after delete: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей после удаления: %d\n", len(ordersData))
|
||||
}
|
||||
|
||||
// testDeleteByPartialMatch тестирует удаление записей по частичному совпадению
|
||||
func testDeleteByPartialMatch() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-delete",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "customers",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем массив тестовых данных
|
||||
customers := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"name": "Jane Smith",
|
||||
"email": "jane@example.com",
|
||||
},
|
||||
map[string]any{
|
||||
"id": 3,
|
||||
"name": "John Smith",
|
||||
"email": "john.smith@example.com",
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(customers, "customers", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert customers: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
customersData, err := db.Read("customers", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read customers: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей до удаления: %d\n", len(customersData))
|
||||
|
||||
// Удаляем записи по частичному совпадению
|
||||
deleted, err := db.Delete(
|
||||
map[string]any{"name": "John"},
|
||||
"customers",
|
||||
linedb.LineDbAdapterOptions{StrictCompare: false},
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete customers: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Удалено записей с именем 'John': %d\n", len(deleted))
|
||||
|
||||
// Проверяем результат
|
||||
customersData, err = db.Read("customers", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read customers after delete: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей после удаления: %d\n", len(customersData))
|
||||
}
|
||||
|
||||
// testDeleteFromPartitionedCollections тестирует удаление из партиционированных коллекций
|
||||
func testDeleteFromPartitionedCollections() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных с партициями
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-delete",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "logs",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "level"},
|
||||
},
|
||||
},
|
||||
Partitions: []linedb.PartitionCollection{
|
||||
{
|
||||
CollectionName: "logs",
|
||||
PartIDFnStr: "level",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем логи для разных уровней
|
||||
logs := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"level": "error",
|
||||
"message": "Critical error occurred",
|
||||
"timestamp": time.Now().Unix(),
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"level": "info",
|
||||
"message": "User logged in",
|
||||
"timestamp": time.Now().Unix(),
|
||||
},
|
||||
map[string]any{
|
||||
"id": 3,
|
||||
"level": "error",
|
||||
"message": "Another error",
|
||||
"timestamp": time.Now().Unix(),
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(logs, "logs", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert logs: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
logsData, err := db.Read("logs", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read logs: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей до удаления: %d\n", len(logsData))
|
||||
|
||||
// Удаляем логи с уровнем 'error'
|
||||
deleted, err := db.Delete(map[string]any{"level": "error"}, "logs", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete error logs: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Удалено записей с уровнем 'error': %d\n", len(deleted))
|
||||
|
||||
// Проверяем результат
|
||||
logsData, err = db.Read("logs", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read logs after delete: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей после удаления: %d\n", len(logsData))
|
||||
}
|
||||
|
||||
// testDeleteEdgeCases тестирует граничные случаи удаления
|
||||
func testDeleteEdgeCases() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-delete",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "test_data",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "type"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Тест удаления несуществующей записи
|
||||
fmt.Println(" Тест удаления несуществующей записи:")
|
||||
deleted, err := db.Delete(map[string]any{"id": 999}, "test_data", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete non-existent record: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Удалено несуществующих записей: %d\n", len(deleted))
|
||||
|
||||
// Тест удаления пустого массива
|
||||
fmt.Println(" Тест удаления пустого массива:")
|
||||
deleted, err = db.Delete([]any{}, "test_data", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete empty array: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Удалено записей из пустого массива: %d\n", len(deleted))
|
||||
|
||||
// Тест удаления записей с разными типами ID
|
||||
fmt.Println(" Тест удаления записей с разными типами ID:")
|
||||
|
||||
// Вставляем запись со строковым ID
|
||||
stringIDData := map[string]any{
|
||||
"id": "user-1",
|
||||
"name": "Test String Id User",
|
||||
"type": "string_id",
|
||||
}
|
||||
if err := db.Insert(stringIDData, "test_data", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert string ID data: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Удаляем запись со строковым ID
|
||||
deleted, err = db.Delete("id == 'user-1'", "test_data", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete string ID record: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Удалено записей со строковым ID: %d\n", len(deleted))
|
||||
}
|
||||
|
||||
// testDeletePerformance тестирует производительность удаления
|
||||
func testDeletePerformance() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 10000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-delete",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "performance_data",
|
||||
AllocSize: 1024,
|
||||
IndexedFields: []string{"id", "category"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем большое количество записей
|
||||
recordCount := 1000
|
||||
fmt.Printf(" Создание %d записей для теста производительности...\n", recordCount)
|
||||
|
||||
largeDataArray := make([]any, recordCount)
|
||||
for i := 1; i <= recordCount; i++ {
|
||||
largeDataArray[i-1] = map[string]any{
|
||||
"id": i,
|
||||
"name": fmt.Sprintf("User %d", i),
|
||||
"category": fmt.Sprintf("Category %d", (i-1)%10+1),
|
||||
"value": float64(i) * 1.5,
|
||||
}
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(largeDataArray, "performance_data", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert large data array: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные для проверки
|
||||
result, err := db.Read("performance_data", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read large data: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей в базе: %d\n", len(result))
|
||||
|
||||
// Удаляем половину записей (четные ID)
|
||||
startTime := time.Now()
|
||||
itemsToDelete := make([]any, recordCount/2)
|
||||
for i := 0; i < recordCount/2; i++ {
|
||||
itemsToDelete[i] = map[string]any{"id": (i + 1) * 2}
|
||||
}
|
||||
|
||||
deleted, err := db.Delete(itemsToDelete, "performance_data", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete large number of records: %v", err)
|
||||
return
|
||||
}
|
||||
endTime := time.Now()
|
||||
|
||||
duration := endTime.Sub(startTime)
|
||||
fmt.Printf(" Удалено записей: %d\n", len(deleted))
|
||||
fmt.Printf(" Время выполнения: %v\n", duration)
|
||||
|
||||
// Проверяем результат
|
||||
result, err = db.Read("performance_data", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read data after bulk delete: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Записей после массового удаления: %d\n", len(result))
|
||||
}
|
||||
|
||||
// testDeleteMultipleCollections тестирует удаление из множественных коллекций
|
||||
func testDeleteMultipleCollections() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных с множественными коллекциями
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-delete",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "username"},
|
||||
},
|
||||
{
|
||||
CollectionName: "posts",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "authorId"},
|
||||
},
|
||||
{
|
||||
CollectionName: "comments",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "postId"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем данные для разных коллекций
|
||||
users := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"username": "user1",
|
||||
"email": "user1@example.com",
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"username": "user2",
|
||||
"email": "user2@example.com",
|
||||
},
|
||||
}
|
||||
|
||||
posts := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"title": "First Post",
|
||||
"authorId": 1,
|
||||
"content": "This is the first post",
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"title": "Second Post",
|
||||
"authorId": 2,
|
||||
"content": "This is the second post",
|
||||
},
|
||||
}
|
||||
|
||||
comments := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"postId": 1,
|
||||
"content": "Great post!",
|
||||
"authorId": 2,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"postId": 2,
|
||||
"content": "Nice article",
|
||||
"authorId": 1,
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем данные в разные коллекции
|
||||
if err := db.Insert(users, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert users: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := db.Insert(posts, "posts", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert posts: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := db.Insert(comments, "comments", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert comments: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Удаляем данные из разных коллекций
|
||||
usersDeleted, _ := db.Delete(map[string]any{"id": 1}, "users", linedb.LineDbAdapterOptions{})
|
||||
postsDeleted, _ := db.Delete(map[string]any{"authorId": 1}, "posts", linedb.LineDbAdapterOptions{})
|
||||
commentsDeleted, _ := db.Delete(map[string]any{"postId": 1}, "comments", linedb.LineDbAdapterOptions{})
|
||||
|
||||
// Читаем данные из всех коллекций
|
||||
usersData, _ := db.Read("users", linedb.LineDbAdapterOptions{})
|
||||
postsData, _ := db.Read("posts", linedb.LineDbAdapterOptions{})
|
||||
commentsData, _ := db.Read("comments", linedb.LineDbAdapterOptions{})
|
||||
|
||||
fmt.Printf(" Удалено пользователей: %d\n", len(usersDeleted))
|
||||
fmt.Printf(" Удалено постов: %d\n", len(postsDeleted))
|
||||
fmt.Printf(" Удалено комментариев: %d\n", len(commentsDeleted))
|
||||
fmt.Printf(" Осталось пользователей: %d\n", len(usersData))
|
||||
fmt.Printf(" Осталось постов: %d\n", len(postsData))
|
||||
fmt.Printf(" Осталось комментариев: %d\n", len(commentsData))
|
||||
}
|
||||
167
examples/delete/main.go
Normal file
167
examples/delete/main.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TestData представляет тестовые данные
|
||||
type TestData struct {
|
||||
ID any `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Value *int `json:"value,omitempty"`
|
||||
UserID int `json:"userId"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// TestUser представляет пользователя
|
||||
type TestUser struct {
|
||||
ID int `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
IsActive bool `json:"isActive"`
|
||||
Role string `json:"role"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// TestOrder представляет заказ
|
||||
type TestOrder struct {
|
||||
ID int `json:"id"`
|
||||
UserID int `json:"userId"`
|
||||
Status string `json:"status"`
|
||||
Amount float64 `json:"amount"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Очищаем тестовую папку
|
||||
os.RemoveAll("./data/test-linedb-delete")
|
||||
|
||||
fmt.Println("=== LineDb Delete Operations 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 > 8 {
|
||||
fmt.Printf("Ошибка: номер теста %d должен быть от 1 до 8\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 - Удаление одной записи по ID")
|
||||
fmt.Println(" 2 - Удаление одной записи по текстовому фильтру")
|
||||
fmt.Println(" 3 - Удаление нескольких записей по массиву данных")
|
||||
fmt.Println(" 4 - Удаление записей по частичному совпадению")
|
||||
fmt.Println(" 5 - Удаление записей из партиционированных коллекций")
|
||||
fmt.Println(" 6 - Удаление записей с граничными случаями")
|
||||
fmt.Println(" 7 - Удаление записей с производительностью")
|
||||
fmt.Println(" 8 - Удаление записей с множественными коллекциями")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// runAllTests запускает все тесты
|
||||
func runAllTests() {
|
||||
testDeleteOneRecordByID()
|
||||
testDeleteOneRecordByTextFilter()
|
||||
testDeleteMultipleRecordsByArray()
|
||||
testDeleteByPartialMatch()
|
||||
testDeleteFromPartitionedCollections()
|
||||
testDeleteEdgeCases()
|
||||
testDeletePerformance()
|
||||
testDeleteMultipleCollections()
|
||||
}
|
||||
|
||||
// runSelectedTests запускает только выбранные тесты
|
||||
func runSelectedTests(numbers []int) {
|
||||
for _, num := range numbers {
|
||||
switch num {
|
||||
case 1:
|
||||
fmt.Println("1. Удаление одной записи по ID")
|
||||
testDeleteOneRecordByID()
|
||||
case 2:
|
||||
fmt.Println("2. Удаление одной записи по текстовому фильтру")
|
||||
testDeleteOneRecordByTextFilter()
|
||||
case 3:
|
||||
fmt.Println("3. Удаление нескольких записей по массиву данных")
|
||||
testDeleteMultipleRecordsByArray()
|
||||
case 4:
|
||||
fmt.Println("4. Удаление записей по частичному совпадению")
|
||||
testDeleteByPartialMatch()
|
||||
case 5:
|
||||
fmt.Println("5. Удаление записей из партиционированных коллекций")
|
||||
testDeleteFromPartitionedCollections()
|
||||
case 6:
|
||||
fmt.Println("6. Удаление записей с граничными случаями")
|
||||
testDeleteEdgeCases()
|
||||
case 7:
|
||||
fmt.Println("7. Удаление записей с производительностью")
|
||||
testDeletePerformance()
|
||||
case 8:
|
||||
fmt.Println("8. Удаление записей с множественными коллекциями")
|
||||
testDeleteMultipleCollections()
|
||||
}
|
||||
}
|
||||
}
|
||||
592
examples/insert/insert.go
Normal file
592
examples/insert/insert.go
Normal file
@@ -0,0 +1,592 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"linedb/pkg/linedb"
|
||||
)
|
||||
|
||||
// testSingleInsert тестирует вставку одной записи
|
||||
func testSingleInsert() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-insert",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "username"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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": "john_doe",
|
||||
"email": "john@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
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
users, err := db.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Пользователей в базе: %d\n", len(users))
|
||||
if len(users) > 0 {
|
||||
if record, ok := users[0].(map[string]any); ok {
|
||||
fmt.Printf(" ID: %v, Username: %s\n", record["id"], record["username"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testArrayInsert тестирует вставку массива записей
|
||||
func testArrayInsert() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-insert",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "products",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем массив продуктов
|
||||
products := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"name": "Laptop",
|
||||
"price": 999.99,
|
||||
"category": "Electronics",
|
||||
"inStock": true,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"name": "Mouse",
|
||||
"price": 29.99,
|
||||
"category": "Electronics",
|
||||
"inStock": true,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 3,
|
||||
"name": "Keyboard",
|
||||
"price": 79.99,
|
||||
"category": "Electronics",
|
||||
"inStock": false,
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(products, "products", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert products: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
productsData, err := db.Read("products", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read products: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Продуктов в базе: %d\n", len(productsData))
|
||||
for i, product := range productsData {
|
||||
if record, ok := product.(map[string]any); ok {
|
||||
fmt.Printf(" %d. ID: %v, Name: %s, Price: %v\n", i+1, record["id"], record["name"], record["price"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testAutoID тестирует автоматическую генерацию ID
|
||||
func testAutoID() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-insert",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "orders",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "customerId"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем заказы без ID
|
||||
orders := []any{
|
||||
map[string]any{
|
||||
"customerId": 1,
|
||||
"amount": 150.00,
|
||||
"status": "pending",
|
||||
"createdAt": time.Now().Unix(),
|
||||
},
|
||||
map[string]any{
|
||||
"customerId": 2,
|
||||
"amount": 75.50,
|
||||
"status": "completed",
|
||||
"createdAt": time.Now().Unix(),
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(orders, "orders", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert orders: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
ordersData, err := db.Read("orders", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read orders: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Заказов в базе: %d\n", len(ordersData))
|
||||
for i, order := range ordersData {
|
||||
if record, ok := order.(map[string]any); ok {
|
||||
fmt.Printf(" %d. ID: %v, Customer: %v, Amount: %v\n", i+1, record["id"], record["customerId"], record["amount"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testPartitionedCollections тестирует партиционированные коллекции
|
||||
func testPartitionedCollections() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных с партиционированными коллекциями
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-insert",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users_2024",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "username"},
|
||||
},
|
||||
{
|
||||
CollectionName: "users_2023",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "username"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем пользователей для разных партиций
|
||||
users2024 := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"username": "user_2024_1",
|
||||
"email": "user1@2024.com",
|
||||
"year": 2024,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"username": "user_2024_2",
|
||||
"email": "user2@2024.com",
|
||||
"year": 2024,
|
||||
},
|
||||
}
|
||||
|
||||
users2023 := []any{
|
||||
map[string]any{
|
||||
"id": 3,
|
||||
"username": "user_2023_1",
|
||||
"email": "user1@2023.com",
|
||||
"year": 2023,
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем данные в разные партиции
|
||||
if err := db.Insert(users2024, "users_2024", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert users 2024: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := db.Insert(users2023, "users_2023", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert users 2023: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные из обеих партиций
|
||||
users2024Data, err := db.Read("users_2024", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users 2024: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
users2023Data, err := db.Read("users_2023", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users 2023: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Пользователей 2024: %d\n", len(users2024Data))
|
||||
fmt.Printf(" Пользователей 2023: %d\n", len(users2023Data))
|
||||
}
|
||||
|
||||
// testUniquenessCheck тестирует проверку уникальности
|
||||
func testUniquenessCheck() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-insert",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "unique_users",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "email"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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": "unique_user",
|
||||
"email": "unique@example.com",
|
||||
"isActive": true,
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(user, "unique_users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert user: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Пытаемся вставить пользователя с тем же email
|
||||
duplicateUser := map[string]any{
|
||||
"id": 2,
|
||||
"username": "duplicate_user",
|
||||
"email": "unique@example.com", // Тот же email
|
||||
"isActive": true,
|
||||
}
|
||||
|
||||
if err := db.Insert(duplicateUser, "unique_users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
fmt.Printf(" Ожидаемая ошибка дублирования: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" Дублирование не обнаружено\n")
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
users, err := db.Read("unique_users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Уникальных пользователей: %d\n", len(users))
|
||||
}
|
||||
|
||||
// testDifferentDataTypes тестирует различные типы данных
|
||||
func testDifferentDataTypes() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-insert",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "mixed_data",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "type"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем данные разных типов
|
||||
mixedData := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"type": "string",
|
||||
"value": "Hello World",
|
||||
"isString": true,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"type": "number",
|
||||
"value": 42.5,
|
||||
"isNumber": true,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 3,
|
||||
"type": "boolean",
|
||||
"value": true,
|
||||
"isBool": true,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 4,
|
||||
"type": "array",
|
||||
"value": []any{1, 2, 3, "four"},
|
||||
"isArray": true,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 5,
|
||||
"type": "object",
|
||||
"value": map[string]any{"nested": "value", "count": 10},
|
||||
"isObject": true,
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
if err := db.Insert(mixedData, "mixed_data", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert mixed data: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные
|
||||
data, err := db.Read("mixed_data", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read mixed data: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Записей с разными типами данных: %d\n", len(data))
|
||||
for i, record := range data {
|
||||
if item, ok := record.(map[string]any); ok {
|
||||
fmt.Printf(" %d. ID: %v, Type: %s\n", i+1, item["id"], item["type"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testBulkInsert тестирует массовую вставку
|
||||
func testBulkInsert() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 10000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-insert",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "bulk_items",
|
||||
AllocSize: 1024,
|
||||
IndexedFields: []string{"id", "category"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем большое количество записей
|
||||
var bulkItems []any
|
||||
for i := 1; i <= 1000; i++ {
|
||||
item := map[string]any{
|
||||
"id": i,
|
||||
"name": fmt.Sprintf("Item %d", i),
|
||||
"category": fmt.Sprintf("Category %d", (i-1)%10+1),
|
||||
"price": float64(i) * 1.5,
|
||||
"inStock": i%2 == 0,
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
bulkItems = append(bulkItems, item)
|
||||
}
|
||||
|
||||
// Вставляем данные
|
||||
startTime := time.Now()
|
||||
if err := db.Insert(bulkItems, "bulk_items", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert bulk items: %v", err)
|
||||
return
|
||||
}
|
||||
insertTime := time.Since(startTime)
|
||||
|
||||
// Читаем данные
|
||||
startTime = time.Now()
|
||||
items, err := db.Read("bulk_items", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read bulk items: %v", err)
|
||||
return
|
||||
}
|
||||
readTime := time.Since(startTime)
|
||||
|
||||
fmt.Printf(" Массовая вставка: %d записей за %v\n", len(items), insertTime)
|
||||
fmt.Printf(" Чтение: %d записей за %v\n", len(items), readTime)
|
||||
}
|
||||
|
||||
// testMultipleCollections тестирует работу с множественными коллекциями
|
||||
func testMultipleCollections() {
|
||||
// Создаем базу данных
|
||||
db := linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных с множественными коллекциями
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-insert",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "customers",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "email"},
|
||||
},
|
||||
{
|
||||
CollectionName: "orders",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "customerId"},
|
||||
},
|
||||
{
|
||||
CollectionName: "products",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := db.Init(true, initOptions); err != nil {
|
||||
log.Printf("Failed to init database: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Создаем данные для разных коллекций
|
||||
customers := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"isActive": true,
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"name": "Jane Smith",
|
||||
"email": "jane@example.com",
|
||||
"isActive": true,
|
||||
},
|
||||
}
|
||||
|
||||
orders := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"customerId": 1,
|
||||
"amount": 150.00,
|
||||
"status": "completed",
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"customerId": 2,
|
||||
"amount": 75.50,
|
||||
"status": "pending",
|
||||
},
|
||||
}
|
||||
|
||||
products := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"name": "Laptop",
|
||||
"price": 999.99,
|
||||
"category": "Electronics",
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"name": "Mouse",
|
||||
"price": 29.99,
|
||||
"category": "Electronics",
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем данные в разные коллекции
|
||||
if err := db.Insert(customers, "customers", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert customers: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := db.Insert(orders, "orders", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert orders: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := db.Insert(products, "products", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert products: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные из всех коллекций
|
||||
customersData, _ := db.Read("customers", linedb.LineDbAdapterOptions{})
|
||||
ordersData, _ := db.Read("orders", linedb.LineDbAdapterOptions{})
|
||||
productsData, _ := db.Read("products", linedb.LineDbAdapterOptions{})
|
||||
|
||||
fmt.Printf(" Коллекций: 3\n")
|
||||
fmt.Printf(" Клиентов: %d\n", len(customersData))
|
||||
fmt.Printf(" Заказов: %d\n", len(ordersData))
|
||||
fmt.Printf(" Продуктов: %d\n", len(productsData))
|
||||
}
|
||||
138
examples/insert/main.go
Normal file
138
examples/insert/main.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Очищаем тестовые данные
|
||||
os.RemoveAll("./data/test-linedb-insert")
|
||||
|
||||
fmt.Println("=== LineDb Insert Operations 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 > 8 {
|
||||
fmt.Printf("Ошибка: номер теста %d должен быть от 1 до 8\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 - Вставка одной записи")
|
||||
fmt.Println(" 2 - Вставка массива записей")
|
||||
fmt.Println(" 3 - Автоматическая генерация ID")
|
||||
fmt.Println(" 4 - Партиционированные коллекции")
|
||||
fmt.Println(" 5 - Проверка уникальности")
|
||||
fmt.Println(" 6 - Различные типы данных")
|
||||
fmt.Println(" 7 - Массовая вставка")
|
||||
fmt.Println(" 8 - Множественные коллекции")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// runAllTests запускает все тесты
|
||||
func runAllTests() {
|
||||
testSingleInsert()
|
||||
testArrayInsert()
|
||||
testAutoID()
|
||||
testPartitionedCollections()
|
||||
testUniquenessCheck()
|
||||
testDifferentDataTypes()
|
||||
testBulkInsert()
|
||||
testMultipleCollections()
|
||||
}
|
||||
|
||||
// runSelectedTests запускает только выбранные тесты
|
||||
func runSelectedTests(numbers []int) {
|
||||
for _, num := range numbers {
|
||||
switch num {
|
||||
case 1:
|
||||
fmt.Println("1. Вставка одной записи")
|
||||
testSingleInsert()
|
||||
case 2:
|
||||
fmt.Println("2. Вставка массива записей")
|
||||
testArrayInsert()
|
||||
case 3:
|
||||
fmt.Println("3. Автоматическая генерация ID")
|
||||
testAutoID()
|
||||
case 4:
|
||||
fmt.Println("4. Партиционированные коллекции")
|
||||
testPartitionedCollections()
|
||||
case 5:
|
||||
fmt.Println("5. Проверка уникальности")
|
||||
testUniquenessCheck()
|
||||
case 6:
|
||||
fmt.Println("6. Различные типы данных")
|
||||
testDifferentDataTypes()
|
||||
case 7:
|
||||
fmt.Println("7. Массовая вставка")
|
||||
testBulkInsert()
|
||||
case 8:
|
||||
fmt.Println("8. Множественные коллекции")
|
||||
testMultipleCollections()
|
||||
}
|
||||
}
|
||||
}
|
||||
1
examples/insert/test-linedb-insert/users.jsonl
Normal file
1
examples/insert/test-linedb-insert/users.jsonl
Normal file
@@ -0,0 +1 @@
|
||||
{"createdAt":1754974407,"email":"john@example.com","id":1,"isActive":true,"role":"user","username":"john_doe"}
|
||||
722
examples/integration/main.go
Normal file
722
examples/integration/main.go
Normal file
@@ -0,0 +1,722 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"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"`
|
||||
LastLogin *int64 `json:"lastLogin,omitempty"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// Order представляет заказ
|
||||
type Order struct {
|
||||
ID int `json:"id"`
|
||||
UserID int `json:"userId"`
|
||||
ProductID int `json:"productId"`
|
||||
Quantity int `json:"quantity"`
|
||||
TotalPrice float64 `json:"totalPrice"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// OrderItem представляет элемент заказа
|
||||
type OrderItem struct {
|
||||
ID int `json:"id"`
|
||||
OrderID int `json:"orderId"`
|
||||
ProductID int `json:"productId"`
|
||||
Quantity int `json:"quantity"`
|
||||
Price float64 `json:"price"`
|
||||
}
|
||||
|
||||
// APIResponse представляет ответ API
|
||||
type APIResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
var Database *linedb.LineDb
|
||||
var server *http.Server
|
||||
|
||||
// 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 - Базовые CRUD операции")
|
||||
fmt.Println(" 2 - Сложные запросы и фильтрация")
|
||||
fmt.Println(" 3 - Работа с несколькими коллекциями")
|
||||
fmt.Println(" 4 - Тест производительности")
|
||||
fmt.Println(" 5 - HTTP API сервер")
|
||||
fmt.Println(" 6 - API endpoints")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// runAllTests запускает все тесты
|
||||
func runAllTests() {
|
||||
testBasicCRUDOperations()
|
||||
testComplexQueries()
|
||||
testMultipleCollections()
|
||||
testPerformance()
|
||||
testHTTPServer()
|
||||
testAPIEndpoints()
|
||||
}
|
||||
|
||||
// runSelectedTests запускает только выбранные тесты
|
||||
func runSelectedTests(numbers []int) {
|
||||
for _, num := range numbers {
|
||||
switch num {
|
||||
case 1:
|
||||
fmt.Println("1. Базовые CRUD операции")
|
||||
testBasicCRUDOperations()
|
||||
case 2:
|
||||
fmt.Println("2. Сложные запросы и фильтрация")
|
||||
testComplexQueries()
|
||||
case 3:
|
||||
fmt.Println("3. Работа с несколькими коллекциями")
|
||||
testMultipleCollections()
|
||||
case 4:
|
||||
fmt.Println("4. Тест производительности")
|
||||
testPerformance()
|
||||
case 5:
|
||||
fmt.Println("5. HTTP API сервер")
|
||||
testHTTPServer()
|
||||
case 6:
|
||||
fmt.Println("6. API endpoints")
|
||||
testAPIEndpoints()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBasicCRUDOperations() {
|
||||
// Создаем пользователя
|
||||
user := map[string]any{
|
||||
"id": 1,
|
||||
"username": "testuser",
|
||||
"email": "test@example.com",
|
||||
"isActive": true,
|
||||
"role": "user",
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Вставка
|
||||
if err := Database.Insert(user, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert user: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("\tПользователь создан: %s\n", user["username"])
|
||||
|
||||
// Чтение
|
||||
result, err := Database.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("\tПользователей в базе: %d\n", len(result))
|
||||
|
||||
// Обновление
|
||||
updateData := map[string]any{"role": "admin"}
|
||||
updated, err := Database.Update(updateData, "users", map[string]any{"id": 1}, linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to update user: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Обновлено пользователей: %d\n", len(updated))
|
||||
|
||||
// Удаление
|
||||
deleted, err := Database.Delete(map[string]any{"id": 1}, "users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete user: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Удалено пользователей: %d\n", len(deleted))
|
||||
|
||||
// Проверяем, что пользователь удален
|
||||
result, err = Database.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users after delete: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Пользователей после удаления: %d\n", len(result))
|
||||
}
|
||||
|
||||
func testComplexQueries() {
|
||||
// Создаем несколько пользователей
|
||||
users := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"username": "john_doe",
|
||||
"email": "john@example.com",
|
||||
"isActive": true,
|
||||
"role": "user",
|
||||
"createdAt": time.Now().Unix(),
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"username": "jane_smith",
|
||||
"email": "jane@example.com",
|
||||
"isActive": true,
|
||||
"role": "admin",
|
||||
"createdAt": time.Now().Unix(),
|
||||
},
|
||||
map[string]any{
|
||||
"id": 3,
|
||||
"username": "bob_wilson",
|
||||
"email": "bob@example.com",
|
||||
"isActive": false,
|
||||
"role": "user",
|
||||
"createdAt": time.Now().Unix(),
|
||||
},
|
||||
}
|
||||
|
||||
if err := Database.Insert(users, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert users: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Фильтрация по роли
|
||||
admins, err := Database.ReadByFilter(map[string]any{"role": "admin"}, "users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to filter admins: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Администраторов: %d\n", len(admins))
|
||||
|
||||
// Фильтрация по активности
|
||||
activeUsers, err := Database.ReadByFilter(map[string]any{"isActive": true}, "users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to filter active users: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Активных пользователей: %d\n", len(activeUsers))
|
||||
|
||||
// Строковая фильтрация
|
||||
emailFilter, err := Database.ReadByFilter("email == 'john@example.com'", "users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to filter by email: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Пользователей с email john@example.com: %d\n", len(emailFilter))
|
||||
|
||||
// Частичное совпадение
|
||||
partialMatch, err := Database.ReadByFilter(
|
||||
map[string]any{"username": "john"},
|
||||
"users",
|
||||
linedb.LineDbAdapterOptions{StrictCompare: false},
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to partial match: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Пользователей с именем содержащим 'john': %d\n", len(partialMatch))
|
||||
}
|
||||
|
||||
func testMultipleCollections() {
|
||||
// Создаем пользователя
|
||||
user := map[string]any{
|
||||
"id": 1,
|
||||
"username": "customer1",
|
||||
"email": "customer1@example.com",
|
||||
"isActive": true,
|
||||
"role": "customer",
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Создаем продукты
|
||||
products := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"name": "Laptop",
|
||||
"price": 999.99,
|
||||
"category": "Electronics",
|
||||
"inStock": true,
|
||||
"sellerId": 1,
|
||||
"createdAt": time.Now().Unix(),
|
||||
},
|
||||
map[string]any{
|
||||
"id": 2,
|
||||
"name": "Mouse",
|
||||
"price": 29.99,
|
||||
"category": "Electronics",
|
||||
"inStock": true,
|
||||
"sellerId": 1,
|
||||
"createdAt": time.Now().Unix(),
|
||||
},
|
||||
}
|
||||
|
||||
// Создаем заказ
|
||||
order := map[string]any{
|
||||
"id": 1,
|
||||
"userId": 1,
|
||||
"productId": 1,
|
||||
"quantity": 2,
|
||||
"totalPrice": 1999.98,
|
||||
"status": "pending",
|
||||
"createdAt": time.Now().Unix(),
|
||||
"updatedAt": time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Создаем элементы заказа
|
||||
orderItems := []any{
|
||||
map[string]any{
|
||||
"id": 1,
|
||||
"orderId": 1,
|
||||
"productId": 1,
|
||||
"quantity": 2,
|
||||
"price": 999.99,
|
||||
},
|
||||
}
|
||||
|
||||
// Вставляем данные во все коллекции
|
||||
if err := Database.Insert(user, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert user: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := Database.Insert(products, "products", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert products: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := Database.Insert(order, "orders", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert order: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := Database.Insert(orderItems, "orderItems", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert order items: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Читаем данные из всех коллекций
|
||||
users, err := Database.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
productsData, err := Database.Read("products", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read products: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
orders, err := Database.Read("orders", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read orders: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
orderItemsData, err := Database.Read("orderItems", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read order items: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(" Пользователей: %d\n", len(users))
|
||||
fmt.Printf(" Продуктов: %d\n", len(productsData))
|
||||
fmt.Printf(" Заказов: %d\n", len(orders))
|
||||
fmt.Printf(" Элементов заказов: %d\n", len(orderItemsData))
|
||||
|
||||
// Сложный запрос: найти все заказы пользователя
|
||||
userOrders, err := Database.ReadByFilter(map[string]any{"userId": 1}, "orders", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to get user orders: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Заказов пользователя 1: %d\n", len(userOrders))
|
||||
}
|
||||
|
||||
func testPerformance() {
|
||||
// Тест производительности массовой вставки
|
||||
recordCount := 500
|
||||
fmt.Printf(" Создание %d записей для теста производительности...\n", recordCount)
|
||||
|
||||
// Создаем пользователей
|
||||
users := make([]any, recordCount)
|
||||
for i := 1; i <= recordCount; i++ {
|
||||
users[i-1] = map[string]any{
|
||||
"id": i,
|
||||
"username": fmt.Sprintf("user%d", i),
|
||||
"email": fmt.Sprintf("user%d@example.com", i),
|
||||
"isActive": i%2 == 0, // чередуем активных и неактивных
|
||||
"role": "user",
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
}
|
||||
|
||||
// Измеряем время вставки
|
||||
startTime := time.Now()
|
||||
if err := Database.Insert(users, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
log.Printf("Failed to insert users: %v", err)
|
||||
return
|
||||
}
|
||||
endTime := time.Now()
|
||||
|
||||
duration := endTime.Sub(startTime)
|
||||
fmt.Printf(" Вставлено пользователей: %d\n", recordCount)
|
||||
fmt.Printf(" Время выполнения: %v\n", duration)
|
||||
fmt.Printf(" Скорость: %.2f записей/сек\n", float64(recordCount)/duration.Seconds())
|
||||
|
||||
// Тест производительности чтения
|
||||
startTime = time.Now()
|
||||
result, err := Database.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to read users: %v", err)
|
||||
return
|
||||
}
|
||||
endTime = time.Now()
|
||||
|
||||
readDuration := endTime.Sub(startTime)
|
||||
fmt.Printf(" Прочитано пользователей: %d\n", len(result))
|
||||
fmt.Printf(" Время чтения: %v\n", readDuration)
|
||||
fmt.Printf(" Скорость чтения: %.2f записей/сек\n", float64(len(result))/readDuration.Seconds())
|
||||
|
||||
// Тест производительности фильтрации
|
||||
startTime = time.Now()
|
||||
activeUsers, err := Database.ReadByFilter(map[string]any{"isActive": true}, "users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Failed to filter active users: %v", err)
|
||||
return
|
||||
}
|
||||
endTime = time.Now()
|
||||
|
||||
filterDuration := endTime.Sub(startTime)
|
||||
fmt.Printf(" Активных пользователей: %d\n", len(activeUsers))
|
||||
fmt.Printf(" Время фильтрации: %v\n", filterDuration)
|
||||
}
|
||||
|
||||
func testHTTPServer() {
|
||||
// Настраиваем HTTP сервер
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// Обработчики API
|
||||
mux.HandleFunc("/api/users", handleUsers)
|
||||
mux.HandleFunc("/api/products", handleProducts)
|
||||
mux.HandleFunc("/api/orders", handleOrders)
|
||||
|
||||
server = &http.Server{
|
||||
Addr: ":3001",
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
fmt.Printf(" Запуск HTTP сервера на порту 3001...\n")
|
||||
fmt.Printf(" Доступные эндпоинты:\n")
|
||||
fmt.Printf(" - GET /api/users - получить всех пользователей\n")
|
||||
fmt.Printf(" - POST /api/users - создать пользователя\n")
|
||||
fmt.Printf(" - GET /api/products - получить все продукты\n")
|
||||
fmt.Printf(" - POST /api/products - создать продукт\n")
|
||||
fmt.Printf(" - GET /api/orders - получить все заказы\n")
|
||||
fmt.Printf(" - POST /api/orders - создать заказ\n")
|
||||
|
||||
// Запускаем сервер в горутине
|
||||
go func() {
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Printf("HTTP server error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Даем серверу время на запуск
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Тестируем API
|
||||
fmt.Printf(" Тестирование API...\n")
|
||||
testAPIEndpoints()
|
||||
|
||||
// Останавливаем сервер
|
||||
if err := server.Close(); err != nil {
|
||||
log.Printf("Failed to close server: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func handleUsers(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
users, err := Database.Read("users", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: true, Data: users})
|
||||
|
||||
case "POST":
|
||||
var user map[string]any
|
||||
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := Database.Insert(user, "users", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: true, Message: "User created successfully"})
|
||||
|
||||
default:
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func handleProducts(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
products, err := Database.Read("products", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: true, Data: products})
|
||||
|
||||
case "POST":
|
||||
var product map[string]any
|
||||
if err := json.NewDecoder(r.Body).Decode(&product); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := Database.Insert(product, "products", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: true, Message: "Product created successfully"})
|
||||
|
||||
default:
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func handleOrders(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
orders, err := Database.Read("orders", linedb.LineDbAdapterOptions{})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: true, Data: orders})
|
||||
|
||||
case "POST":
|
||||
var order map[string]any
|
||||
if err := json.NewDecoder(r.Body).Decode(&order); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := Database.Insert(order, "orders", linedb.LineDbAdapterOptions{}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: true, Message: "Order created successfully"})
|
||||
|
||||
default:
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func testAPIEndpoints() {
|
||||
// Тестируем GET /api/users
|
||||
resp, err := http.Get("http://localhost:3001/api/users")
|
||||
if err != nil {
|
||||
log.Printf("Failed to test GET /api/users: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
fmt.Printf(" ✓ GET /api/users работает\n")
|
||||
} else {
|
||||
fmt.Printf(" ✗ GET /api/users вернул статус %d\n", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Тестируем POST /api/users
|
||||
userData := map[string]any{
|
||||
"id": 999,
|
||||
"username": "apitest",
|
||||
"email": "apitest@example.com",
|
||||
"isActive": true,
|
||||
"role": "user",
|
||||
"createdAt": time.Now().Unix(),
|
||||
}
|
||||
|
||||
jsonData, _ := json.Marshal(userData)
|
||||
resp, err = http.Post("http://localhost:3001/api/users", "application/json", bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
log.Printf("Failed to test POST /api/users: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
fmt.Printf(" ✓ POST /api/users работает\n")
|
||||
} else {
|
||||
fmt.Printf(" ✗ POST /api/users вернул статус %d\n", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Очищаем тестовую папку
|
||||
os.RemoveAll("./data/test-linedb-integration")
|
||||
|
||||
// Создаем опции инициализации
|
||||
initOptions := &linedb.LineDbInitOptions{
|
||||
CacheSize: 1000,
|
||||
CacheTTL: 10 * time.Second,
|
||||
DBFolder: "./data/test-linedb-integration",
|
||||
Collections: []linedb.JSONLFileOptions{
|
||||
{
|
||||
CollectionName: "users",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "username", "email"},
|
||||
},
|
||||
{
|
||||
CollectionName: "products",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "name", "category"},
|
||||
},
|
||||
{
|
||||
CollectionName: "orders",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "userId", "status"},
|
||||
},
|
||||
{
|
||||
CollectionName: "orderItems",
|
||||
AllocSize: 256,
|
||||
IndexedFields: []string{"id", "orderId", "productId"},
|
||||
},
|
||||
},
|
||||
Partitions: []linedb.PartitionCollection{
|
||||
{
|
||||
CollectionName: "orders",
|
||||
PartIDFnStr: "userId",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Создаем базу данных
|
||||
Database = linedb.NewLineDb(nil)
|
||||
|
||||
// Инициализируем базу данных
|
||||
if err := Database.Init(true, initOptions); err != nil {
|
||||
log.Fatalf("Failed to init database: %v", err)
|
||||
}
|
||||
defer Database.Close()
|
||||
|
||||
fmt.Println("=== LineDb Integration Tests Demo ===")
|
||||
|
||||
numbers := parseTestNumbers()
|
||||
if len(numbers) > 0 {
|
||||
runSelectedTests(numbers)
|
||||
} else {
|
||||
runAllTests()
|
||||
}
|
||||
|
||||
// // Тест 1: Базовые CRUD операции
|
||||
// fmt.Println("1. Базовые CRUD операции")
|
||||
// testBasicCRUDOperations()
|
||||
|
||||
// // Тест 2: Сложные запросы и фильтрация
|
||||
// fmt.Println("\n2. Сложные запросы и фильтрация")
|
||||
// testComplexQueries()
|
||||
|
||||
// // Тест 3: Работа с несколькими коллекциями
|
||||
// fmt.Println("\n3. Работа с несколькими коллекциями")
|
||||
// testMultipleCollections()
|
||||
|
||||
// // Тест 4: Производительность
|
||||
// fmt.Println("\n4. Тест производительности")
|
||||
// testPerformance()
|
||||
|
||||
// // Тест 5: HTTP API сервер
|
||||
// fmt.Println("\n5. HTTP API сервер")
|
||||
// testHTTPServer()
|
||||
|
||||
fmt.Println("\n=== Все тесты завершены ===")
|
||||
}
|
||||
Reference in New Issue
Block a user