and yet more

This commit is contained in:
tsmethurst 2021-08-24 19:52:02 +02:00
commit 465aa3da86
34 changed files with 128 additions and 134 deletions

View file

@ -129,10 +129,10 @@ The following libraries and frameworks are used by GoToSocial, with gratitude
* [gin-contrib/static](https://github.com/gin-contrib/static); Gin static page middleware. [MIT License](https://spdx.org/licenses/MIT.html) * [gin-contrib/static](https://github.com/gin-contrib/static); Gin static page middleware. [MIT License](https://spdx.org/licenses/MIT.html)
* [go-fed/activity](https://github.com/go-fed/activity); Golang ActivityPub/ActivityStreams library. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html). * [go-fed/activity](https://github.com/go-fed/activity); Golang ActivityPub/ActivityStreams library. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html).
* [go-fed/httpsig](https://github.com/go-fed/httpsig); secure HTTP signature library. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html). * [go-fed/httpsig](https://github.com/go-fed/httpsig); secure HTTP signature library. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html).
* [go-pg/pg](https://github.com/go-pg/pg); Postgres ORM library. [BSD-2-Clause License](https://spdx.org/licenses/BSD-2-Clause.html).
* [google/uuid](https://github.com/google/uuid); UUID generation. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html) * [google/uuid](https://github.com/google/uuid); UUID generation. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html)
* [gorilla/websocket](https://github.com/gorilla/websocket); Websocket connectivity. [BSD-2-Clause License](https://spdx.org/licenses/BSD-2-Clause.html). * [gorilla/websocket](https://github.com/gorilla/websocket); Websocket connectivity. [BSD-2-Clause License](https://spdx.org/licenses/BSD-2-Clause.html).
* [h2non/filetype](https://github.com/h2non/filetype); filetype checking. [MIT License](https://spdx.org/licenses/MIT.html). * [h2non/filetype](https://github.com/h2non/filetype); filetype checking. [MIT License](https://spdx.org/licenses/MIT.html).
* [jackc/pgx](https://github.com/jackc/pgx); Postgres driver. [MIT License](https://spdx.org/licenses/MIT.html).
* [microcosm-cc/bluemonday](https://github.com/microcosm-cc/bluemonday); HTML user-input sanitization. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html). * [microcosm-cc/bluemonday](https://github.com/microcosm-cc/bluemonday); HTML user-input sanitization. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html).
* [mvdan/xurls](https://github.com/mvdan/xurls); URL parsing regular expressions. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html). * [mvdan/xurls](https://github.com/mvdan/xurls); URL parsing regular expressions. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html).
* [nfnt/resize](https://github.com/nfnt/resize); convenient image resizing. [ISC License](https://spdx.org/licenses/ISC.html). * [nfnt/resize](https://github.com/nfnt/resize); convenient image resizing. [ISC License](https://spdx.org/licenses/ISC.html).
@ -145,6 +145,7 @@ The following libraries and frameworks are used by GoToSocial, with gratitude
* [superseriousbusiness/oauth2](https://github.com/superseriousbusiness/oauth2) forked from [go-oauth2/oauth2](https://github.com/go-oauth2/oauth2); oauth server framework and token handling. [MIT License](https://spdx.org/licenses/MIT.html). * [superseriousbusiness/oauth2](https://github.com/superseriousbusiness/oauth2) forked from [go-oauth2/oauth2](https://github.com/go-oauth2/oauth2); oauth server framework and token handling. [MIT License](https://spdx.org/licenses/MIT.html).
* [go-swagger/go-swagger](https://github.com/go-swagger/go-swagger); Swagger OpenAPI spec generation. [Apache-2.0 License](https://spdx.org/licenses/Apache-2.0.html). * [go-swagger/go-swagger](https://github.com/go-swagger/go-swagger); Swagger OpenAPI spec generation. [Apache-2.0 License](https://spdx.org/licenses/Apache-2.0.html).
* [tdewolff/minify](https://github.com/tdewolff/minify); HTML minification. [MIT License](https://spdx.org/licenses/MIT.html). * [tdewolff/minify](https://github.com/tdewolff/minify); HTML minification. [MIT License](https://spdx.org/licenses/MIT.html).
* [uptrace/bun](https://github.com/uptrace/bun); database ORM. [BSD-2-Clause License](https://spdx.org/licenses/BSD-2-Clause.html).
* [urfave/cli](https://github.com/urfave/cli); command-line interface framework. [MIT License](https://spdx.org/licenses/MIT.html). * [urfave/cli](https://github.com/urfave/cli); command-line interface framework. [MIT License](https://spdx.org/licenses/MIT.html).
* [wagslane/go-password-validator](https://github.com/wagslane/go-password-validator); password strength validation. [MIT License](https://spdx.org/licenses/MIT.html). * [wagslane/go-password-validator](https://github.com/wagslane/go-password-validator); password strength validation. [MIT License](https://spdx.org/licenses/MIT.html).

4
go.mod
View file

@ -46,8 +46,8 @@ require (
github.com/superseriousbusiness/oauth2/v4 v4.3.0-SSB github.com/superseriousbusiness/oauth2/v4 v4.3.0-SSB
github.com/tdewolff/minify/v2 v2.9.21 github.com/tdewolff/minify/v2 v2.9.21
github.com/tidwall/buntdb v1.2.4 // indirect github.com/tidwall/buntdb v1.2.4 // indirect
github.com/uptrace/bun v0.4.3 github.com/uptrace/bun v1.0.0-rc.1
github.com/uptrace/bun/dialect/pgdialect v0.4.3 github.com/uptrace/bun/dialect/pgdialect v1.0.0-rc.1
github.com/urfave/cli/v2 v2.3.0 github.com/urfave/cli/v2 v2.3.0
github.com/wagslane/go-password-validator v0.3.0 github.com/wagslane/go-password-validator v0.3.0
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97

8
go.sum
View file

@ -446,10 +446,10 @@ github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ= github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
github.com/uptrace/bun v0.4.3 h1:x6bjDqwjxwM/9Q1eauhkznuvTrz/rLiCK2p4tT63sAE= github.com/uptrace/bun v1.0.0-rc.1 h1:yMjz/JdlgYRema5mk59URzjAV7HpOV58Fj3KID34K9U=
github.com/uptrace/bun v0.4.3/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw= github.com/uptrace/bun v1.0.0-rc.1/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
github.com/uptrace/bun/dialect/pgdialect v0.4.3 h1:lM2IUKpU99110chKkupw3oTfXiOKpB0hTJIe6frqQDo= github.com/uptrace/bun/dialect/pgdialect v1.0.0-rc.1 h1:4rxcO4+x8r2xyCnduH9fhhkjhbtzLHFl3vmx2goVgio=
github.com/uptrace/bun/dialect/pgdialect v0.4.3/go.mod h1:BaNvWejl32oKUhwpFkw/eNcWldzIlVY4nfw/sNul0s8= github.com/uptrace/bun/dialect/pgdialect v1.0.0-rc.1/go.mod h1:x48KjNeAGTSq4WNIOvtfzAOFjPG/V/Gx+SdwO5ksimU=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=

View file

@ -58,11 +58,6 @@ type Basic interface {
// The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice. // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
Put(ctx context.Context, i interface{}) Error Put(ctx context.Context, i interface{}) Error
// Upsert stores or updates i based on the given conflict column, as in https://www.postgresqltutorial.com/postgresql-upsert/
// It is up to the implementation to figure out how to store it, and using what key.
// The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
Upsert(ctx context.Context, i interface{}, conflictColumn string) Error
// UpdateByID updates i with id id. // UpdateByID updates i with id id.
// The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice. // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
UpdateByID(ctx context.Context, id string, i interface{}) Error UpdateByID(ctx context.Context, id string, i interface{}) Error

View file

@ -47,7 +47,7 @@ func (a *accountDB) newAccountQ(account *gtsmodel.Account) *bun.SelectQuery {
} }
func (a *accountDB) GetAccountByID(ctx context.Context, id string) (*gtsmodel.Account, db.Error) { func (a *accountDB) GetAccountByID(ctx context.Context, id string) (*gtsmodel.Account, db.Error) {
account := &gtsmodel.Account{} account := new(gtsmodel.Account)
q := a.newAccountQ(account). q := a.newAccountQ(account).
Where("account.id = ?", id) Where("account.id = ?", id)
@ -58,7 +58,7 @@ func (a *accountDB) GetAccountByID(ctx context.Context, id string) (*gtsmodel.Ac
} }
func (a *accountDB) GetAccountByURI(ctx context.Context, uri string) (*gtsmodel.Account, db.Error) { func (a *accountDB) GetAccountByURI(ctx context.Context, uri string) (*gtsmodel.Account, db.Error) {
account := &gtsmodel.Account{} account := new(gtsmodel.Account)
q := a.newAccountQ(account). q := a.newAccountQ(account).
Where("account.uri = ?", uri) Where("account.uri = ?", uri)
@ -69,7 +69,7 @@ func (a *accountDB) GetAccountByURI(ctx context.Context, uri string) (*gtsmodel.
} }
func (a *accountDB) GetAccountByURL(ctx context.Context, uri string) (*gtsmodel.Account, db.Error) { func (a *accountDB) GetAccountByURL(ctx context.Context, uri string) (*gtsmodel.Account, db.Error) {
account := &gtsmodel.Account{} account := new(gtsmodel.Account)
q := a.newAccountQ(account). q := a.newAccountQ(account).
Where("account.url = ?", uri) Where("account.url = ?", uri)
@ -80,7 +80,7 @@ func (a *accountDB) GetAccountByURL(ctx context.Context, uri string) (*gtsmodel.
} }
func (a *accountDB) GetInstanceAccount(ctx context.Context, domain string) (*gtsmodel.Account, db.Error) { func (a *accountDB) GetInstanceAccount(ctx context.Context, domain string) (*gtsmodel.Account, db.Error) {
account := &gtsmodel.Account{} account := new(gtsmodel.Account)
q := a.newAccountQ(account) q := a.newAccountQ(account)
@ -100,7 +100,7 @@ func (a *accountDB) GetInstanceAccount(ctx context.Context, domain string) (*gts
} }
func (a *accountDB) GetAccountLastPosted(ctx context.Context, accountID string) (time.Time, db.Error) { func (a *accountDB) GetAccountLastPosted(ctx context.Context, accountID string) (time.Time, db.Error) {
status := &gtsmodel.Status{} status := new(gtsmodel.Status)
q := a.conn. q := a.conn.
NewSelect(). NewSelect().
@ -130,18 +130,26 @@ func (a *accountDB) SetAccountHeaderOrAvatar(ctx context.Context, mediaAttachmen
} }
// TODO: there are probably more side effects here that need to be handled // TODO: there are probably more side effects here that need to be handled
if _, err := a.conn.NewInsert().Model(mediaAttachment).On("CONFLICT (id) DO UPDATE").Exec(ctx); err != nil { if _, err := a.conn.
NewInsert().
Model(mediaAttachment).
Exec(ctx); err != nil {
return err return err
} }
if _, err := a.conn.NewInsert().Model(&gtsmodel.Account{}).Set(fmt.Sprintf("%s_media_attachment_id = ?", headerOrAVI), mediaAttachment.ID).Where("id = ?", accountID).Exec(ctx); err != nil { if _, err := a.conn.
NewUpdate().
Model(&gtsmodel.Account{}).
Set(fmt.Sprintf("%s_media_attachment_id = ?", headerOrAVI), mediaAttachment.ID).
Where("id = ?", accountID).
Exec(ctx); err != nil {
return err return err
} }
return nil return nil
} }
func (a *accountDB) GetLocalAccountByUsername(ctx context.Context, username string) (*gtsmodel.Account, db.Error) { func (a *accountDB) GetLocalAccountByUsername(ctx context.Context, username string) (*gtsmodel.Account, db.Error) {
account := &gtsmodel.Account{} account := new(gtsmodel.Account)
q := a.newAccountQ(account). q := a.newAccountQ(account).
Where("username = ?", username). Where("username = ?", username).
@ -153,16 +161,16 @@ func (a *accountDB) GetLocalAccountByUsername(ctx context.Context, username stri
} }
func (a *accountDB) GetAccountFaves(ctx context.Context, accountID string) ([]*gtsmodel.StatusFave, db.Error) { func (a *accountDB) GetAccountFaves(ctx context.Context, accountID string) ([]*gtsmodel.StatusFave, db.Error) {
faves := []*gtsmodel.StatusFave{} faves := new([]*gtsmodel.StatusFave)
if err := a.conn. if err := a.conn.
NewSelect(). NewSelect().
Model(&faves). Model(faves).
Where("account_id = ?", accountID). Where("account_id = ?", accountID).
Scan(ctx); err != nil { Scan(ctx); err != nil {
return nil, err return nil, err
} }
return faves, nil return *faves, nil
} }
func (a *accountDB) CountAccountStatuses(ctx context.Context, accountID string) (int, db.Error) { func (a *accountDB) CountAccountStatuses(ctx context.Context, accountID string) (int, db.Error) {

View file

@ -21,7 +21,6 @@ package pg
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"strings" "strings"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -113,23 +112,11 @@ func (b *basicDB) DeleteWhere(ctx context.Context, where []db.Where, i interface
return processErrorResponse(err) return processErrorResponse(err)
} }
func (b *basicDB) Upsert(ctx context.Context, i interface{}, conflictColumn string) db.Error {
q := b.conn.
NewInsert().
Model(i).
On(fmt.Sprintf("CONFLICT (%s) DO UPDATE", conflictColumn))
_, err := q.Exec(ctx)
return processErrorResponse(err)
}
func (b *basicDB) UpdateByID(ctx context.Context, id string, i interface{}) db.Error { func (b *basicDB) UpdateByID(ctx context.Context, id string, i interface{}) db.Error {
q := b.conn. q := b.conn.
NewInsert(). NewUpdate().
Model(i). Model(i).
Where("id = ?", id). Where("id = ?", id)
On("CONFLICT (id) DO UPDATE")
_, err := q.Exec(ctx) _, err := q.Exec(ctx)
@ -170,12 +157,12 @@ func (b *basicDB) UpdateWhere(ctx context.Context, where []db.Where, key string,
} }
func (b *basicDB) CreateTable(ctx context.Context, i interface{}) db.Error { func (b *basicDB) CreateTable(ctx context.Context, i interface{}) db.Error {
_, err := b.conn.NewCreateTable().IfNotExists().Model(i).Exec(ctx) _, err := b.conn.NewCreateTable().Model(i).IfNotExists().Exec(ctx)
return err return err
} }
func (b *basicDB) DropTable(ctx context.Context, i interface{}) db.Error { func (b *basicDB) DropTable(ctx context.Context, i interface{}) db.Error {
_, err := b.conn.NewDropTable().IfExists().Model(i).Exec(ctx) _, err := b.conn.NewDropTable().Model(i).IfExists().Exec(ctx)
return processErrorResponse(err) return processErrorResponse(err)
} }

View file

@ -76,13 +76,7 @@ func (s *statusDB) newStatusQ(status interface{}) *bun.SelectQuery {
Relation("Attachments"). Relation("Attachments").
Relation("Tags"). Relation("Tags").
Relation("Mentions"). Relation("Mentions").
Relation("Emojis"). Relation("Emojis")
Relation("Account").
Relation("InReplyTo").
Relation("InReplyToAccount").
Relation("BoostOf").
Relation("BoostOfAccount").
Relation("CreatedWithApplication")
} }
func (s *statusDB) newFaveQ(faves interface{}) *bun.SelectQuery { func (s *statusDB) newFaveQ(faves interface{}) *bun.SelectQuery {
@ -99,14 +93,18 @@ func (s *statusDB) GetStatusByID(ctx context.Context, id string) (*gtsmodel.Stat
return status, nil return status, nil
} }
status := &gtsmodel.Status{} status := new(gtsmodel.Status)
q := s.newStatusQ(status). q := s.newStatusQ(status).
Where("status.id = ?", id) Where("status.id = ?", id)
err := processErrorResponse(q.Scan(ctx)) err := processErrorResponse(q.Scan(ctx))
if err == nil && status != nil { if err != nil {
return nil, err
}
if status != nil {
s.cacheStatus(id, status) s.cacheStatus(id, status)
} }

View file

@ -59,6 +59,7 @@ func (suite *StatusTestSuite) TearDownTest() {
func (suite *StatusTestSuite) TestGetStatusByID() { func (suite *StatusTestSuite) TestGetStatusByID() {
status, err := suite.db.GetStatusByID(context.Background(), suite.testStatuses["local_account_1_status_1"].ID) status, err := suite.db.GetStatusByID(context.Background(), suite.testStatuses["local_account_1_status_1"].ID)
if err != nil { if err != nil {
fmt.Println(err.Error())
suite.FailNow(err.Error()) suite.FailNow(err.Error())
} }
suite.NotNil(status) suite.NotNil(status)

View file

@ -65,9 +65,9 @@ type Account struct {
// This account has moved this account id in the database // This account has moved this account id in the database
MovedToAccountID string `bun:"type:CHAR(26)"` MovedToAccountID string `bun:"type:CHAR(26)"`
// When was this account created? // When was this account created?
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
// When was this account last updated? // When was this account last updated?
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
// Does this account identify itself as a bot? // Does this account identify itself as a bot?
Bot bool Bot bool
// What reason was given for signing up when this account was created? // What reason was given for signing up when this account was created?
@ -97,7 +97,7 @@ type Account struct {
// At which URL can we see the user account in a web browser? // At which URL can we see the user account in a web browser?
URL string `bun:",unique"` URL string `bun:",unique"`
// Last time this account was located using the webfinger API. // Last time this account was located using the webfinger API.
LastWebfingeredAt time.Time `bun:"type:timestamp"` LastWebfingeredAt time.Time `bun:",nullzero"`
// Address of this account's activitypub inbox, for sending activity to // Address of this account's activitypub inbox, for sending activity to
InboxURI string `bun:",unique"` InboxURI string `bun:",unique"`
// Address of this account's activitypub outbox // Address of this account's activitypub outbox
@ -129,11 +129,11 @@ type Account struct {
*/ */
// When was this account set to have all its media shown as sensitive? // When was this account set to have all its media shown as sensitive?
SensitizedAt time.Time `bun:"type:timestamp"` SensitizedAt time.Time `bun:",nullzero"`
// When was this account silenced (eg., statuses only visible to followers, not public)? // When was this account silenced (eg., statuses only visible to followers, not public)?
SilencedAt time.Time `bun:"type:timestamp"` SilencedAt time.Time `bun:",nullzero"`
// When was this account suspended (eg., don't allow it to log in/post, don't accept media/posts from this account) // When was this account suspended (eg., don't allow it to log in/post, don't accept media/posts from this account)
SuspendedAt time.Time `bun:"type:timestamp"` SuspendedAt time.Time `bun:",nullzero"`
// Should we hide this account's collections? // Should we hide this account's collections?
HideCollections bool HideCollections bool
// id of the database entry that caused this account to become suspended -- can be an account ID or a domain block ID // id of the database entry that caused this account to become suspended -- can be an account ID or a domain block ID
@ -146,5 +146,5 @@ type Account struct {
type Field struct { type Field struct {
Name string Name string
Value string Value string
VerifiedAt time.Time `bun:"type:timestamp"` VerifiedAt time.Time `bun:",nullzero"`
} }

View file

@ -7,15 +7,15 @@ type Block struct {
// id of this block in the database // id of this block in the database
ID string `bun:"type:CHAR(26),pk,notnull"` ID string `bun:"type:CHAR(26),pk,notnull"`
// When was this block created // When was this block created
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// When was this block updated // When was this block updated
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// Who created this block? // Who created this block?
AccountID string `bun:"type:CHAR(26),notnull"` AccountID string `bun:"type:CHAR(26),notnull"`
Account *Account `bun:"rel:belongs-to"` Account *Account `bun:"-"`
// Who is targeted by this block? // Who is targeted by this block?
TargetAccountID string `bun:"type:CHAR(26),notnull"` TargetAccountID string `bun:"type:CHAR(26),notnull"`
TargetAccount *Account `bun:"rel:belongs-to"` TargetAccount *Account `bun:"-"`
// Activitypub URI for this block // Activitypub URI for this block
URI string `bun:",notnull"` URI string `bun:",notnull"`
} }

View file

@ -27,9 +27,9 @@ type DomainBlock struct {
// blocked domain // blocked domain
Domain string `bun:",pk,notnull,unique"` Domain string `bun:",pk,notnull,unique"`
// When was this block created // When was this block created
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// When was this block updated // When was this block updated
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// Account ID of the creator of this block // Account ID of the creator of this block
CreatedByAccountID string `bun:"type:CHAR(26),notnull"` CreatedByAccountID string `bun:"type:CHAR(26),notnull"`
CreatedByAccount *Account `bun:"rel:belongs-to"` CreatedByAccount *Account `bun:"rel:belongs-to"`

View file

@ -27,9 +27,9 @@ type EmailDomainBlock struct {
// Email domain to block. Eg. 'gmail.com' or 'hotmail.com' // Email domain to block. Eg. 'gmail.com' or 'hotmail.com'
Domain string `bun:",notnull"` Domain string `bun:",notnull"`
// When was this block created // When was this block created
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// When was this block updated // When was this block updated
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// Account ID of the creator of this block // Account ID of the creator of this block
CreatedByAccountID string `bun:"type:CHAR(26),notnull"` CreatedByAccountID string `bun:"type:CHAR(26),notnull"`
CreatedByAccount *Account `bun:"rel:belongs-to"` CreatedByAccount *Account `bun:"rel:belongs-to"`

View file

@ -28,11 +28,11 @@ type Emoji struct {
// eg., 'blob_hug' 'purple_heart' Must be unique with domain. // eg., 'blob_hug' 'purple_heart' Must be unique with domain.
Shortcode string `bun:",notnull,unique:shortcodedomain"` Shortcode string `bun:",notnull,unique:shortcodedomain"`
// Origin domain of this emoji, eg 'example.org', 'queer.party'. empty string for local emojis. // Origin domain of this emoji, eg 'example.org', 'queer.party'. empty string for local emojis.
Domain string `bun:",notnull,default:'',use_zero,unique:shortcodedomain"` Domain string `bun:",notnull,default:'',unique:shortcodedomain"`
// When was this emoji created. Must be unique with shortcode. // When was this emoji created. Must be unique with shortcode.
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// When was this emoji updated // When was this emoji updated
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// Where can this emoji be retrieved remotely? Null for local emojis. // Where can this emoji be retrieved remotely? Null for local emojis.
// For remote emojis, it'll be something like: // For remote emojis, it'll be something like:
// https://hackers.town/system/custom_emojis/images/000/049/842/original/1b74481204feabfd.png // https://hackers.town/system/custom_emojis/images/000/049/842/original/1b74481204feabfd.png
@ -65,7 +65,7 @@ type Emoji struct {
// Size of the static version of the emoji image file in bytes, for serving purposes. // Size of the static version of the emoji image file in bytes, for serving purposes.
ImageStaticFileSize int `bun:",notnull"` ImageStaticFileSize int `bun:",notnull"`
// When was the emoji image last updated? // When was the emoji image last updated?
ImageUpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` ImageUpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// Has a moderation action disabled this emoji from being shown? // Has a moderation action disabled this emoji from being shown?
Disabled bool `bun:",notnull,default:false"` Disabled bool `bun:",notnull,default:false"`
// ActivityStreams uri of this emoji. Something like 'https://example.org/emojis/1234' // ActivityStreams uri of this emoji. Something like 'https://example.org/emojis/1234'
@ -74,5 +74,5 @@ type Emoji struct {
VisibleInPicker bool `bun:",notnull,default:true"` VisibleInPicker bool `bun:",notnull,default:true"`
// In which emoji category is this emoji visible? // In which emoji category is this emoji visible?
CategoryID string `bun:"type:CHAR(26)"` CategoryID string `bun:"type:CHAR(26)"`
Status *Status `bun:"rel:belongs-to"` Status *Status `bun:"-"`
} }

View file

@ -25,15 +25,15 @@ type Follow struct {
// id of this follow in the database // id of this follow in the database
ID string `bun:"type:CHAR(26),pk,notnull,unique"` ID string `bun:"type:CHAR(26),pk,notnull,unique"`
// When was this follow created? // When was this follow created?
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// When was this follow last updated? // When was this follow last updated?
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// Who does this follow belong to? // Who does this follow belong to?
AccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"` AccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"`
Account *Account `bun:"rel:belongs-to"` Account *Account `bun:"-"`
// Who does AccountID follow? // Who does AccountID follow?
TargetAccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"` TargetAccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"`
TargetAccount *Account `bun:"rel:belongs-to"` TargetAccount *Account `bun:"-"`
// Does this follow also want to see reblogs and not just posts? // Does this follow also want to see reblogs and not just posts?
ShowReblogs bool `bun:"default:true"` ShowReblogs bool `bun:"default:true"`
// What is the activitypub URI of this follow? // What is the activitypub URI of this follow?

View file

@ -25,15 +25,15 @@ type FollowRequest struct {
// id of this follow request in the database // id of this follow request in the database
ID string `bun:"type:CHAR(26),pk,notnull,unique"` ID string `bun:"type:CHAR(26),pk,notnull,unique"`
// When was this follow request created? // When was this follow request created?
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// When was this follow request last updated? // When was this follow request last updated?
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// Who does this follow request originate from? // Who does this follow request originate from?
AccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"` AccountID string `bun:"type:CHAR(26),unique:frsrctarget,notnull"`
Account Account `bun:"rel:belongs-to"` Account Account `bun:"-"`
// Who is the target of this follow request? // Who is the target of this follow request?
TargetAccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"` TargetAccountID string `bun:"type:CHAR(26),unique:frsrctarget,notnull"`
TargetAccount Account `bun:"rel:belongs-to"` TargetAccount Account `bun:"-"`
// Does this follow also want to see reblogs and not just posts? // Does this follow also want to see reblogs and not just posts?
ShowReblogs bool `bun:"default:true"` ShowReblogs bool `bun:"default:true"`
// What is the activitypub URI of this follow request? // What is the activitypub URI of this follow request?

View file

@ -13,14 +13,14 @@ type Instance struct {
// base URI of this instance eg https://example.org // base URI of this instance eg https://example.org
URI string `bun:",notnull,unique"` URI string `bun:",notnull,unique"`
// When was this instance created in the db? // When was this instance created in the db?
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// When was this instance last updated in the db? // When was this instance last updated in the db?
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// When was this instance suspended, if at all? // When was this instance suspended, if at all?
SuspendedAt time.Time SuspendedAt time.Time
// ID of any existing domain block for this instance in the database // ID of any existing domain block for this instance in the database
DomainBlockID string `bun:"type:CHAR(26)"` DomainBlockID string `bun:"type:CHAR(26)"`
DomainBlock *DomainBlock `bun:"rel:belongs-to"` DomainBlock *DomainBlock `bun:"-"`
// Short description of this instance // Short description of this instance
ShortDescription string ShortDescription string
// Longer description of this instance // Longer description of this instance
@ -33,7 +33,7 @@ type Instance struct {
ContactAccountUsername string ContactAccountUsername string
// Contact account ID in the database for this instance // Contact account ID in the database for this instance
ContactAccountID string `bun:"type:CHAR(26)"` ContactAccountID string `bun:"type:CHAR(26)"`
ContactAccount *Account `bun:"rel:belongs-to"` ContactAccount *Account `bun:"-"`
// Reputation score of this instance // Reputation score of this instance
Reputation int64 `bun:",notnull,default:0"` Reputation int64 `bun:",notnull,default:0"`
// Version of the software used on this instance // Version of the software used on this instance

View file

@ -34,16 +34,16 @@ type MediaAttachment struct {
// Where can the attachment be retrieved on a remote server (empty for local media) // Where can the attachment be retrieved on a remote server (empty for local media)
RemoteURL string RemoteURL string
// When was the attachment created // When was the attachment created
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// When was the attachment last updated // When was the attachment last updated
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// Type of file (image/gif/audio/video) // Type of file (image/gif/audio/video)
Type FileType `bun:",notnull"` Type FileType `bun:",notnull"`
// Metadata about the file // Metadata about the file
FileMeta FileMeta FileMeta FileMeta
// To which account does this attachment belong // To which account does this attachment belong
AccountID string `bun:"type:CHAR(26),notnull"` AccountID string `bun:"type:CHAR(26),notnull"`
Account *Account `bun:"rel:belongs-to"` Account *Account `bun:"rel:has-one"`
// Description of the attachment (for screenreaders) // Description of the attachment (for screenreaders)
Description string Description string
// To which scheduled status does this attachment belong // To which scheduled status does this attachment belong
@ -71,7 +71,7 @@ type File struct {
// What is the size of the file in bytes. // What is the size of the file in bytes.
FileSize int FileSize int
// When was the file last updated. // When was the file last updated.
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
} }
// Thumbnail refers to a small image thumbnail derived from a larger image, video, or audio file. // Thumbnail refers to a small image thumbnail derived from a larger image, video, or audio file.
@ -83,7 +83,7 @@ type Thumbnail struct {
// What is the size of the file in bytes // What is the size of the file in bytes
FileSize int FileSize int
// When was the file last updated // When was the file last updated
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// What is the URL of the thumbnail on the local server // What is the URL of the thumbnail on the local server
URL string URL string
// What is the remote URL of the thumbnail (empty for local media) // What is the remote URL of the thumbnail (empty for local media)

View file

@ -28,9 +28,9 @@ type Mention struct {
StatusID string `bun:"type:CHAR(26),notnull"` StatusID string `bun:"type:CHAR(26),notnull"`
Status *Status `bun:"rel:belongs-to"` Status *Status `bun:"rel:belongs-to"`
// When was this mention created? // When was this mention created?
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// When was this mention last updated? // When was this mention last updated?
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// What's the internal account ID of the originator of the mention? // What's the internal account ID of the originator of the mention?
OriginAccountID string `bun:"type:CHAR(26),notnull"` OriginAccountID string `bun:"type:CHAR(26),notnull"`
OriginAccount *Account `bun:"rel:belongs-to"` OriginAccount *Account `bun:"rel:belongs-to"`

View file

@ -27,7 +27,7 @@ type Notification struct {
// Type of this notification // Type of this notification
NotificationType NotificationType `bun:",notnull"` NotificationType NotificationType `bun:",notnull"`
// Creation time of this notification // Creation time of this notification
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// Which account does this notification target (ie., who will receive the notification?) // Which account does this notification target (ie., who will receive the notification?)
TargetAccountID string `bun:"type:CHAR(26),notnull"` TargetAccountID string `bun:"type:CHAR(26),notnull"`
TargetAccount *Account `bun:"rel:belongs-to"` TargetAccount *Account `bun:"rel:belongs-to"`

View file

@ -37,38 +37,38 @@ type Status struct {
Attachments []*MediaAttachment `bun:"attached_media,rel:has-many"` Attachments []*MediaAttachment `bun:"attached_media,rel:has-many"`
// Database IDs of any tags used in this status // Database IDs of any tags used in this status
TagIDs []string `bun:"tags,array"` TagIDs []string `bun:"tags,array"`
Tags []*Tag `bun:"attached_tags,m2m:status_to_tags"` // https://pg.uptrace.dev/orm/many-to-many-relation/ Tags []*Tag `bun:"attached_tags,m2m:status_to_tags"` // https://bun.uptrace.dev/guide/relations.html#many-to-many-relation
// Database IDs of any mentions in this status // Database IDs of any mentions in this status
MentionIDs []string `bun:"mentions,array"` MentionIDs []string `bun:"mentions,array"`
Mentions []*Mention `bun:"attached_mentions,rel:has-many"` Mentions []*Mention `bun:"attached_mentions,rel:has-many"`
// Database IDs of any emojis used in this status // Database IDs of any emojis used in this status
EmojiIDs []string `bun:"emojis,array"` EmojiIDs []string `bun:"emojis,array"`
Emojis []*Emoji `bun:"attached_emojis,m2m:status_to_emojis"` // https://pg.uptrace.dev/orm/many-to-many-relation/ Emojis []*Emoji `bun:"attached_emojis,m2m:status_to_emojis"` // https://bun.uptrace.dev/guide/relations.html#many-to-many-relation
// when was this status created? // when was this status created?
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
// when was this status updated? // when was this status updated?
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
// is this status from a local account? // is this status from a local account?
Local bool Local bool
// which account posted this status? // which account posted this status?
AccountID string `bun:"type:CHAR(26),notnull"` AccountID string `bun:"type:CHAR(26),notnull"`
Account *Account `bun:"rel:belongs-to"` Account *Account `bun:"-"`
// AP uri of the owner of this status // AP uri of the owner of this status
AccountURI string AccountURI string
// id of the status this status is a reply to // id of the status this status is a reply to
InReplyToID string `bun:"type:CHAR(26)"` InReplyToID string `bun:"type:CHAR(26)"`
InReplyTo *Status `bun:"rel:belongs-to"` InReplyTo *Status `bun:"-"`
// AP uri of the status this status is a reply to // AP uri of the status this status is a reply to
InReplyToURI string InReplyToURI string
// id of the account that this status replies to // id of the account that this status replies to
InReplyToAccountID string `bun:"type:CHAR(26)"` InReplyToAccountID string `bun:"type:CHAR(26)"`
InReplyToAccount *Account `bun:"rel:belongs-to"` InReplyToAccount *Account `bun:"-"`
// id of the status this status is a boost of // id of the status this status is a boost of
BoostOfID string `bun:"type:CHAR(26)"` BoostOfID string `bun:"type:CHAR(26)"`
BoostOf *Status `bun:"rel:belongs-to"` BoostOf *Status `bun:"-"`
// id of the account that owns the boosted status // id of the account that owns the boosted status
BoostOfAccountID string `bun:"type:CHAR(26)"` BoostOfAccountID string `bun:"type:CHAR(26)"`
BoostOfAccount *Account `bun:"rel:belongs-to"` BoostOfAccount *Account `bun:"-"`
// cw string for this status // cw string for this status
ContentWarning string ContentWarning string
// visibility entry for this status // visibility entry for this status
@ -79,7 +79,7 @@ type Status struct {
Language string Language string
// Which application was used to create this status? // Which application was used to create this status?
CreatedWithApplicationID string `bun:"type:CHAR(26)"` CreatedWithApplicationID string `bun:"type:CHAR(26)"`
CreatedWithApplication *Application `bun:"rel:belongs-to"` CreatedWithApplication *Application `bun:"-"`
// advanced visibility for this status // advanced visibility for this status
VisibilityAdvanced *VisibilityAdvanced VisibilityAdvanced *VisibilityAdvanced
// What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types // What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types
@ -94,17 +94,17 @@ type Status struct {
// StatusToTag is an intermediate struct to facilitate the many2many relationship between a status and one or more tags. // StatusToTag is an intermediate struct to facilitate the many2many relationship between a status and one or more tags.
type StatusToTag struct { type StatusToTag struct {
StatusID string `bun:"type:CHAR(26),unique:statustag"` StatusID string `bun:"type:CHAR(26),unique:statustag"`
Status *Status `bun:"rel:has-one"` Status *Status `bun:"rel:belongs-to"`
TagID string `bun:"type:CHAR(26),unique:statustag"` TagID string `bun:"type:CHAR(26),unique:statustag"`
Tag *Tag `bun:"rel:has-one"` Tag *Tag `bun:"rel:belongs-to"`
} }
// StatusToEmoji is an intermediate struct to facilitate the many2many relationship between a status and one or more emojis. // StatusToEmoji is an intermediate struct to facilitate the many2many relationship between a status and one or more emojis.
type StatusToEmoji struct { type StatusToEmoji struct {
StatusID string `bun:"type:CHAR(26),unique:statusemoji"` StatusID string `bun:"type:CHAR(26),unique:statusemoji"`
Status *Status `bun:"rel:has-one"` Status *Status `bun:"rel:belongs-to"`
EmojiID string `bun:"type:CHAR(26),unique:statusemoji"` EmojiID string `bun:"type:CHAR(26),unique:statusemoji"`
Emoji *Emoji `bun:"rel:has-one"` Emoji *Emoji `bun:"rel:belongs-to"`
} }
// Visibility represents the visibility granularity of a status. // Visibility represents the visibility granularity of a status.

View file

@ -25,7 +25,7 @@ type StatusBookmark struct {
// id of this bookmark in the database // id of this bookmark in the database
ID string `bun:"type:CHAR(26),pk,notnull,unique"` ID string `bun:"type:CHAR(26),pk,notnull,unique"`
// when was this bookmark created // when was this bookmark created
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// id of the account that created ('did') the bookmarking // id of the account that created ('did') the bookmarking
AccountID string `bun:"type:CHAR(26),notnull"` AccountID string `bun:"type:CHAR(26),notnull"`
Account *Account `bun:"rel:belongs-to"` Account *Account `bun:"rel:belongs-to"`

View file

@ -25,7 +25,7 @@ type StatusFave struct {
// id of this fave in the database // id of this fave in the database
ID string `bun:"type:CHAR(26),pk,notnull,unique"` ID string `bun:"type:CHAR(26),pk,notnull,unique"`
// when was this fave created // when was this fave created
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// id of the account that created ('did') the fave // id of the account that created ('did') the fave
AccountID string `bun:"type:CHAR(26),notnull"` AccountID string `bun:"type:CHAR(26),notnull"`
Account *Account `bun:"rel:belongs-to"` Account *Account `bun:"rel:belongs-to"`

View file

@ -25,7 +25,7 @@ type StatusMute struct {
// id of this mute in the database // id of this mute in the database
ID string `bun:"type:CHAR(26),pk,notnull,unique"` ID string `bun:"type:CHAR(26),pk,notnull,unique"`
// when was this mute created // when was this mute created
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// id of the account that created ('did') the mute // id of the account that created ('did') the mute
AccountID string `bun:"type:CHAR(26),notnull"` AccountID string `bun:"type:CHAR(26),notnull"`
Account *Account `bun:"rel:belongs-to"` Account *Account `bun:"rel:belongs-to"`

View file

@ -31,13 +31,13 @@ type Tag struct {
// Which account ID is the first one we saw using this tag? // Which account ID is the first one we saw using this tag?
FirstSeenFromAccountID string `bun:"type:CHAR(26)"` FirstSeenFromAccountID string `bun:"type:CHAR(26)"`
// when was this tag created // when was this tag created
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// when was this tag last updated // when was this tag last updated
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// can our instance users use this tag? // can our instance users use this tag?
Useable bool `bun:",notnull,default:true"` Useable bool `bun:",notnull,default:true"`
// can our instance users look up this tag? // can our instance users look up this tag?
Listable bool `bun:",notnull,default:true"` Listable bool `bun:",notnull,default:true"`
// when was this tag last used? // when was this tag last used?
LastStatusAt time.Time `bun:"type:timestamp,notnull,default:now()"` LastStatusAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
} }

View file

@ -45,19 +45,19 @@ type User struct {
*/ */
// When was this user created? // When was this user created?
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
// From what IP was this user created? // From what IP was this user created?
SignUpIP net.IP SignUpIP net.IP `bun:",nullzero"`
// When was this user updated (eg., password changed, email address changed)? // When was this user updated (eg., password changed, email address changed)?
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"` UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
// When did this user sign in for their current session? // When did this user sign in for their current session?
CurrentSignInAt time.Time `bun:"type:timestamp"` CurrentSignInAt time.Time `bun:",nullzero"`
// What's the most recent IP of this user // What's the most recent IP of this user
CurrentSignInIP net.IP CurrentSignInIP net.IP `bun:",nullzero"`
// When did this user last sign in? // When did this user last sign in?
LastSignInAt time.Time `bun:"type:timestamp"` LastSignInAt time.Time `bun:",nullzero"`
// What's the previous IP of this user? // What's the previous IP of this user?
LastSignInIP net.IP LastSignInIP net.IP `bun:",nullzero"`
// How many times has this user signed in? // How many times has this user signed in?
SignInCount int SignInCount int
// id of the user who invited this user (who let this guy in?) // id of the user who invited this user (who let this guy in?)
@ -70,9 +70,9 @@ type User struct {
Locale string Locale string
// Which application id created this user? See gtsmodel.Application // Which application id created this user? See gtsmodel.Application
CreatedByApplicationID string `bun:"type:CHAR(26)"` CreatedByApplicationID string `bun:"type:CHAR(26)"`
CreatedByApplication *Application `bun:"rel:belongs-to"` CreatedByApplication *Application `bun:"-"`
// When did we last contact this user // When did we last contact this user
LastEmailedAt time.Time `bun:"type:timestamp"` LastEmailedAt time.Time `bun:",nullzero"`
/* /*
USER CONFIRMATION USER CONFIRMATION
@ -81,9 +81,9 @@ type User struct {
// What confirmation token did we send this user/what are we expecting back? // What confirmation token did we send this user/what are we expecting back?
ConfirmationToken string ConfirmationToken string
// When did the user confirm their email address // When did the user confirm their email address
ConfirmedAt time.Time `bun:"type:timestamp"` ConfirmedAt time.Time `bun:",nullzero"`
// When did we send email confirmation to this user? // When did we send email confirmation to this user?
ConfirmationSentAt time.Time `bun:"type:timestamp"` ConfirmationSentAt time.Time `bun:",nullzero"`
// Email address that hasn't yet been confirmed // Email address that hasn't yet been confirmed
UnconfirmedEmail string UnconfirmedEmail string

View file

@ -55,7 +55,7 @@ func (cs *clientStore) Set(ctx context.Context, id string, cli oauth2.ClientInfo
Domain: cli.GetDomain(), Domain: cli.GetDomain(),
UserID: cli.GetUserID(), UserID: cli.GetUserID(),
} }
return cs.db.UpdateByID(ctx, id, poc) return cs.db.Put(ctx, poc)
} }
func (cs *clientStore) Delete(ctx context.Context, id string) error { func (cs *clientStore) Delete(ctx context.Context, id string) error {

View file

@ -224,7 +224,7 @@ func (p *processor) ProcessTags(ctx context.Context, form *apimodel.AdvancedStat
return fmt.Errorf("error generating hashtags from status: %s", err) return fmt.Errorf("error generating hashtags from status: %s", err)
} }
for _, tag := range gtsTags { for _, tag := range gtsTags {
if err := p.db.Upsert(ctx, tag, "name"); err != nil { if err := p.db.Put(ctx, tag); err != nil && err != db.ErrAlreadyExists {
return fmt.Errorf("error putting tags in db: %s", err) return fmt.Errorf("error putting tags in db: %s", err)
} }
tags = append(tags, tag.ID) tags = append(tags, tag.ID)

View file

@ -92,7 +92,7 @@ func StandardDBSetup(db db.DB, accounts map[string]*gtsmodel.Account) {
for _, m := range testModels { for _, m := range testModels {
if err := db.CreateTable(ctx, m); err != nil { if err := db.CreateTable(ctx, m); err != nil {
logrus.Panic(err) logrus.Panicf("error creating table for %+v: %s", m, err)
} }
} }

View file

@ -11,6 +11,10 @@
[![Documentation](https://img.shields.io/badge/bun-documentation-informational)](https://bun.uptrace.dev/) [![Documentation](https://img.shields.io/badge/bun-documentation-informational)](https://bun.uptrace.dev/)
[![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj) [![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj)
Status: API freeze (release candidate). Note that all sub-packages (mainly extra/\* packages) are
not part of the API freeze and are developed independently. You can think of them as 3-rd party
packages.
Main features are: Main features are:
- Works with [PostgreSQL](https://bun.uptrace.dev/guide/drivers.html#postgresql), - Works with [PostgreSQL](https://bun.uptrace.dev/guide/drivers.html#postgresql),

View file

@ -4,4 +4,4 @@ go 1.16
replace github.com/uptrace/bun => ../.. replace github.com/uptrace/bun => ../..
require github.com/uptrace/bun v0.4.3 require github.com/uptrace/bun v1.0.0-rc.1

View file

@ -20,4 +20,4 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -89,10 +89,10 @@ func (f Formatter) AppendQuery(dst []byte, query string, args ...interface{}) []
func (f Formatter) append(dst []byte, p *parser.Parser, args []interface{}) []byte { func (f Formatter) append(dst []byte, p *parser.Parser, args []interface{}) []byte {
var namedArgs NamedArgAppender var namedArgs NamedArgAppender
if len(args) == 1 { if len(args) == 1 {
var ok bool if v, ok := args[0].(NamedArgAppender); ok {
namedArgs, ok = args[0].(NamedArgAppender) namedArgs = v
if !ok { } else if v, ok := newStructArgs(f, args[0]); ok {
namedArgs, _ = newStructArgs(f, args[0]) namedArgs = v
} }
} }

View file

@ -2,5 +2,5 @@ package bun
// Version is the current release version. // Version is the current release version.
func Version() string { func Version() string {
return "0.4.3" return "1.0.0-rc.1"
} }

4
vendor/modules.txt vendored
View file

@ -389,7 +389,7 @@ github.com/tdewolff/parse/v2/strconv
github.com/tmthrgd/go-hex github.com/tmthrgd/go-hex
# github.com/ugorji/go/codec v1.2.6 # github.com/ugorji/go/codec v1.2.6
github.com/ugorji/go/codec github.com/ugorji/go/codec
# github.com/uptrace/bun v0.4.3 # github.com/uptrace/bun v1.0.0-rc.1
## explicit ## explicit
github.com/uptrace/bun github.com/uptrace/bun
github.com/uptrace/bun/dialect github.com/uptrace/bun/dialect
@ -400,7 +400,7 @@ github.com/uptrace/bun/internal
github.com/uptrace/bun/internal/parser github.com/uptrace/bun/internal/parser
github.com/uptrace/bun/internal/tagparser github.com/uptrace/bun/internal/tagparser
github.com/uptrace/bun/schema github.com/uptrace/bun/schema
# github.com/uptrace/bun/dialect/pgdialect v0.4.3 # github.com/uptrace/bun/dialect/pgdialect v1.0.0-rc.1
## explicit ## explicit
github.com/uptrace/bun/dialect/pgdialect github.com/uptrace/bun/dialect/pgdialect
# github.com/urfave/cli/v2 v2.3.0 # github.com/urfave/cli/v2 v2.3.0