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)
* [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-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)
* [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).
* [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).
* [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).
@ -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).
* [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).
* [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).
* [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/tdewolff/minify/v2 v2.9.21
github.com/tidwall/buntdb v1.2.4 // indirect
github.com/uptrace/bun v0.4.3
github.com/uptrace/bun/dialect/pgdialect v0.4.3
github.com/uptrace/bun v1.0.0-rc.1
github.com/uptrace/bun/dialect/pgdialect v1.0.0-rc.1
github.com/urfave/cli/v2 v2.3.0
github.com/wagslane/go-password-validator v0.3.0
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.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
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 v0.4.3/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
github.com/uptrace/bun/dialect/pgdialect v0.4.3 h1:lM2IUKpU99110chKkupw3oTfXiOKpB0hTJIe6frqQDo=
github.com/uptrace/bun/dialect/pgdialect v0.4.3/go.mod h1:BaNvWejl32oKUhwpFkw/eNcWldzIlVY4nfw/sNul0s8=
github.com/uptrace/bun v1.0.0-rc.1 h1:yMjz/JdlgYRema5mk59URzjAV7HpOV58Fj3KID34K9U=
github.com/uptrace/bun v1.0.0-rc.1/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
github.com/uptrace/bun/dialect/pgdialect v1.0.0-rc.1 h1:4rxcO4+x8r2xyCnduH9fhhkjhbtzLHFl3vmx2goVgio=
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/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
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.
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.
// 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

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) {
account := &gtsmodel.Account{}
account := new(gtsmodel.Account)
q := a.newAccountQ(account).
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) {
account := &gtsmodel.Account{}
account := new(gtsmodel.Account)
q := a.newAccountQ(account).
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) {
account := &gtsmodel.Account{}
account := new(gtsmodel.Account)
q := a.newAccountQ(account).
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) {
account := &gtsmodel.Account{}
account := new(gtsmodel.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) {
status := &gtsmodel.Status{}
status := new(gtsmodel.Status)
q := a.conn.
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
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
}
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 nil
}
func (a *accountDB) GetLocalAccountByUsername(ctx context.Context, username string) (*gtsmodel.Account, db.Error) {
account := &gtsmodel.Account{}
account := new(gtsmodel.Account)
q := a.newAccountQ(account).
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) {
faves := []*gtsmodel.StatusFave{}
faves := new([]*gtsmodel.StatusFave)
if err := a.conn.
NewSelect().
Model(&faves).
Model(faves).
Where("account_id = ?", accountID).
Scan(ctx); err != nil {
return nil, err
}
return faves, nil
return *faves, nil
}
func (a *accountDB) CountAccountStatuses(ctx context.Context, accountID string) (int, db.Error) {

View file

@ -21,7 +21,6 @@ package pg
import (
"context"
"errors"
"fmt"
"strings"
"github.com/sirupsen/logrus"
@ -113,23 +112,11 @@ func (b *basicDB) DeleteWhere(ctx context.Context, where []db.Where, i interface
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 {
q := b.conn.
NewInsert().
NewUpdate().
Model(i).
Where("id = ?", id).
On("CONFLICT (id) DO UPDATE")
Where("id = ?", id)
_, 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 {
_, err := b.conn.NewCreateTable().IfNotExists().Model(i).Exec(ctx)
_, err := b.conn.NewCreateTable().Model(i).IfNotExists().Exec(ctx)
return err
}
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)
}

View file

@ -76,13 +76,7 @@ func (s *statusDB) newStatusQ(status interface{}) *bun.SelectQuery {
Relation("Attachments").
Relation("Tags").
Relation("Mentions").
Relation("Emojis").
Relation("Account").
Relation("InReplyTo").
Relation("InReplyToAccount").
Relation("BoostOf").
Relation("BoostOfAccount").
Relation("CreatedWithApplication")
Relation("Emojis")
}
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
}
status := &gtsmodel.Status{}
status := new(gtsmodel.Status)
q := s.newStatusQ(status).
Where("status.id = ?", id)
err := processErrorResponse(q.Scan(ctx))
if err == nil && status != nil {
if err != nil {
return nil, err
}
if status != nil {
s.cacheStatus(id, status)
}

View file

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

View file

@ -65,9 +65,9 @@ type Account struct {
// This account has moved this account id in the database
MovedToAccountID string `bun:"type:CHAR(26)"`
// 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?
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?
Bot bool
// 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?
URL string `bun:",unique"`
// 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
InboxURI string `bun:",unique"`
// 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?
SensitizedAt time.Time `bun:"type:timestamp"`
SensitizedAt time.Time `bun:",nullzero"`
// 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)
SuspendedAt time.Time `bun:"type:timestamp"`
SuspendedAt time.Time `bun:",nullzero"`
// Should we hide this account's collections?
HideCollections bool
// 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 {
Name 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 string `bun:"type:CHAR(26),pk,notnull"`
// 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
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:now()"`
UpdatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// Who created this block?
AccountID string `bun:"type:CHAR(26),notnull"`
Account *Account `bun:"rel:belongs-to"`
Account *Account `bun:"-"`
// Who is targeted by this block?
TargetAccountID string `bun:"type:CHAR(26),notnull"`
TargetAccount *Account `bun:"rel:belongs-to"`
TargetAccount *Account `bun:"-"`
// Activitypub URI for this block
URI string `bun:",notnull"`
}

View file

@ -27,9 +27,9 @@ type DomainBlock struct {
// blocked domain
Domain string `bun:",pk,notnull,unique"`
// 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
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
CreatedByAccountID string `bun:"type:CHAR(26),notnull"`
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'
Domain string `bun:",notnull"`
// 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
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
CreatedByAccountID string `bun:"type:CHAR(26),notnull"`
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.
Shortcode string `bun:",notnull,unique:shortcodedomain"`
// 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.
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"`
CreatedAt time.Time `bun:"type:timestamp,notnull,default:current_timestamp"`
// 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.
// For remote emojis, it'll be something like:
// 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.
ImageStaticFileSize int `bun:",notnull"`
// 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?
Disabled bool `bun:",notnull,default:false"`
// 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"`
// In which emoji category is this emoji visible?
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 string `bun:"type:CHAR(26),pk,notnull,unique"`
// 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?
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?
AccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"`
Account *Account `bun:"rel:belongs-to"`
Account *Account `bun:"-"`
// Who does AccountID follow?
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?
ShowReblogs bool `bun:"default:true"`
// 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 string `bun:"type:CHAR(26),pk,notnull,unique"`
// 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?
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?
AccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"`
Account Account `bun:"rel:belongs-to"`
AccountID string `bun:"type:CHAR(26),unique:frsrctarget,notnull"`
Account Account `bun:"-"`
// Who is the target of this follow request?
TargetAccountID string `bun:"type:CHAR(26),unique:srctarget,notnull"`
TargetAccount Account `bun:"rel:belongs-to"`
TargetAccountID string `bun:"type:CHAR(26),unique:frsrctarget,notnull"`
TargetAccount Account `bun:"-"`
// Does this follow also want to see reblogs and not just posts?
ShowReblogs bool `bun:"default:true"`
// 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
URI string `bun:",notnull,unique"`
// 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?
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?
SuspendedAt time.Time
// ID of any existing domain block for this instance in the database
DomainBlockID string `bun:"type:CHAR(26)"`
DomainBlock *DomainBlock `bun:"rel:belongs-to"`
DomainBlock *DomainBlock `bun:"-"`
// Short description of this instance
ShortDescription string
// Longer description of this instance
@ -33,7 +33,7 @@ type Instance struct {
ContactAccountUsername string
// Contact account ID in the database for this instance
ContactAccountID string `bun:"type:CHAR(26)"`
ContactAccount *Account `bun:"rel:belongs-to"`
ContactAccount *Account `bun:"-"`
// Reputation score of this instance
Reputation int64 `bun:",notnull,default:0"`
// 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)
RemoteURL string
// 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
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 FileType `bun:",notnull"`
// Metadata about the file
FileMeta FileMeta
// To which account does this attachment belong
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 string
// To which scheduled status does this attachment belong
@ -71,7 +71,7 @@ type File struct {
// What is the size of the file in bytes.
FileSize int
// 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.
@ -83,7 +83,7 @@ type Thumbnail struct {
// What is the size of the file in bytes
FileSize int
// 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
URL string
// 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"`
Status *Status `bun:"rel:belongs-to"`
// 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?
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?
OriginAccountID string `bun:"type:CHAR(26),notnull"`
OriginAccount *Account `bun:"rel:belongs-to"`

View file

@ -27,7 +27,7 @@ type Notification struct {
// Type of this notification
NotificationType NotificationType `bun:",notnull"`
// 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?)
TargetAccountID string `bun:"type:CHAR(26),notnull"`
TargetAccount *Account `bun:"rel:belongs-to"`

View file

@ -37,38 +37,38 @@ type Status struct {
Attachments []*MediaAttachment `bun:"attached_media,rel:has-many"`
// Database IDs of any tags used in this status
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
MentionIDs []string `bun:"mentions,array"`
Mentions []*Mention `bun:"attached_mentions,rel:has-many"`
// Database IDs of any emojis used in this status
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?
CreatedAt time.Time `bun:"type:timestamp,notnull,default:now()"`
CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
// 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?
Local bool
// which account posted this status?
AccountID string `bun:"type:CHAR(26),notnull"`
Account *Account `bun:"rel:belongs-to"`
Account *Account `bun:"-"`
// AP uri of the owner of this status
AccountURI string
// id of the status this status is a reply to
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
InReplyToURI string
// id of the account that this status replies to
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
BoostOfID string `bun:"type:CHAR(26)"`
BoostOf *Status `bun:"rel:belongs-to"`
BoostOf *Status `bun:"-"`
// id of the account that owns the boosted status
BoostOfAccountID string `bun:"type:CHAR(26)"`
BoostOfAccount *Account `bun:"rel:belongs-to"`
BoostOfAccount *Account `bun:"-"`
// cw string for this status
ContentWarning string
// visibility entry for this status
@ -79,7 +79,7 @@ type Status struct {
Language string
// Which application was used to create this status?
CreatedWithApplicationID string `bun:"type:CHAR(26)"`
CreatedWithApplication *Application `bun:"rel:belongs-to"`
CreatedWithApplication *Application `bun:"-"`
// advanced visibility for this status
VisibilityAdvanced *VisibilityAdvanced
// 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.
type StatusToTag struct {
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"`
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.
type StatusToEmoji struct {
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"`
Emoji *Emoji `bun:"rel:has-one"`
Emoji *Emoji `bun:"rel:belongs-to"`
}
// 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 string `bun:"type:CHAR(26),pk,notnull,unique"`
// 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
AccountID string `bun:"type:CHAR(26),notnull"`
Account *Account `bun:"rel:belongs-to"`

View file

@ -25,7 +25,7 @@ type StatusFave struct {
// id of this fave in the database
ID string `bun:"type:CHAR(26),pk,notnull,unique"`
// 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
AccountID string `bun:"type:CHAR(26),notnull"`
Account *Account `bun:"rel:belongs-to"`

View file

@ -25,7 +25,7 @@ type StatusMute struct {
// id of this mute in the database
ID string `bun:"type:CHAR(26),pk,notnull,unique"`
// 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
AccountID string `bun:"type:CHAR(26),notnull"`
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?
FirstSeenFromAccountID string `bun:"type:CHAR(26)"`
// 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
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?
Useable bool `bun:",notnull,default:true"`
// can our instance users look up this tag?
Listable bool `bun:",notnull,default:true"`
// 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?
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?
SignUpIP net.IP
SignUpIP net.IP `bun:",nullzero"`
// 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?
CurrentSignInAt time.Time `bun:"type:timestamp"`
CurrentSignInAt time.Time `bun:",nullzero"`
// What's the most recent IP of this user
CurrentSignInIP net.IP
CurrentSignInIP net.IP `bun:",nullzero"`
// 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?
LastSignInIP net.IP
LastSignInIP net.IP `bun:",nullzero"`
// How many times has this user signed in?
SignInCount int
// id of the user who invited this user (who let this guy in?)
@ -70,9 +70,9 @@ type User struct {
Locale string
// Which application id created this user? See gtsmodel.Application
CreatedByApplicationID string `bun:"type:CHAR(26)"`
CreatedByApplication *Application `bun:"rel:belongs-to"`
CreatedByApplication *Application `bun:"-"`
// When did we last contact this user
LastEmailedAt time.Time `bun:"type:timestamp"`
LastEmailedAt time.Time `bun:",nullzero"`
/*
USER CONFIRMATION
@ -81,9 +81,9 @@ type User struct {
// What confirmation token did we send this user/what are we expecting back?
ConfirmationToken string
// 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?
ConfirmationSentAt time.Time `bun:"type:timestamp"`
ConfirmationSentAt time.Time `bun:",nullzero"`
// Email address that hasn't yet been confirmed
UnconfirmedEmail string

View file

@ -55,7 +55,7 @@ func (cs *clientStore) Set(ctx context.Context, id string, cli oauth2.ClientInfo
Domain: cli.GetDomain(),
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 {

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)
}
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)
}
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 {
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/)
[![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:
- 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 => ../..
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/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/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 {
var namedArgs NamedArgAppender
if len(args) == 1 {
var ok bool
namedArgs, ok = args[0].(NamedArgAppender)
if !ok {
namedArgs, _ = newStructArgs(f, args[0])
if v, ok := args[0].(NamedArgAppender); ok {
namedArgs = v
} else if v, ok := newStructArgs(f, args[0]); ok {
namedArgs = v
}
}

View file

@ -2,5 +2,5 @@ package bun
// Version is the current release version.
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/ugorji/go/codec v1.2.6
github.com/ugorji/go/codec
# github.com/uptrace/bun v0.4.3
# github.com/uptrace/bun v1.0.0-rc.1
## explicit
github.com/uptrace/bun
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/tagparser
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
github.com/uptrace/bun/dialect/pgdialect
# github.com/urfave/cli/v2 v2.3.0