Files
grosbeak/internal/domain64/database.go
Matt Jadud 06cdc68be7 Integrated, working.
This integrates the liteq, and it prevents duplicates in a way that
matches my use-case.

I might try and push things back out to a separate module, but for now,
this will do.
2025-11-30 18:01:35 -05:00

171 lines
4.2 KiB
Go

package domain64
import (
"context"
"database/sql"
"fmt"
"log"
"slices"
"sync"
sqlc "git.jadud.com/jadudm/grosbeak/internal/domain64/sqlc"
"github.com/jpillora/go-tld"
)
type Domain64Map struct {
mu sync.Mutex
m map[string]int
DB *sql.DB
Flushed bool
}
func NewDomain64Map(db *sql.DB) (*Domain64Map, error) {
d64m := &Domain64Map{}
d64m.DB = db
d64m.Flushed = true
// Init the tables if a DB pointer is passed in.
return d64m, nil
}
func (d64m *Domain64Map) URLToRFQDN(url *tld.URL) string {
s := ""
if url.TLD != "" {
s += url.TLD
}
if url.Domain != "" {
s += "." + url.Domain
}
if url.Subdomain != "" {
s += "." + url.Subdomain
}
s += url.Path
return s
}
func _get_or_insert_tld(queries *sqlc.Queries, d64 *Domain64, url *tld.URL) error {
ctx := context.Background()
tld_id, err := queries.GetTLDId(ctx, url.TLD)
if err != nil {
cnt, err := queries.CountTLDs(ctx)
if err != nil {
return err
}
d64.TLD = cnt + 1
err = queries.InsertTLD(ctx, sqlc.InsertTLDParams{TldID: d64.TLD, Tld: url.TLD})
if err != nil {
return err
}
} else {
d64.TLD = tld_id
}
return nil
}
func _get_or_insert_domain(queries *sqlc.Queries, d64 *Domain64, url *tld.URL) error {
ctx := context.Background()
domain_id, err := queries.GetDomainId(ctx, sqlc.GetDomainIdParams{TldID: d64.TLD, Domain: url.Domain})
if err != nil {
cnt, err := queries.CountDomains(ctx, d64.TLD)
if err != nil {
return err
}
d64.Domain = cnt + 1
err = queries.InsertDomain(ctx, sqlc.InsertDomainParams{TldID: d64.TLD, DomainID: d64.Domain, Domain: url.Domain})
if err != nil {
return err
}
} else {
d64.Domain = domain_id
}
return nil
}
func _get_or_insert_subdomain(queries *sqlc.Queries, d64 *Domain64, url *tld.URL) error {
ctx := context.Background()
subdomain_id, err := queries.GetSubdomainId(ctx, sqlc.GetSubdomainIdParams{
TldID: int64(d64.TLD), DomainID: int64(d64.Domain), Subdomain: url.Subdomain,
})
if err != nil {
if url.Subdomain == "" {
d64.Subdomain = 0
} else {
cnt, err := queries.CountSubdomains(ctx, sqlc.CountSubdomainsParams{TldID: d64.TLD, DomainID: d64.Domain})
if err != nil {
return err
}
d64.Subdomain = cnt + 1
err = queries.InsertSubdomain(ctx, sqlc.InsertSubdomainParams{TldID: d64.TLD, DomainID: d64.Domain, SubdomainID: d64.Subdomain, Subdomain: url.Subdomain})
if err != nil {
return err
}
}
} else {
d64.Subdomain = subdomain_id
}
return nil
}
func _get_or_insert_path(queries *sqlc.Queries, d64 *Domain64, url *tld.URL) error {
ctx := context.Background()
log.Println(url, url.Path)
path_id, err := queries.GetPathId(ctx, sqlc.GetPathIdParams{
TldID: d64.TLD, DomainID: d64.Domain, SubdomainID: d64.Subdomain, Path: url.Path,
})
if err != nil {
if url.Path == "/" {
d64.Path = 0
} else {
cnt, err := queries.CountPaths(ctx, sqlc.CountPathsParams{TldID: d64.TLD, DomainID: d64.Domain, SubdomainID: d64.Subdomain})
if err != nil {
return err
}
d64.Path = cnt + 1
err = queries.InsertPath(ctx, sqlc.InsertPathParams{TldID: d64.TLD, DomainID: d64.Domain, SubdomainID: d64.Subdomain, PathID: d64.Path, Path: url.Path})
if err != nil {
return err
}
}
} else {
d64.Path = path_id
}
return nil
}
// FIXME: This feels like a very convoluted way to maintain the domain names.
// However, I also need to maintain uniqueness. Can I do this in one table?
func (d64m *Domain64Map) URLToDomain64(url *tld.URL) (*Domain64, error) {
allowed_schemes := []string{"https"}
if !slices.Contains(allowed_schemes, url.Scheme) {
return nil, fmt.Errorf("URL scheme must be in %q; given %s", allowed_schemes, url.Scheme)
}
d64 := &Domain64{}
queries := sqlc.New(d64m.DB)
// These manipulate both the DB and the Domain64 struct
err := _get_or_insert_tld(queries, d64, url)
if err != nil {
return nil, err
}
err = _get_or_insert_domain(queries, d64, url)
if err != nil {
return nil, err
}
err = _get_or_insert_subdomain(queries, d64, url)
if err != nil {
return nil, err
}
err = _get_or_insert_path(queries, d64, url)
if err != nil {
return nil, err
}
return d64, nil
}
func NullInt64(i int64) sql.NullInt64 {
return sql.NullInt64{Int64: i, Valid: true}
}
func NullString(s string) sql.NullString {
return sql.NullString{String: s, Valid: true}
}