Skip to content

Commit

Permalink
feat: add generalized entity model for v2 search
Browse files Browse the repository at this point in the history
Issue: #527
  • Loading branch information
adamdecaf committed Jan 10, 2024
1 parent c092b54 commit 07ae5fb
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 0 deletions.
166 changes: 166 additions & 0 deletions pkg/search/models.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package search

import "time"

type Entity[T any] struct {
Name string `json:"name"`
Type EntityType `json:"entityType"`
Source SourceList `json:"sourceList"`

// TODO(adam): What has opensanctions done to normalize and join this data
// Review https://www.opensanctions.org/reference/

Person *Person `json:"person"`
Business *Business `json:"business"`
Organization *Organization `json:"organization"`
Aircraft *Aircraft `json:"aircraft"`
Vessel *Vessel `json:"vessel"`

CryptoAddresses []CryptoAddress `json:"cryptoAddresses"`

Addresses []Address `json:"addresses"`

SourceData T `json:"sourceData"` // Contains all original list data with source list naming
}

type EntityType string

var (
EntityPerson EntityType = "person"
EntityBusiness EntityType = "business"
EntityAircraft EntityType = "aircraft"
EntityVessel EntityType = "vessel"
EntityCryptoAddress EntityType = "crypto-address"
)

type SourceList string

var (
SourceEUCSL SourceList = "eu_csl"
SourceUKCSL SourceList = "uk_csl"
SourceUSCSL SourceList = "us_csl"
SourceUSOFAC SourceList = "us_ofac"
)

type Person struct {
Name string `json:"name"`
Gender Gender `json:"gender"`
BirthDate *time.Time `json:"birthDate"`
DeathDate *time.Time `json:"deathDate"`

GovernmentIDs []GovernmentID `json:"governmentIDs"`
}

type Gender string

var (
GenderUnknown Gender = "unknown"
GenderMale Gender = "male"
GenderFemale Gender = "female"
)

type GovernmentID struct {
Type GovernmentIDType `json:"type"`
Identifier string `json:"identifier"`
}

type GovernmentIDType string

var (
GovernmentIDPassport GovernmentIDType = "passport"
)

type Business struct {
Name string `json:"name"`
Created *time.Time `json:"created"`
Dissolved *time.Time `json:"dissolved"`
Identifier []Identifier `json:"identifier"`
}

// Identifier
//
// TODO(adam): Look at OpenSanctions for tax ID codes
// https://www.opensanctions.org/reference/#schema.Company
type Identifier struct {
Type IdentifierType `json:"type"`
Identifier string `json:"value"`
}

type IdentifierType string

var (
Identifier_US_EIN IdentifierType = "us_ein"
Identifier_US_SSN IdentifierType = "us_ssn"
)

// Organization
//
// TODO(adam): https://www.opensanctions.org/reference/#schema.Organization
type Organization struct {
Name string `json:"name"`
Created *time.Time `json:"created"`
Dissolved *time.Time `json:"dissolved"`
Identifier []Identifier `json:"identifier"`
}

type Aircraft struct {
Name string `json:"name"`
Type AircraftType `json:"type"`
Flag string `json:"flag"` // ISO-3166
Built *time.Time `json:"built"`
ICAOCode string `json:"icaoCode"` // ICAO aircraft type designator
Model string `json:"model"`
SerialNumber string `json:"serialNumber"`
}

type AircraftType string

var (
AircraftTypeUnknown AircraftType = "unknown"
AircraftCargo AircraftType = "cargo"
)

// Vessel
//
// TODO(adam): https://www.opensanctions.org/reference/#schema.Vessel
type Vessel struct {
Name string `json:"name"`
IMONumber string `json:"imoNumber"`
Type VesselType `json:"type"`
Flag string `json:"flag"` // ISO-3166
Built *time.Time `json:"built"`
Model string `json:"model"`
Tonnage int `json:"tonnage"`
MMSI string `json:"mmsi"` // Maritime Mobile Service Identity
}

type VesselType string

var (
VesselTypeUnknown VesselType = "unknown"
VesselTypeCargo VesselType = "cargo"
)

type CryptoAddress struct {
Currency string `json:"currency"`
Address string `json:"address"`
}

// Address is a struct which represents any physical location
//
// TODO(adam): Should probably adopt something like libpostal's naming
// https://github.com/openvenues/libpostal?tab=readme-ov-file#parser-labels
//
// Or OpenSanctions
// https://www.opensanctions.org/reference/#schema.Address
type Address struct {
Line1 string `json:"line1"`
Line2 string `json:"line2"`
City string `json:"city"`
PostalCode string `json:"postalCode"`
State string `json:"state"`
Country string `json:"country"` // ISO-3166 code

Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
}
38 changes: 38 additions & 0 deletions pkg/search/models_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package search

import (
"encoding/json"
"strings"
"testing"

"github.com/stretchr/testify/require"
)

func TestEntityJSON(t *testing.T) {
type SDN struct {
EntityID string `json:"entityID"`
}
bs, err := json.MarshalIndent(Entity[SDN]{
SourceData: SDN{
EntityID: "12345",
},
}, "", " ")
require.NoError(t, err)

expected := strings.TrimSpace(`{
"name": "",
"entityType": "",
"sourceList": "",
"person": null,
"business": null,
"organization": null,
"aircraft": null,
"vessel": null,
"cryptoAddresses": null,
"addresses": null,
"sourceData": {
"entityID": "12345"
}
}`)
require.Equal(t, expected, string(bs))
}

0 comments on commit 07ae5fb

Please sign in to comment.