mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
Some checks failed
CI/CD Pipeline / frontend-lint (push) Successful in 1m38s
CI/CD Pipeline / backend-lint (push) Failing after 1m41s
CI/CD Pipeline / backend-build (push) Has been skipped
CI/CD Pipeline / frontend-build (push) Failing after 26s
CI/CD Pipeline / e2e-test (push) Has been skipped
- Update .gitignore to selectively ignore pkg/ directories at the root level - Modify CI workflow to verify all Go packages can be listed - Introduce configuration management with a new config package, including loading environment variables - Add comprehensive tests for configuration loading and environment variable handling - Implement Neo4j database interaction functions with corresponding tests for data extraction
206 lines
5.5 KiB
Go
206 lines
5.5 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
|
|
)
|
|
|
|
// Neo4jConfig holds configuration for Neo4j connection
|
|
type Neo4jConfig struct {
|
|
URI string
|
|
Username string
|
|
Password string
|
|
Database string
|
|
}
|
|
|
|
// NewNeo4jDriver creates a new Neo4j driver instance
|
|
func NewNeo4jDriver(config Neo4jConfig) (neo4j.DriverWithContext, error) {
|
|
driver, err := neo4j.NewDriverWithContext(
|
|
config.URI,
|
|
neo4j.BasicAuth(config.Username, config.Password, ""),
|
|
func(c *neo4j.Config) {
|
|
c.MaxConnectionPoolSize = 50
|
|
c.ConnectionAcquisitionTimeout = 30 * time.Second
|
|
c.MaxTransactionRetryTime = 30 * time.Second
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create Neo4j driver: %w", err)
|
|
}
|
|
|
|
// Verify connectivity
|
|
ctx := context.Background()
|
|
if err := driver.VerifyConnectivity(ctx); err != nil {
|
|
driver.Close(ctx)
|
|
return nil, fmt.Errorf("failed to verify Neo4j connectivity: %w", err)
|
|
}
|
|
|
|
return driver, nil
|
|
}
|
|
|
|
// InitializeSchema creates constraints and indexes in Neo4j
|
|
func InitializeSchema(ctx context.Context, driver neo4j.DriverWithContext, database string) error {
|
|
session := driver.NewSession(ctx, neo4j.SessionConfig{
|
|
AccessMode: neo4j.AccessModeWrite,
|
|
DatabaseName: database,
|
|
})
|
|
defer session.Close(ctx)
|
|
|
|
// Constraints for uniqueness
|
|
constraints := []string{
|
|
"CREATE CONSTRAINT business_id_unique IF NOT EXISTS FOR (b:Business) REQUIRE b.id IS UNIQUE",
|
|
"CREATE CONSTRAINT organization_id_unique IF NOT EXISTS FOR (o:Organization) REQUIRE o.id IS UNIQUE",
|
|
"CREATE CONSTRAINT site_id_unique IF NOT EXISTS FOR (s:Site) REQUIRE s.id IS UNIQUE",
|
|
"CREATE CONSTRAINT resource_flow_id_unique IF NOT EXISTS FOR (rf:ResourceFlow) REQUIRE rf.id IS UNIQUE",
|
|
"CREATE CONSTRAINT match_id_unique IF NOT EXISTS FOR (m:Match) REQUIRE m.id IS UNIQUE",
|
|
"CREATE CONSTRAINT shared_asset_id_unique IF NOT EXISTS FOR (sa:SharedAsset) REQUIRE sa.id IS UNIQUE",
|
|
}
|
|
|
|
// Indexes for performance
|
|
indexes := []string{
|
|
"CREATE INDEX organization_name_index IF NOT EXISTS FOR (o:Organization) ON (o.name)",
|
|
"CREATE INDEX organization_sector_index IF NOT EXISTS FOR (o:Organization) ON (o.sector)",
|
|
"CREATE INDEX organization_subtype_index IF NOT EXISTS FOR (o:Organization) ON (o.subtype)",
|
|
"CREATE INDEX site_location_index IF NOT EXISTS FOR (s:Site) ON (s.latitude, s.longitude)",
|
|
"CREATE INDEX site_type_index IF NOT EXISTS FOR (s:Site) ON (s.site_type)",
|
|
"CREATE INDEX resource_flow_type_direction_index IF NOT EXISTS FOR (rf:ResourceFlow) ON (rf.type, rf.direction)",
|
|
"CREATE INDEX resource_flow_type_index IF NOT EXISTS FOR (rf:ResourceFlow) ON (rf.type)",
|
|
"CREATE INDEX resource_flow_direction_index IF NOT EXISTS FOR (rf:ResourceFlow) ON (rf.direction)",
|
|
"CREATE INDEX match_status_index IF NOT EXISTS FOR (m:Match) ON (m.status)",
|
|
"CREATE INDEX match_score_index IF NOT EXISTS FOR (m:Match) ON (m.compatibility_score)",
|
|
"CREATE INDEX shared_asset_type_index IF NOT EXISTS FOR (sa:SharedAsset) ON (sa.type)",
|
|
}
|
|
|
|
// Execute constraints
|
|
for _, constraint := range constraints {
|
|
if _, err := session.Run(ctx, constraint, nil); err != nil {
|
|
return fmt.Errorf("failed to create constraint: %w", err)
|
|
}
|
|
}
|
|
|
|
// Execute indexes
|
|
for _, index := range indexes {
|
|
if _, err := session.Run(ctx, index, nil); err != nil {
|
|
return fmt.Errorf("failed to create index: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Helper functions for extracting values from Neo4j records
|
|
|
|
// GetString extracts a string value from a map
|
|
func GetString(m map[string]interface{}, key string) string {
|
|
if val, ok := m[key]; ok {
|
|
if str, ok := val.(string); ok {
|
|
return str
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetFloat64 extracts a float64 value from a map
|
|
func GetFloat64(m map[string]interface{}, key string) float64 {
|
|
if val, ok := m[key]; ok {
|
|
switch v := val.(type) {
|
|
case float64:
|
|
return v
|
|
case int64:
|
|
return float64(v)
|
|
case int:
|
|
return float64(v)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// GetInt extracts an int value from a map
|
|
func GetInt(m map[string]interface{}, key string) int {
|
|
if val, ok := m[key]; ok {
|
|
switch v := val.(type) {
|
|
case int64:
|
|
return int(v)
|
|
case int:
|
|
return v
|
|
case float64:
|
|
return int(v)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// GetBool extracts a bool value from a map
|
|
func GetBool(m map[string]interface{}, key string) bool {
|
|
if val, ok := m[key]; ok {
|
|
if b, ok := val.(bool); ok {
|
|
return b
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetTime extracts a time.Time value from a map
|
|
func GetTime(m map[string]interface{}, key string) time.Time {
|
|
if val, ok := m[key]; ok {
|
|
if t, ok := val.(time.Time); ok {
|
|
return t
|
|
}
|
|
if str, ok := val.(string); ok {
|
|
if parsed, err := time.Parse(time.RFC3339, str); err == nil {
|
|
return parsed
|
|
}
|
|
}
|
|
}
|
|
return time.Time{}
|
|
}
|
|
|
|
// GetStringFromRecord extracts a string value from a Neo4j record
|
|
func GetStringFromRecord(record neo4j.Record, key string) string {
|
|
val, ok := record.Get(key)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
if str, ok := val.(string); ok {
|
|
return str
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetFloat64FromRecord extracts a float64 value from a Neo4j record
|
|
func GetFloat64FromRecord(record neo4j.Record, key string) float64 {
|
|
val, ok := record.Get(key)
|
|
if !ok {
|
|
return 0
|
|
}
|
|
switch v := val.(type) {
|
|
case float64:
|
|
return v
|
|
case int64:
|
|
return float64(v)
|
|
case int:
|
|
return float64(v)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// GetIntFromRecord extracts an int value from a Neo4j record
|
|
func GetIntFromRecord(record neo4j.Record, key string) int {
|
|
val, ok := record.Get(key)
|
|
if !ok {
|
|
return 0
|
|
}
|
|
switch v := val.(type) {
|
|
case int64:
|
|
return int(v)
|
|
case int:
|
|
return v
|
|
case float64:
|
|
return int(v)
|
|
}
|
|
return 0
|
|
}
|