Created
February 17, 2023 22:05
-
-
Save divan/dd05b64ceea7541b9dc1a4b1aff09fca to your computer and use it in GitHub Desktop.
edgedb-delete-checker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"io/fs" | |
"io/ioutil" | |
"os" | |
"path/filepath" | |
"sort" | |
"strings" | |
) | |
// Checker finds the links with deletion rules from the esdl files in the dir. | |
type Checker struct { | |
Dir string | |
Links []Link | |
} | |
// Link represents a link in the esdl file. | |
type Link struct { | |
Source string // source type name | |
Target string // target type name | |
Name string // link name | |
OnDelete string // on delete constraint | |
} | |
// String implements the Stringer interface. | |
func (l Link) String() string { | |
switch l.OnDelete { | |
case "allow": | |
return fmt.Sprintf("If you delete %s, it will be deleted from %s (via .%s), and %s will stay", l.Target, l.Source, l.Name, l.Source) | |
case "delete source": | |
return fmt.Sprintf("If you delete %s, all linked %s will be deleted (via .%s)", l.Target, l.Source, l.Name) | |
case "restrict": | |
return fmt.Sprintf("If you try to delete %s that is referenced by %s (via .%s), it'll return an error", l.Target, l.Source, l.Name) | |
default: | |
return fmt.Sprintf("Unknown on delete constraint %s", l.OnDelete) | |
} | |
} | |
func main() { | |
var dir = flag.String("dir", ".", "directory with dbschema/.esdl files for your project") | |
flag.Parse() | |
c := Checker{ | |
Dir: *dir, | |
} | |
// find all dbschema/.esdl files in the directory | |
err := filepath.WalkDir(*dir, func(s string, d fs.DirEntry, e error) error { | |
if e != nil { | |
return e | |
} | |
if d.IsDir() { | |
return nil | |
} | |
if filepath.Ext(s) != ".esdl" { | |
return nil | |
} | |
return c.processESDL(s) | |
}) | |
if err != nil { | |
fmt.Println("[ERROR]:", err) | |
os.Exit(1) | |
} | |
// sort by target for output | |
sort.Slice(c.Links, func(i, j int) bool { | |
return c.Links[i].Target < c.Links[j].Target | |
}) | |
for _, link := range c.Links { | |
fmt.Println(link) | |
} | |
fmt.Println() | |
fmt.Println("See details on: https://www.edgedb.com/docs/datamodel/links#ref-datamodel-link-deletion") | |
} | |
func (c *Checker) processESDL(path string) error { | |
data, err := ioutil.ReadFile(path) | |
if err != nil { | |
return fmt.Errorf("read file: %w", err) | |
} | |
// find lines theat contain "link " | |
// and print them | |
currentType := "" | |
lines := strings.Split(string(data), "\n") | |
for i, line := range lines { | |
lastLine := i == len(lines)-1 | |
line = strings.TrimSpace(line) | |
// save current type (esdl can contain many types | |
if strings.Contains(line, "type ") { | |
currentType = strings.Split(line, " ")[1] | |
continue | |
} | |
if strings.Contains(line, "link ") { | |
// peek the next line and check if it contains "on target delete" | |
var onDelete string = "restrict" | |
if !lastLine { | |
nextLine := strings.TrimSpace(lines[i+1]) | |
if strings.Contains(nextLine, "on target delete") { | |
if strings.Contains(nextLine, "allow") { | |
onDelete = "allow" | |
} else if strings.Contains(nextLine, "delete source") { | |
onDelete = "delete source" | |
} | |
} | |
} | |
// strip required/multi | |
line = strings.ReplaceAll(line, "required ", "") | |
line = strings.ReplaceAll(line, "multi ", "") | |
// split by spaces | |
fields := strings.Fields(line) | |
var name, target string | |
name = fields[1] | |
target = fields[3] | |
// skip backlinks | |
if strings.HasPrefix(target, ".<") { | |
continue | |
} | |
// cleanup | |
if strings.HasPrefix(name, "`") { | |
name = strings.Trim(name, "`") | |
} | |
if strings.HasSuffix(target, ";") { | |
target = strings.TrimSuffix(target, ";") | |
} | |
link := Link{ | |
Source: currentType, | |
Target: target, | |
Name: name, | |
OnDelete: onDelete, | |
} | |
c.Links = append(c.Links, link) | |
} | |
} | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment