Save information about the organization and user from ArcGIS

This commit is contained in:
Eli Ribble 2025-11-07 02:07:33 +00:00
parent 07d3b3ea76
commit a08cd87813
No known key found for this signature in database
20 changed files with 786 additions and 93 deletions

View file

@ -39,3 +39,14 @@ PSQL_DSN="postgresql://?host=/var/run/postgresql&sslmode=disable&dbname=nidus-sy
```
This will generate a bunch of files. They're already committed, you only need this if you change the database schema in some way.
### goose
This uses [goose](https://github.com/pressly/goose). You can use the goose command line to check status and make changes
```sh
> cd migrations
> GOOSE_DRIVER=postgres GOOSE_DBSTRING="dbname=nidus-sync sslmode=disable" goose status
> GOOSE_DRIVER=postgres GOOSE_DBSTRING="dbname=nidus-sync sslmode=disable" goose down
> GOOSE_DRIVER=postgres GOOSE_DBSTRING="dbname=nidus-sync sslmode=disable" goose up
```

@ -1 +1 @@
Subproject commit 5bc087a120a5dab09789b9abe913fd01b735dcff
Subproject commit a99b4a72b2bb3dcff642209f029eb4e7d746fa8d

View file

@ -6,6 +6,7 @@ import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
@ -19,6 +20,8 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/models"
"github.com/Gleipnir-Technology/nidus-sync/sql"
"github.com/aarondl/opt/omit"
"github.com/aarondl/opt/omitnull"
"github.com/jackc/pgx/v5"
)
var CodeVerifier string = "random_secure_string_min_43_chars_long_should_be_stored_in_session"
@ -63,7 +66,7 @@ func generateCodeVerifier() string {
}
// Find out what we can about this user
func getArcgisUserData(access_token string, expires time.Time, refresh_token string) {
func updateArcgisUserData(ctx context.Context, user *models.User, access_token string, expires time.Time, refresh_token string) {
client := arcgis.NewArcGIS(
arcgis.AuthenticatorOAuth{
AccessToken: access_token,
@ -71,15 +74,60 @@ func getArcgisUserData(access_token string, expires time.Time, refresh_token str
RefreshToken: refresh_token,
},
)
/*portal, err := client.PortalsSelf()
portal, err := client.PortalsSelf()
if err != nil {
slog.Error("Failed to get ArcGIS user data", slog.String("err", err.Error()))
return
}
slog.Info("Got portals data",
slog.String("Username", portal.User.Username),
slog.String("ID", portal.ID))
*/
slog.String("user_id", portal.User.ID),
slog.String("org_id", portal.User.OrgID),
slog.String("org_name", portal.Name),
slog.String("license_type_id", portal.User.UserLicenseTypeID))
_, err = sql.UpdateOauthTokenOrg(portal.User.ID, portal.User.UserLicenseTypeID, refresh_token).Exec(ctx, PGInstance.BobDB)
if err != nil {
slog.Error("Failed to update oauth token portal data", slog.String("err", err.Error()))
return
}
var org *models.Organization
orgs, err := models.Organizations.Query(models.SelectWhere.Organizations.ArcgisName.EQ(portal.Name)).All(ctx, PGInstance.BobDB)
switch len(orgs) {
case 0:
setter := models.OrganizationSetter{
Name: omitnull.From(portal.Name),
ArcgisID: omitnull.From(portal.User.OrgID),
ArcgisName: omitnull.From(portal.Name),
}
org, err = models.Organizations.Insert(&setter).One(ctx, PGInstance.BobDB)
if err != nil {
slog.Error("Failed to create new organization", slog.String("err", err.Error()))
return
}
slog.Info("Created new organization", slog.Int("org_id", int(org.ID)))
case 1:
org = orgs[0]
slog.Info("Organization already exists")
default:
slog.Error("Got too many organizations, bailing")
return
}
if err != nil {
LogErrorTypeInfo(err)
if errors.Is(err, pgx.ErrNoRows) {
} else {
slog.Error("Failed to query for existing org", slog.String("err", err.Error()))
return
}
}
err = org.AttachUser(ctx, PGInstance.BobDB, user)
if err != nil {
slog.Error("Failed to attach user to organization", slog.String("err", err.Error()), slog.Int("user_id", int(user.ID)), slog.Int("org_id", int(org.ID)))
return
}
search, err := client.Search("Fieldseeker")
if err != nil {
slog.Error("Failed to get search FieldseekerGIS data", slog.String("err", err.Error()))
@ -152,7 +200,7 @@ func handleOauthAccessCode(ctx context.Context, user *models.User, code string)
if err != nil {
return fmt.Errorf("Failed to save token to database: %v", err)
}
go getArcgisUserData(tokenResponse.AccessToken, expires, tokenResponse.RefreshToken)
go updateArcgisUserData(context.Background(), user, tokenResponse.AccessToken, expires, tokenResponse.RefreshToken)
return nil
}
@ -166,3 +214,7 @@ func hasFieldseekerConnection(ctx context.Context, user *models.User) (bool, err
func redirectURL() string {
return BaseURL + "/arcgis/oauth/callback"
}
// This is a goroutine that is in charge of getting Fieldseeker data and keeping it fresh.
func refreshFieldseekerData(newOauthCh <-chan int, done <-chan struct{}) {
}

View file

@ -69,6 +69,24 @@ var OauthTokens = Table[
Generated: false,
AutoIncr: false,
},
ArcgisID: column{
Name: "arcgis_id",
DBType: "text",
Default: "NULL",
Comment: "",
Nullable: true,
Generated: false,
AutoIncr: false,
},
ArcgisLicenseTypeID: column{
Name: "arcgis_license_type_id",
DBType: "text",
Default: "NULL",
Comment: "",
Nullable: true,
Generated: false,
AutoIncr: false,
},
},
Indexes: oauthTokenIndexes{
OauthTokenPkey: index{
@ -116,11 +134,13 @@ type oauthTokenColumns struct {
RefreshToken column
Username column
UserID column
ArcgisID column
ArcgisLicenseTypeID column
}
func (c oauthTokenColumns) AsSlice() []column {
return []column{
c.ID, c.AccessToken, c.Expires, c.RefreshToken, c.Username, c.UserID,
c.ID, c.AccessToken, c.Expires, c.RefreshToken, c.Username, c.UserID, c.ArcgisID, c.ArcgisLicenseTypeID,
}
}

View file

@ -33,6 +33,24 @@ var Organizations = Table[
Generated: false,
AutoIncr: false,
},
ArcgisID: column{
Name: "arcgis_id",
DBType: "text",
Default: "NULL",
Comment: "",
Nullable: true,
Generated: false,
AutoIncr: false,
},
ArcgisName: column{
Name: "arcgis_name",
DBType: "text",
Default: "NULL",
Comment: "",
Nullable: true,
Generated: false,
AutoIncr: false,
},
},
Indexes: organizationIndexes{
OrganizationPkey: index{
@ -65,11 +83,13 @@ var Organizations = Table[
type organizationColumns struct {
ID column
Name column
ArcgisID column
ArcgisName column
}
func (c organizationColumns) AsSlice() []column {
return []column{
c.ID, c.Name,
c.ID, c.Name, c.ArcgisID, c.ArcgisName,
}
}

28
errors.go Normal file
View file

@ -0,0 +1,28 @@
package main
import (
"errors"
"log/slog"
"reflect"
)
func LogErrorTypeInfo(err error) {
if err == nil {
slog.Info("Error is nil")
return
}
// Log current error type
errType := reflect.TypeOf(err)
slog.Info("Error type info",
"type", errType.String(),
"pkgPath", errType.PkgPath(),
"error", err.Error())
// Recursively log wrapped errors
wrappedErr := errors.Unwrap(err)
if wrappedErr != nil {
slog.Info("Contains wrapped error")
LogErrorTypeInfo(wrappedErr)
}
}

View file

@ -76,6 +76,8 @@ func (f *Factory) FromExistingOauthToken(m *models.OauthToken) *OauthTokenTempla
o.RefreshToken = func() string { return m.RefreshToken }
o.Username = func() string { return m.Username }
o.UserID = func() int32 { return m.UserID }
o.ArcgisID = func() null.Val[string] { return m.ArcgisID }
o.ArcgisLicenseTypeID = func() null.Val[string] { return m.ArcgisLicenseTypeID }
ctx := context.Background()
if m.R.UserUser != nil {
@ -106,6 +108,8 @@ func (f *Factory) FromExistingOrganization(m *models.Organization) *Organization
o.ID = func() int32 { return m.ID }
o.Name = func() null.Val[string] { return m.Name }
o.ArcgisID = func() null.Val[string] { return m.ArcgisID }
o.ArcgisName = func() null.Val[string] { return m.ArcgisName }
ctx := context.Background()
if len(m.R.User) > 0 {

View file

@ -9,7 +9,9 @@ import (
"time"
models "github.com/Gleipnir-Technology/nidus-sync/models"
"github.com/aarondl/opt/null"
"github.com/aarondl/opt/omit"
"github.com/aarondl/opt/omitnull"
"github.com/jaswdr/faker/v2"
"github.com/stephenafamo/bob"
)
@ -41,6 +43,8 @@ type OauthTokenTemplate struct {
RefreshToken func() string
Username func() string
UserID func() int32
ArcgisID func() null.Val[string]
ArcgisLicenseTypeID func() null.Val[string]
r oauthTokenR
f *Factory
@ -103,6 +107,14 @@ func (o OauthTokenTemplate) BuildSetter() *models.OauthTokenSetter {
val := o.UserID()
m.UserID = omit.From(val)
}
if o.ArcgisID != nil {
val := o.ArcgisID()
m.ArcgisID = omitnull.FromNull(val)
}
if o.ArcgisLicenseTypeID != nil {
val := o.ArcgisLicenseTypeID()
m.ArcgisLicenseTypeID = omitnull.FromNull(val)
}
return m
}
@ -143,6 +155,12 @@ func (o OauthTokenTemplate) Build() *models.OauthToken {
if o.UserID != nil {
m.UserID = o.UserID()
}
if o.ArcgisID != nil {
m.ArcgisID = o.ArcgisID()
}
if o.ArcgisLicenseTypeID != nil {
m.ArcgisLicenseTypeID = o.ArcgisLicenseTypeID()
}
o.setModelRels(m)
@ -308,6 +326,8 @@ func (m oauthTokenMods) RandomizeAllColumns(f *faker.Faker) OauthTokenMod {
OauthTokenMods.RandomRefreshToken(f),
OauthTokenMods.RandomUsername(f),
OauthTokenMods.RandomUserID(f),
OauthTokenMods.RandomArcgisID(f),
OauthTokenMods.RandomArcgisLicenseTypeID(f),
}
}
@ -497,6 +517,112 @@ func (m oauthTokenMods) RandomUserID(f *faker.Faker) OauthTokenMod {
})
}
// Set the model columns to this value
func (m oauthTokenMods) ArcgisID(val null.Val[string]) OauthTokenMod {
return OauthTokenModFunc(func(_ context.Context, o *OauthTokenTemplate) {
o.ArcgisID = func() null.Val[string] { return val }
})
}
// Set the Column from the function
func (m oauthTokenMods) ArcgisIDFunc(f func() null.Val[string]) OauthTokenMod {
return OauthTokenModFunc(func(_ context.Context, o *OauthTokenTemplate) {
o.ArcgisID = f
})
}
// Clear any values for the column
func (m oauthTokenMods) UnsetArcgisID() OauthTokenMod {
return OauthTokenModFunc(func(_ context.Context, o *OauthTokenTemplate) {
o.ArcgisID = nil
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is sometimes null
func (m oauthTokenMods) RandomArcgisID(f *faker.Faker) OauthTokenMod {
return OauthTokenModFunc(func(_ context.Context, o *OauthTokenTemplate) {
o.ArcgisID = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is never null
func (m oauthTokenMods) RandomArcgisIDNotNull(f *faker.Faker) OauthTokenMod {
return OauthTokenModFunc(func(_ context.Context, o *OauthTokenTemplate) {
o.ArcgisID = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Set the model columns to this value
func (m oauthTokenMods) ArcgisLicenseTypeID(val null.Val[string]) OauthTokenMod {
return OauthTokenModFunc(func(_ context.Context, o *OauthTokenTemplate) {
o.ArcgisLicenseTypeID = func() null.Val[string] { return val }
})
}
// Set the Column from the function
func (m oauthTokenMods) ArcgisLicenseTypeIDFunc(f func() null.Val[string]) OauthTokenMod {
return OauthTokenModFunc(func(_ context.Context, o *OauthTokenTemplate) {
o.ArcgisLicenseTypeID = f
})
}
// Clear any values for the column
func (m oauthTokenMods) UnsetArcgisLicenseTypeID() OauthTokenMod {
return OauthTokenModFunc(func(_ context.Context, o *OauthTokenTemplate) {
o.ArcgisLicenseTypeID = nil
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is sometimes null
func (m oauthTokenMods) RandomArcgisLicenseTypeID(f *faker.Faker) OauthTokenMod {
return OauthTokenModFunc(func(_ context.Context, o *OauthTokenTemplate) {
o.ArcgisLicenseTypeID = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is never null
func (m oauthTokenMods) RandomArcgisLicenseTypeIDNotNull(f *faker.Faker) OauthTokenMod {
return OauthTokenModFunc(func(_ context.Context, o *OauthTokenTemplate) {
o.ArcgisLicenseTypeID = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
func (m oauthTokenMods) WithParentsCascading() OauthTokenMod {
return OauthTokenModFunc(func(ctx context.Context, o *OauthTokenTemplate) {
if isDone, _ := oauthTokenWithParentsCascadingCtx.Value(ctx); isDone {

View file

@ -38,6 +38,8 @@ func (mods OrganizationModSlice) Apply(ctx context.Context, n *OrganizationTempl
type OrganizationTemplate struct {
ID func() int32
Name func() null.Val[string]
ArcgisID func() null.Val[string]
ArcgisName func() null.Val[string]
r organizationR
f *Factory
@ -91,6 +93,14 @@ func (o OrganizationTemplate) BuildSetter() *models.OrganizationSetter {
val := o.Name()
m.Name = omitnull.FromNull(val)
}
if o.ArcgisID != nil {
val := o.ArcgisID()
m.ArcgisID = omitnull.FromNull(val)
}
if o.ArcgisName != nil {
val := o.ArcgisName()
m.ArcgisName = omitnull.FromNull(val)
}
return m
}
@ -119,6 +129,12 @@ func (o OrganizationTemplate) Build() *models.Organization {
if o.Name != nil {
m.Name = o.Name()
}
if o.ArcgisID != nil {
m.ArcgisID = o.ArcgisID()
}
if o.ArcgisName != nil {
m.ArcgisName = o.ArcgisName()
}
o.setModelRels(m)
@ -261,6 +277,8 @@ func (m organizationMods) RandomizeAllColumns(f *faker.Faker) OrganizationMod {
return OrganizationModSlice{
OrganizationMods.RandomID(f),
OrganizationMods.RandomName(f),
OrganizationMods.RandomArcgisID(f),
OrganizationMods.RandomArcgisName(f),
}
}
@ -348,6 +366,112 @@ func (m organizationMods) RandomNameNotNull(f *faker.Faker) OrganizationMod {
})
}
// Set the model columns to this value
func (m organizationMods) ArcgisID(val null.Val[string]) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.ArcgisID = func() null.Val[string] { return val }
})
}
// Set the Column from the function
func (m organizationMods) ArcgisIDFunc(f func() null.Val[string]) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.ArcgisID = f
})
}
// Clear any values for the column
func (m organizationMods) UnsetArcgisID() OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.ArcgisID = nil
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is sometimes null
func (m organizationMods) RandomArcgisID(f *faker.Faker) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.ArcgisID = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is never null
func (m organizationMods) RandomArcgisIDNotNull(f *faker.Faker) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.ArcgisID = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Set the model columns to this value
func (m organizationMods) ArcgisName(val null.Val[string]) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.ArcgisName = func() null.Val[string] { return val }
})
}
// Set the Column from the function
func (m organizationMods) ArcgisNameFunc(f func() null.Val[string]) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.ArcgisName = f
})
}
// Clear any values for the column
func (m organizationMods) UnsetArcgisName() OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.ArcgisName = nil
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is sometimes null
func (m organizationMods) RandomArcgisName(f *faker.Faker) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.ArcgisName = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is never null
func (m organizationMods) RandomArcgisNameNotNull(f *faker.Faker) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.ArcgisName = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
func (m organizationMods) WithParentsCascading() OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
if isDone, _ := organizationWithParentsCascadingCtx.Value(ctx); isDone {

View file

@ -76,6 +76,9 @@ func main() {
localFS := http.Dir("./static")
FileServer(r, "/static", localFS, embeddedStaticFS, "static")
newTokenChannel := make(chan int)
endChannel := make(chan struct{})
go refreshFieldseekerData(newTokenChannel, endChannel)
log.Printf("Serving on %s", bind)
log.Fatal(http.ListenAndServe(bind, r))
}

View file

@ -0,0 +1,10 @@
-- +goose Up
ALTER TABLE organization ADD COLUMN arcgis_id TEXT;
ALTER TABLE organization ADD COLUMN arcgis_name TEXT;
ALTER TABLE oauth_token ADD COLUMN arcgis_id TEXT;
ALTER TABLE oauth_token ADD COLUMN arcgis_license_type_id TEXT;
-- +goose Down
ALTER TABLE organization DROP COLUMN arcgis_id;
ALTER TABLE organization DROP COLUMN arcgis_name;
ALTER TABLE oauth_token DROP COLUMN arcgis_id;
ALTER TABLE oauth_token DROP COLUMN arcgis_license_type_id;

View file

@ -9,7 +9,9 @@ import (
"io"
"time"
"github.com/aarondl/opt/null"
"github.com/aarondl/opt/omit"
"github.com/aarondl/opt/omitnull"
"github.com/stephenafamo/bob"
"github.com/stephenafamo/bob/dialect/psql"
"github.com/stephenafamo/bob/dialect/psql/dialect"
@ -30,6 +32,8 @@ type OauthToken struct {
RefreshToken string `db:"refresh_token" `
Username string `db:"username" `
UserID int32 `db:"user_id" `
ArcgisID null.Val[string] `db:"arcgis_id" `
ArcgisLicenseTypeID null.Val[string] `db:"arcgis_license_type_id" `
R oauthTokenR `db:"-" `
}
@ -52,7 +56,7 @@ type oauthTokenR struct {
func buildOauthTokenColumns(alias string) oauthTokenColumns {
return oauthTokenColumns{
ColumnsExpr: expr.NewColumnsExpr(
"id", "access_token", "expires", "refresh_token", "username", "user_id",
"id", "access_token", "expires", "refresh_token", "username", "user_id", "arcgis_id", "arcgis_license_type_id",
).WithParent("oauth_token"),
tableAlias: alias,
ID: psql.Quote(alias, "id"),
@ -61,6 +65,8 @@ func buildOauthTokenColumns(alias string) oauthTokenColumns {
RefreshToken: psql.Quote(alias, "refresh_token"),
Username: psql.Quote(alias, "username"),
UserID: psql.Quote(alias, "user_id"),
ArcgisID: psql.Quote(alias, "arcgis_id"),
ArcgisLicenseTypeID: psql.Quote(alias, "arcgis_license_type_id"),
}
}
@ -73,6 +79,8 @@ type oauthTokenColumns struct {
RefreshToken psql.Expression
Username psql.Expression
UserID psql.Expression
ArcgisID psql.Expression
ArcgisLicenseTypeID psql.Expression
}
func (c oauthTokenColumns) Alias() string {
@ -93,10 +101,12 @@ type OauthTokenSetter struct {
RefreshToken omit.Val[string] `db:"refresh_token" `
Username omit.Val[string] `db:"username" `
UserID omit.Val[int32] `db:"user_id" `
ArcgisID omitnull.Val[string] `db:"arcgis_id" `
ArcgisLicenseTypeID omitnull.Val[string] `db:"arcgis_license_type_id" `
}
func (s OauthTokenSetter) SetColumns() []string {
vals := make([]string, 0, 6)
vals := make([]string, 0, 8)
if s.ID.IsValue() {
vals = append(vals, "id")
}
@ -115,6 +125,12 @@ func (s OauthTokenSetter) SetColumns() []string {
if s.UserID.IsValue() {
vals = append(vals, "user_id")
}
if !s.ArcgisID.IsUnset() {
vals = append(vals, "arcgis_id")
}
if !s.ArcgisLicenseTypeID.IsUnset() {
vals = append(vals, "arcgis_license_type_id")
}
return vals
}
@ -137,6 +153,12 @@ func (s OauthTokenSetter) Overwrite(t *OauthToken) {
if s.UserID.IsValue() {
t.UserID = s.UserID.MustGet()
}
if !s.ArcgisID.IsUnset() {
t.ArcgisID = s.ArcgisID.MustGetNull()
}
if !s.ArcgisLicenseTypeID.IsUnset() {
t.ArcgisLicenseTypeID = s.ArcgisLicenseTypeID.MustGetNull()
}
}
func (s *OauthTokenSetter) Apply(q *dialect.InsertQuery) {
@ -145,7 +167,7 @@ func (s *OauthTokenSetter) Apply(q *dialect.InsertQuery) {
})
q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) {
vals := make([]bob.Expression, 6)
vals := make([]bob.Expression, 8)
if s.ID.IsValue() {
vals[0] = psql.Arg(s.ID.MustGet())
} else {
@ -182,6 +204,18 @@ func (s *OauthTokenSetter) Apply(q *dialect.InsertQuery) {
vals[5] = psql.Raw("DEFAULT")
}
if !s.ArcgisID.IsUnset() {
vals[6] = psql.Arg(s.ArcgisID.MustGetNull())
} else {
vals[6] = psql.Raw("DEFAULT")
}
if !s.ArcgisLicenseTypeID.IsUnset() {
vals[7] = psql.Arg(s.ArcgisLicenseTypeID.MustGetNull())
} else {
vals[7] = psql.Raw("DEFAULT")
}
return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "")
}))
}
@ -191,7 +225,7 @@ func (s OauthTokenSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] {
}
func (s OauthTokenSetter) Expressions(prefix ...string) []bob.Expression {
exprs := make([]bob.Expression, 0, 6)
exprs := make([]bob.Expression, 0, 8)
if s.ID.IsValue() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
@ -235,6 +269,20 @@ func (s OauthTokenSetter) Expressions(prefix ...string) []bob.Expression {
}})
}
if !s.ArcgisID.IsUnset() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "arcgis_id")...),
psql.Arg(s.ArcgisID),
}})
}
if !s.ArcgisLicenseTypeID.IsUnset() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "arcgis_license_type_id")...),
psql.Arg(s.ArcgisLicenseTypeID),
}})
}
return exprs
}
@ -540,6 +588,8 @@ type oauthTokenWhere[Q psql.Filterable] struct {
RefreshToken psql.WhereMod[Q, string]
Username psql.WhereMod[Q, string]
UserID psql.WhereMod[Q, int32]
ArcgisID psql.WhereNullMod[Q, string]
ArcgisLicenseTypeID psql.WhereNullMod[Q, string]
}
func (oauthTokenWhere[Q]) AliasedAs(alias string) oauthTokenWhere[Q] {
@ -554,6 +604,8 @@ func buildOauthTokenWhere[Q psql.Filterable](cols oauthTokenColumns) oauthTokenW
RefreshToken: psql.Where[Q, string](cols.RefreshToken),
Username: psql.Where[Q, string](cols.Username),
UserID: psql.Where[Q, int32](cols.UserID),
ArcgisID: psql.WhereNull[Q, string](cols.ArcgisID),
ArcgisLicenseTypeID: psql.WhereNull[Q, string](cols.ArcgisLicenseTypeID),
}
}

View file

@ -27,6 +27,8 @@ import (
type Organization struct {
ID int32 `db:"id,pk" `
Name null.Val[string] `db:"name" `
ArcgisID null.Val[string] `db:"arcgis_id" `
ArcgisName null.Val[string] `db:"arcgis_name" `
R organizationR `db:"-" `
}
@ -49,11 +51,13 @@ type organizationR struct {
func buildOrganizationColumns(alias string) organizationColumns {
return organizationColumns{
ColumnsExpr: expr.NewColumnsExpr(
"id", "name",
"id", "name", "arcgis_id", "arcgis_name",
).WithParent("organization"),
tableAlias: alias,
ID: psql.Quote(alias, "id"),
Name: psql.Quote(alias, "name"),
ArcgisID: psql.Quote(alias, "arcgis_id"),
ArcgisName: psql.Quote(alias, "arcgis_name"),
}
}
@ -62,6 +66,8 @@ type organizationColumns struct {
tableAlias string
ID psql.Expression
Name psql.Expression
ArcgisID psql.Expression
ArcgisName psql.Expression
}
func (c organizationColumns) Alias() string {
@ -78,16 +84,24 @@ func (organizationColumns) AliasedAs(alias string) organizationColumns {
type OrganizationSetter struct {
ID omit.Val[int32] `db:"id,pk" `
Name omitnull.Val[string] `db:"name" `
ArcgisID omitnull.Val[string] `db:"arcgis_id" `
ArcgisName omitnull.Val[string] `db:"arcgis_name" `
}
func (s OrganizationSetter) SetColumns() []string {
vals := make([]string, 0, 2)
vals := make([]string, 0, 4)
if s.ID.IsValue() {
vals = append(vals, "id")
}
if !s.Name.IsUnset() {
vals = append(vals, "name")
}
if !s.ArcgisID.IsUnset() {
vals = append(vals, "arcgis_id")
}
if !s.ArcgisName.IsUnset() {
vals = append(vals, "arcgis_name")
}
return vals
}
@ -98,6 +112,12 @@ func (s OrganizationSetter) Overwrite(t *Organization) {
if !s.Name.IsUnset() {
t.Name = s.Name.MustGetNull()
}
if !s.ArcgisID.IsUnset() {
t.ArcgisID = s.ArcgisID.MustGetNull()
}
if !s.ArcgisName.IsUnset() {
t.ArcgisName = s.ArcgisName.MustGetNull()
}
}
func (s *OrganizationSetter) Apply(q *dialect.InsertQuery) {
@ -106,7 +126,7 @@ func (s *OrganizationSetter) Apply(q *dialect.InsertQuery) {
})
q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) {
vals := make([]bob.Expression, 2)
vals := make([]bob.Expression, 4)
if s.ID.IsValue() {
vals[0] = psql.Arg(s.ID.MustGet())
} else {
@ -119,6 +139,18 @@ func (s *OrganizationSetter) Apply(q *dialect.InsertQuery) {
vals[1] = psql.Raw("DEFAULT")
}
if !s.ArcgisID.IsUnset() {
vals[2] = psql.Arg(s.ArcgisID.MustGetNull())
} else {
vals[2] = psql.Raw("DEFAULT")
}
if !s.ArcgisName.IsUnset() {
vals[3] = psql.Arg(s.ArcgisName.MustGetNull())
} else {
vals[3] = psql.Raw("DEFAULT")
}
return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "")
}))
}
@ -128,7 +160,7 @@ func (s OrganizationSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] {
}
func (s OrganizationSetter) Expressions(prefix ...string) []bob.Expression {
exprs := make([]bob.Expression, 0, 2)
exprs := make([]bob.Expression, 0, 4)
if s.ID.IsValue() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
@ -144,6 +176,20 @@ func (s OrganizationSetter) Expressions(prefix ...string) []bob.Expression {
}})
}
if !s.ArcgisID.IsUnset() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "arcgis_id")...),
psql.Arg(s.ArcgisID),
}})
}
if !s.ArcgisName.IsUnset() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "arcgis_name")...),
psql.Arg(s.ArcgisName),
}})
}
return exprs
}
@ -465,6 +511,8 @@ func (organization0 *Organization) AttachUser(ctx context.Context, exec bob.Exec
type organizationWhere[Q psql.Filterable] struct {
ID psql.WhereMod[Q, int32]
Name psql.WhereNullMod[Q, string]
ArcgisID psql.WhereNullMod[Q, string]
ArcgisName psql.WhereNullMod[Q, string]
}
func (organizationWhere[Q]) AliasedAs(alias string) organizationWhere[Q] {
@ -475,6 +523,8 @@ func buildOrganizationWhere[Q psql.Filterable](cols organizationColumns) organiz
return organizationWhere[Q]{
ID: psql.Where[Q, int32](cols.ID),
Name: psql.WhereNull[Q, string](cols.Name),
ArcgisID: psql.WhereNull[Q, string](cols.ArcgisID),
ArcgisName: psql.WhereNull[Q, string](cols.ArcgisName),
}
}

View file

@ -10,6 +10,7 @@ import (
"iter"
"time"
"github.com/aarondl/opt/null"
"github.com/stephenafamo/bob"
"github.com/stephenafamo/bob/dialect/psql"
"github.com/stephenafamo/bob/dialect/psql/dialect"
@ -20,7 +21,7 @@ import (
//go:embed oauth_by_user_id.bob.sql
var formattedQueries_oauth_by_user_id string
var oauthTokenByUserIdSQL = formattedQueries_oauth_by_user_id[156:440]
var oauthTokenByUserIdSQL = formattedQueries_oauth_by_user_id[156:550]
type OauthTokenByUserIdQuery = orm.ModQuery[*dialect.SelectQuery, oauthTokenByUserId, OauthTokenByUserIdRow, []OauthTokenByUserIdRow, oauthTokenByUserIdTransformer]
@ -47,6 +48,8 @@ func OauthTokenByUserId(UserID int32) *OauthTokenByUserIdQuery {
row.ScheduleScanByIndex(3, &t.RefreshToken)
row.ScheduleScanByIndex(4, &t.Username)
row.ScheduleScanByIndex(5, &t.UserID)
row.ScheduleScanByIndex(6, &t.ArcgisID)
row.ScheduleScanByIndex(7, &t.ArcgisLicenseTypeID)
return &t, nil
}, func(v any) (OauthTokenByUserIdRow, error) {
return *(v.(*OauthTokenByUserIdRow)), nil
@ -54,9 +57,9 @@ func OauthTokenByUserId(UserID int32) *OauthTokenByUserIdQuery {
},
},
Mod: bob.ModFunc[*dialect.SelectQuery](func(q *dialect.SelectQuery) {
q.AppendSelect(expressionTypArgs.subExpr(7, 247))
q.SetTable(expressionTypArgs.subExpr(253, 264))
q.AppendWhere(expressionTypArgs.subExpr(272, 284))
q.AppendSelect(expressionTypArgs.subExpr(7, 357))
q.SetTable(expressionTypArgs.subExpr(363, 374))
q.AppendWhere(expressionTypArgs.subExpr(382, 394))
}),
}
}
@ -68,6 +71,8 @@ type OauthTokenByUserIdRow = struct {
RefreshToken string `db:"refresh_token"`
Username string `db:"username"`
UserID int32 `db:"user_id"`
ArcgisID null.Val[string] `db:"arcgis_id"`
ArcgisLicenseTypeID null.Val[string] `db:"arcgis_license_type_id"`
}
type oauthTokenByUserIdTransformer = bob.SliceTransformer[OauthTokenByUserIdRow, []OauthTokenByUserIdRow]
@ -80,8 +85,8 @@ func (o oauthTokenByUserId) args() iter.Seq[orm.ArgWithPosition] {
return func(yield func(arg orm.ArgWithPosition) bool) {
if !yield(orm.ArgWithPosition{
Name: "userID",
Start: 282,
Stop: 284,
Start: 392,
Stop: 394,
Expression: o.UserID,
}) {
return

View file

@ -2,5 +2,5 @@
-- This file is meant to be re-generated in place and/or deleted at any time.
-- OauthTokenByUserId
SELECT "oauth_token"."id" AS "id", "oauth_token"."access_token" AS "access_token", "oauth_token"."expires" AS "expires", "oauth_token"."refresh_token" AS "refresh_token", "oauth_token"."username" AS "username", "oauth_token"."user_id" AS "user_id" FROM oauth_token WHERE
SELECT "oauth_token"."id" AS "id", "oauth_token"."access_token" AS "access_token", "oauth_token"."expires" AS "expires", "oauth_token"."refresh_token" AS "refresh_token", "oauth_token"."username" AS "username", "oauth_token"."user_id" AS "user_id", "oauth_token"."arcgis_id" AS "arcgis_id", "oauth_token"."arcgis_license_type_id" AS "arcgis_license_type_id" FROM oauth_token WHERE
user_id = $1;

View file

@ -84,8 +84,8 @@ func TestOauthTokenByUserId(t *testing.T) {
t.Fatal(err)
}
if len(columns) != 6 {
t.Fatalf("expected %d columns, got %d", 6, len(columns))
if len(columns) != 8 {
t.Fatalf("expected %d columns, got %d", 8, len(columns))
}
if columns[0] != "id" {
@ -111,5 +111,13 @@ func TestOauthTokenByUserId(t *testing.T) {
if columns[5] != "user_id" {
t.Fatalf("expected column %d to be %s, got %s", 5, "user_id", columns[5])
}
if columns[6] != "arcgis_id" {
t.Fatalf("expected column %d to be %s, got %s", 6, "arcgis_id", columns[6])
}
if columns[7] != "arcgis_license_type_id" {
t.Fatalf("expected column %d to be %s, got %s", 7, "arcgis_license_type_id", columns[7])
}
})
}

View file

@ -0,0 +1,95 @@
// Code generated by BobGen psql v0.41.1. DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.
package sql
import (
"context"
_ "embed"
"io"
"iter"
"github.com/stephenafamo/bob"
"github.com/stephenafamo/bob/dialect/psql"
"github.com/stephenafamo/bob/dialect/psql/dialect"
"github.com/stephenafamo/bob/orm"
)
//go:embed update_oauth_org.bob.sql
var formattedQueries_update_oauth_org string
var updateOauthTokenOrgSQL = formattedQueries_update_oauth_org[157:249]
type UpdateOauthTokenOrgQuery = orm.ModExecQuery[*dialect.UpdateQuery, updateOauthTokenOrg]
func UpdateOauthTokenOrg(ArcgisID string, ArcgisLicenseTypeID string, RefreshToken string) *UpdateOauthTokenOrgQuery {
var expressionTypArgs updateOauthTokenOrg
expressionTypArgs.ArcgisID = psql.Arg(ArcgisID)
expressionTypArgs.ArcgisLicenseTypeID = psql.Arg(ArcgisLicenseTypeID)
expressionTypArgs.RefreshToken = psql.Arg(RefreshToken)
return &UpdateOauthTokenOrgQuery{
ExecQuery: orm.ExecQuery[updateOauthTokenOrg]{
BaseQuery: bob.BaseQuery[updateOauthTokenOrg]{
Expression: expressionTypArgs,
Dialect: dialect.Dialect,
QueryType: bob.QueryTypeUpdate,
},
},
Mod: bob.ModFunc[*dialect.UpdateQuery](func(q *dialect.UpdateQuery) {
q.Table.Expression = expressionTypArgs.subExpr(7, 18)
q.AppendSet(expressionTypArgs.subExpr(23, 66))
q.AppendWhere(expressionTypArgs.subExpr(74, 92))
}),
}
}
type updateOauthTokenOrg struct {
ArcgisID bob.Expression
ArcgisLicenseTypeID bob.Expression
RefreshToken bob.Expression
}
func (o updateOauthTokenOrg) args() iter.Seq[orm.ArgWithPosition] {
return func(yield func(arg orm.ArgWithPosition) bool) {
if !yield(orm.ArgWithPosition{
Name: "arcgisID",
Start: 35,
Stop: 37,
Expression: o.ArcgisID,
}) {
return
}
if !yield(orm.ArgWithPosition{
Name: "arcgisLicenseTypeID",
Start: 64,
Stop: 66,
Expression: o.ArcgisLicenseTypeID,
}) {
return
}
if !yield(orm.ArgWithPosition{
Name: "refreshToken",
Start: 90,
Stop: 92,
Expression: o.RefreshToken,
}) {
return
}
}
}
func (o updateOauthTokenOrg) raw(from, to int) string {
return updateOauthTokenOrgSQL[from:to]
}
func (o updateOauthTokenOrg) subExpr(from, to int) bob.Expression {
return orm.ArgsToExpression(updateOauthTokenOrgSQL, from, to, o.args())
}
func (o updateOauthTokenOrg) WriteSQL(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) {
return o.subExpr(0, len(updateOauthTokenOrgSQL)).WriteSQL(ctx, w, d, start)
}

View file

@ -0,0 +1,6 @@
-- Code generated by BobGen psql v0.41.1. DO NOT EDIT.
-- This file is meant to be re-generated in place and/or deleted at any time.
-- UpdateOauthTokenOrg
UPDATE oauth_token SET arcgis_id = $1, arcgis_license_type_id = $2
WHERE refresh_token = $3;

View file

@ -0,0 +1,76 @@
// Code generated by BobGen psql v0.41.1. DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.
package sql
import (
"context"
"fmt"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/stephenafamo/bob"
"github.com/stephenafamo/bob/dialect/psql"
testutils "github.com/stephenafamo/bob/test/utils"
)
func TestUpdateOauthTokenOrg(t *testing.T) {
t.Run("Base", func(t *testing.T) {
var sb strings.Builder
query := UpdateOauthTokenOrg(random_string(nil), random_string(nil), random_string(nil))
if _, err := query.WriteQuery(t.Context(), &sb, 1); err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(updateOauthTokenOrgSQL, sb.String()); diff != "" {
t.Fatalf("unexpected result (-got +want):\n%s", diff)
}
})
t.Run("Mod", func(t *testing.T) {
var sb strings.Builder
query := UpdateOauthTokenOrg(random_string(nil), random_string(nil), random_string(nil))
if _, err := psql.Update(query).WriteQuery(t.Context(), &sb, 1); err != nil {
t.Fatal(err)
}
queryDiff, err := testutils.QueryDiff(updateOauthTokenOrgSQL, sb.String(), formatQuery)
if err != nil {
t.Fatal(err)
}
if queryDiff != "" {
fmt.Println(sb.String())
t.Fatalf("unexpected result (-got +want):\n%s", queryDiff)
}
})
t.Run("Exec", func(t *testing.T) {
if testDB == nil {
t.Skip("skipping test, no DSN provided")
}
ctxTx, cancel := context.WithCancel(t.Context())
defer cancel()
tx, err := testDB.Begin(ctxTx)
if err != nil {
t.Fatalf("Error starting transaction: %v", err)
}
defer func() {
if err := tx.Rollback(ctxTx); err != nil {
t.Fatalf("Error rolling back transaction: %v", err)
}
}()
query := psql.Update(UpdateOauthTokenOrg(random_string(nil), random_string(nil), random_string(nil)))
if _, err := bob.Exec(ctxTx, tx, query); err != nil {
t.Fatal(err)
}
})
}

3
sql/update_oauth_org.sql Normal file
View file

@ -0,0 +1,3 @@
-- UpdateOauthTokenOrg
UPDATE oauth_token SET arcgis_id = $1, arcgis_license_type_id = $2
WHERE refresh_token = $3;