Skip to main content
Glama
orneryd

M.I.M.I.R - Multi-agent Intelligent Memory & Insight Repository

by orneryd
helpers.go9.48 kB
package cypher import ( "math" "strings" "unicode" "github.com/orneryd/nornicdb/pkg/convert" ) // toFloat64 is a package-level alias to convert.ToFloat64 for internal use. // This avoids updating 100+ call sites while still consolidating the implementation. func toFloat64(v interface{}) (float64, bool) { return convert.ToFloat64(v) } // toFloat64Slice is a package-level alias to convert.ToFloat64Slice for internal use. func toFloat64Slice(v interface{}) ([]float64, bool) { return convert.ToFloat64Slice(v) } // ======================================== // Keyword Detection Functions // ======================================== // isWordBoundary checks if a character is a word boundary (not alphanumeric or underscore) // In Cypher, ':' precedes labels so it's NOT a valid left boundary for keywords func isWordBoundary(r rune) bool { return !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != '_' } // isLeftKeywordBoundary checks if a character can precede a keyword // Colon is excluded because it precedes labels in Cypher (e.g., :Label) func isLeftKeywordBoundary(r rune) bool { if r == ':' { return false // Colon precedes labels, not keywords } return isWordBoundary(r) } // findKeywordIndex finds a keyword at word boundaries in the string. // This prevents matching substrings like "RemoveReturn" when searching for "RETURN". // Also prevents matching labels like ":Return" as keywords. // Returns -1 if not found. func findKeywordIndex(s, keyword string) int { upper := strings.ToUpper(s) keywordUpper := strings.ToUpper(keyword) keyLen := len(keywordUpper) // Build masks for positions inside string literals and parentheses inStringLiteral := makeStringLiteralMask(s) inParentheses := makeParenthesesMask(s) idx := 0 for { pos := strings.Index(upper[idx:], keywordUpper) if pos == -1 { return -1 } absolutePos := idx + pos // Skip if this position is inside a string literal if absolutePos < len(inStringLiteral) && inStringLiteral[absolutePos] { idx = absolutePos + 1 if idx >= len(upper) { return -1 } continue } // Skip if this position is inside parentheses (part of node/relationship patterns) if absolutePos < len(inParentheses) && inParentheses[absolutePos] { idx = absolutePos + 1 if idx >= len(upper) { return -1 } continue } // Check left boundary (before keyword) - use special boundary check // that excludes ':' to avoid matching labels leftOK := absolutePos == 0 || isLeftKeywordBoundary(rune(upper[absolutePos-1])) // Check right boundary (after keyword) endPos := absolutePos + keyLen rightOK := endPos >= len(upper) || isWordBoundary(rune(upper[endPos])) if leftOK && rightOK { return absolutePos } // Move past this occurrence and continue searching idx = absolutePos + 1 if idx >= len(upper) { return -1 } } } // makeParenthesesMask creates a boolean slice marking positions inside parentheses or square brackets. // This is used to skip keywords that appear inside node patterns (parentheses) or list comprehensions (brackets). func makeParenthesesMask(s string) []bool { mask := make([]bool, len(s)) parenDepth := 0 bracketDepth := 0 inString := false stringChar := byte(0) for i := 0; i < len(s); i++ { c := s[i] // Handle string boundaries if (c == '\'' || c == '"') && (i == 0 || s[i-1] != '\\') { if !inString { inString = true stringChar = c } else if c == stringChar { inString = false } continue } if inString { continue } // Track parentheses if c == '(' { parenDepth++ } else if c == ')' { if parenDepth > 0 { parenDepth-- } } // Track square brackets (list comprehensions, array literals) if c == '[' { bracketDepth++ } else if c == ']' { if bracketDepth > 0 { bracketDepth-- } } // Mark as inside if in either parentheses or brackets mask[i] = parenDepth > 0 || bracketDepth > 0 } return mask } // containsKeywordOutsideStrings checks if a keyword exists in the string but NOT inside // string literals. This prevents matching keywords inside user data content. func containsKeywordOutsideStrings(s, keyword string) bool { return findKeywordIndex(s, keyword) != -1 } // containsOutsideStrings checks if a substring exists in the string but NOT inside // string literals. Unlike containsKeywordOutsideStrings, this does exact substring matching // without word boundary checks (useful for symbols like -> and <-). func containsOutsideStrings(s, substr string) bool { mask := makeStringLiteralMask(s) idx := 0 for { pos := strings.Index(s[idx:], substr) if pos == -1 { return false } absolutePos := idx + pos // Check if this position is outside string literals insideString := false for i := 0; i < len(substr); i++ { checkPos := absolutePos + i if checkPos < len(mask) && mask[checkPos] { insideString = true break } } if !insideString { return true } // Move past this occurrence and continue searching idx = absolutePos + 1 if idx >= len(s) { return false } } } // makeStringLiteralMask creates a boolean slice where true means that position // is inside a string literal (single or double quoted). // This is used to skip string contents when searching for keywords. func makeStringLiteralMask(s string) []bool { mask := make([]bool, len(s)) inString := false stringChar := byte(0) for i := 0; i < len(s); i++ { c := s[i] // Check for escaped quotes if c == '\\' && i+1 < len(s) { // Skip the escaped character if inString { mask[i] = true mask[i+1] = true } i++ continue } // Handle string boundaries if c == '\'' || c == '"' { if !inString { // Starting a string inString = true stringChar = c mask[i] = true // The quote itself is part of the string } else if c == stringChar { // Ending the string mask[i] = true // The closing quote is part of the string inString = false stringChar = 0 } else { // Different quote type inside string, just mark as inside mask[i] = true } continue } // Mark positions inside strings if inString { mask[i] = true } } return mask } // ======================================== // Spatial Helper Functions // ======================================== // getXY extracts x, y coordinates from a map func getXY(m map[string]interface{}) (float64, float64, bool) { x, okX := toFloat64(m["x"]) y, okY := toFloat64(m["y"]) return x, y, okX && okY } // getLatLon extracts latitude, longitude from a map func getLatLon(m map[string]interface{}) (float64, float64, bool) { lat, okLat := toFloat64(m["latitude"]) if !okLat { lat, okLat = toFloat64(m["lat"]) } lon, okLon := toFloat64(m["longitude"]) if !okLon { lon, okLon = toFloat64(m["lon"]) } return lat, lon, okLat && okLon } // haversineDistance calculates the distance between two lat/lon points in meters func haversineDistance(lat1, lon1, lat2, lon2 float64) float64 { const earthRadius = 6371000 // meters lat1Rad := lat1 * math.Pi / 180 lat2Rad := lat2 * math.Pi / 180 deltaLat := (lat2 - lat1) * math.Pi / 180 deltaLon := (lon2 - lon1) * math.Pi / 180 a := math.Sin(deltaLat/2)*math.Sin(deltaLat/2) + math.Cos(lat1Rad)*math.Cos(lat2Rad)* math.Sin(deltaLon/2)*math.Sin(deltaLon/2) c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a)) return earthRadius * c } // pointInPolygon uses the ray casting algorithm to determine if a point is inside a polygon. // The polygon is defined by a list of point maps (with x,y or latitude,longitude coordinates). // Returns true if the point is inside or on the boundary of the polygon. func pointInPolygon(px, py float64, polygonPoints []interface{}) bool { if len(polygonPoints) < 3 { return false // A valid polygon needs at least 3 points } // Extract coordinates from polygon points coords := make([][2]float64, 0, len(polygonPoints)) for _, p := range polygonPoints { pm, ok := p.(map[string]interface{}) if !ok { return false } // Try x/y coordinates x, y, hasXY := getXY(pm) if hasXY { coords = append(coords, [2]float64{x, y}) continue } // Try lat/lon coordinates lat, lon, hasLatLon := getLatLon(pm) if hasLatLon { coords = append(coords, [2]float64{lat, lon}) continue } return false // Invalid point format } if len(coords) < 3 { return false } // Ray casting algorithm: count how many times a ray from the point // to infinity crosses the polygon edges. Odd = inside, Even = outside. inside := false j := len(coords) - 1 for i := 0; i < len(coords); i++ { xi, yi := coords[i][0], coords[i][1] xj, yj := coords[j][0], coords[j][1] // Check if point is on a horizontal edge if yi == py && yj == py && ((xi <= px && px <= xj) || (xj <= px && px <= xi)) { return true // On boundary } // Ray casting check if ((yi > py) != (yj > py)) && (px < (xj-xi)*(py-yi)/(yj-yi)+xi) { inside = !inside } j = i } return inside } // extractPolygonPoints extracts point list from a polygon/lineString map func extractPolygonPoints(geom map[string]interface{}) []interface{} { if points, ok := geom["points"]; ok { if pointList, ok := points.([]interface{}); ok { return pointList } } // Try "coordinates" as alternative (GeoJSON style) if coords, ok := geom["coordinates"]; ok { if coordList, ok := coords.([]interface{}); ok { return coordList } } return nil }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/orneryd/Mimir'

If you have feedback or need assistance with the MCP directory API, please join our Discord server