BREAKING CHANGE: V2 of thr SDK #12
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.dragse.it/anthrove/otter-space-sdk/pkg/models"
|
"git.dragse.it/anthrove/otter-space-sdk/pkg/models"
|
||||||
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@ -111,9 +110,9 @@ func GetUserFavoritesCount(ctx context.Context, db *gorm.DB, anthroveUserID mode
|
|||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) (map[string]graphModels.AnthroveUserRelationship, error) {
|
func GetUserSourceLinks(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error) {
|
||||||
var userSources []models.UserSource
|
var userSources []models.UserSource
|
||||||
userSourceMap := make(map[string]graphModels.AnthroveUserRelationship)
|
userSourceMap := make(map[string]models.UserSource)
|
||||||
|
|
||||||
err := db.WithContext(ctx).Model(&models.UserSource{}).Where("user_id = ?", string(anthroveUserID)).Find(&userSources).Error
|
err := db.WithContext(ctx).Model(&models.UserSource{}).Where("user_id = ?", string(anthroveUserID)).Find(&userSources).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -133,10 +132,10 @@ func GetUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.A
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
userSourceMap[source.DisplayName] = graphModels.AnthroveUserRelationship{
|
userSourceMap[source.DisplayName] = models.UserSource{
|
||||||
UserID: userSource.AccountID,
|
UserID: userSource.AccountID,
|
||||||
Username: userSource.AccountUsername,
|
AccountUsername: userSource.AccountUsername,
|
||||||
Source: graphModels.AnthroveSource{
|
Source: models.Source{
|
||||||
DisplayName: source.DisplayName,
|
DisplayName: source.DisplayName,
|
||||||
Domain: source.Domain,
|
Domain: source.Domain,
|
||||||
Icon: source.Icon,
|
Icon: source.Icon,
|
||||||
@ -151,13 +150,13 @@ func GetUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.A
|
|||||||
return userSourceMap, nil
|
return userSourceMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSpecifiedUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]graphModels.AnthroveUserRelationship, error) {
|
func GetSpecifiedUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]models.UserSource, error) {
|
||||||
if anthroveUserID == "" || sourceDisplayName == "" {
|
if anthroveUserID == "" || sourceDisplayName == "" {
|
||||||
return nil, fmt.Errorf("anthroveUserID or sourceDisplayName is empty")
|
return nil, fmt.Errorf("anthroveUserID or sourceDisplayName is empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
var userSources []models.UserSource
|
var userSources []models.UserSource
|
||||||
userSourceMap := make(map[string]graphModels.AnthroveUserRelationship)
|
userSourceMap := make(map[string]models.UserSource)
|
||||||
|
|
||||||
err := db.WithContext(ctx).Model(&models.UserSource{}).InnerJoins("Source", db.Where("display_name = ?", sourceDisplayName)).Where("user_id = ?", string(anthroveUserID)).First(&userSources).Error
|
err := db.WithContext(ctx).Model(&models.UserSource{}).InnerJoins("Source", db.Where("display_name = ?", sourceDisplayName)).Where("user_id = ?", string(anthroveUserID)).First(&userSources).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -178,10 +177,10 @@ func GetSpecifiedUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
userSourceMap[source.DisplayName] = graphModels.AnthroveUserRelationship{
|
userSourceMap[source.DisplayName] = models.UserSource{
|
||||||
UserID: userSource.AccountID,
|
UserID: userSource.AccountID,
|
||||||
Username: userSource.AccountUsername,
|
AccountUsername: userSource.AccountUsername,
|
||||||
Source: graphModels.AnthroveSource{
|
Source: models.Source{
|
||||||
DisplayName: source.DisplayName,
|
DisplayName: source.DisplayName,
|
||||||
Domain: source.Domain,
|
Domain: source.Domain,
|
||||||
Icon: source.Icon,
|
Icon: source.Icon,
|
||||||
@ -197,62 +196,6 @@ func GetSpecifiedUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID
|
|||||||
return userSourceMap, nil
|
return userSourceMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAnthroveUser(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) (*graphModels.AnthroveUser, error) {
|
|
||||||
|
|
||||||
if anthroveUserID == "" {
|
|
||||||
return nil, fmt.Errorf("anthroveUserID cannot be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
var user models.User
|
|
||||||
var userSources []models.UserSource
|
|
||||||
anthroveUser := &graphModels.AnthroveUser{
|
|
||||||
UserID: anthroveUserID,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := db.WithContext(ctx).First(&user, "id = ?", string(anthroveUserID)).Error
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"anthrove_user_id": anthroveUserID,
|
|
||||||
}).Error("database: failed to get user")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = db.WithContext(ctx).Model(&models.UserSource{}).Where("user_id = ?", string(anthroveUserID)).Find(&userSources).Error
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"anthrove_user_id": anthroveUserID,
|
|
||||||
}).Error("database: failed to get user sources")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, userSource := range userSources {
|
|
||||||
var source models.Source
|
|
||||||
err = db.WithContext(ctx).Model(&models.Source{}).Where("id = ?", userSource.SourceID).First(&source).Error
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"source_id": userSource.SourceID,
|
|
||||||
}).Error("database: failed to get source")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
anthroveUser.Relationship = append(anthroveUser.Relationship, graphModels.AnthroveUserRelationship{
|
|
||||||
UserID: userSource.AccountID,
|
|
||||||
Username: userSource.AccountUsername,
|
|
||||||
Source: graphModels.AnthroveSource{
|
|
||||||
DisplayName: source.DisplayName,
|
|
||||||
Domain: source.Domain,
|
|
||||||
Icon: source.Icon,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"anthrove_user_id": anthroveUserID,
|
|
||||||
}).Trace("database: got anthrove user")
|
|
||||||
|
|
||||||
return anthroveUser, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAllAnthroveUserIDs(ctx context.Context, db *gorm.DB) ([]models.AnthroveUserID, error) {
|
func GetAllAnthroveUserIDs(ctx context.Context, db *gorm.DB) ([]models.AnthroveUserID, error) {
|
||||||
var users []models.User
|
var users []models.User
|
||||||
var userIDs []models.AnthroveUserID
|
var userIDs []models.AnthroveUserID
|
||||||
@ -274,9 +217,9 @@ func GetAllAnthroveUserIDs(ctx context.Context, db *gorm.DB) ([]models.AnthroveU
|
|||||||
return userIDs, nil
|
return userIDs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserFavoriteNodeWithPagination(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, skip int, limit int) (*graphModels.FavoriteList, error) {
|
func GetUserFavoriteNodeWithPagination(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, skip int, limit int) (*models.FavoriteList, error) {
|
||||||
var userFavorites []models.UserFavorite
|
var userFavorites []models.UserFavorite
|
||||||
var favoritePosts []graphModels.FavoritePost
|
var favoritePosts []models.Post
|
||||||
|
|
||||||
err := db.WithContext(ctx).Model(&models.UserFavorite{}).Where("user_id = ?", string(anthroveUserID)).Offset(skip).Limit(limit).Find(&userFavorites).Error
|
err := db.WithContext(ctx).Model(&models.UserFavorite{}).Where("user_id = ?", string(anthroveUserID)).Offset(skip).Limit(limit).Find(&userFavorites).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -298,11 +241,10 @@ func GetUserFavoriteNodeWithPagination(ctx context.Context, db *gorm.DB, anthrov
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
favoritePosts = append(favoritePosts, graphModels.FavoritePost{
|
favoritePosts = append(favoritePosts,
|
||||||
AnthrovePost: graphModels.AnthrovePost{
|
models.Post{
|
||||||
PostID: models.AnthrovePostID(post.ID),
|
BaseModel: models.BaseModel{ID: post.ID},
|
||||||
Rating: post.Rating,
|
Rating: post.Rating,
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,10 +253,10 @@ func GetUserFavoriteNodeWithPagination(ctx context.Context, db *gorm.DB, anthrov
|
|||||||
"anthrove_user_fav_count": len(favoritePosts),
|
"anthrove_user_fav_count": len(favoritePosts),
|
||||||
}).Trace("database: got all anthrove user favorites")
|
}).Trace("database: got all anthrove user favorites")
|
||||||
|
|
||||||
return &graphModels.FavoriteList{Posts: favoritePosts}, nil
|
return &models.FavoriteList{Posts: favoritePosts}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserTagNodeWitRelationToFavedPosts(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) ([]graphModels.TagsWithFrequency, error) {
|
func GetUserTagNodeWitRelationToFavedPosts(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) ([]models.TagsWithFrequency, error) {
|
||||||
var userFavorites []models.UserFavorite
|
var userFavorites []models.UserFavorite
|
||||||
err := db.WithContext(ctx).Where("user_id = ?", string(anthroveUserID)).Find(&userFavorites).Error
|
err := db.WithContext(ctx).Where("user_id = ?", string(anthroveUserID)).Find(&userFavorites).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -346,13 +288,13 @@ func GetUserTagNodeWitRelationToFavedPosts(ctx context.Context, db *gorm.DB, ant
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagsWithFrequency []graphModels.TagsWithFrequency
|
var tagsWithFrequency []models.TagsWithFrequency
|
||||||
for data, frequency := range tagFrequency {
|
for data, frequency := range tagFrequency {
|
||||||
tagsWithFrequency = append(tagsWithFrequency, graphModels.TagsWithFrequency{
|
tagsWithFrequency = append(tagsWithFrequency, models.TagsWithFrequency{
|
||||||
Frequency: int64(frequency),
|
Frequency: int64(frequency),
|
||||||
Tags: graphModels.AnthroveTag{
|
Tags: models.Tag{
|
||||||
Name: data.name,
|
Name: data.name,
|
||||||
Type: data.typeName,
|
Type: models.TagType(data.typeName),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -795,13 +795,13 @@ func TestGetUserSourceLink(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := GetUserSourceLink(tt.args.ctx, tt.args.db, tt.args.anthroveUserID)
|
got, err := GetUserSourceLinks(tt.args.ctx, tt.args.db, tt.args.anthroveUserID)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("GetUserSourceLink() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("GetUserSourceLinks() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("GetUserSourceLink() got = %v, want %v", got, tt.want)
|
t.Errorf("GetUserSourceLinks() got = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -6,45 +6,63 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type OtterSpace interface {
|
type OtterSpace interface {
|
||||||
|
// Connect establishes a connection to the database.
|
||||||
Connect(ctx context.Context, endpoint string, username string, password string, database string, port int, ssl string, timezone string) error
|
Connect(ctx context.Context, endpoint string, username string, password string, database string, port int, ssl string, timezone string) error
|
||||||
|
|
||||||
|
// AddUserWithRelationToSource adds a user with a relation to a source.
|
||||||
AddUserWithRelationToSource(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDomain string, userID string, username string) error
|
AddUserWithRelationToSource(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDomain string, userID string, username string) error
|
||||||
|
|
||||||
|
// AddSource adds a new source to the database.
|
||||||
AddSource(ctx context.Context, anthroveSource *models.Source) error
|
AddSource(ctx context.Context, anthroveSource *models.Source) error
|
||||||
|
|
||||||
|
// AddPost adds a new post to the database.
|
||||||
AddPost(ctx context.Context, anthrovePost *models.Post) error
|
AddPost(ctx context.Context, anthrovePost *models.Post) error
|
||||||
|
|
||||||
|
// AddTagWithRelationToPost adds a tag with a relation to a post.
|
||||||
AddTagWithRelationToPost(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveTag *models.Tag) error
|
AddTagWithRelationToPost(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveTag *models.Tag) error
|
||||||
|
|
||||||
|
// LinkPostWithSource links a post with a source.
|
||||||
LinkPostWithSource(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveSourceDomain string, anthrovePostRelationship *models.PostReference) error
|
LinkPostWithSource(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveSourceDomain string, anthrovePostRelationship *models.PostReference) error
|
||||||
|
|
||||||
|
// LinkUserWithPost links a user with a post.
|
||||||
LinkUserWithPost(ctx context.Context, anthroveUser *models.User, anthrovePost *models.Post) error
|
LinkUserWithPost(ctx context.Context, anthroveUser *models.User, anthrovePost *models.Post) error
|
||||||
|
|
||||||
|
// CheckUserPostLink checks if a user-post link exists.
|
||||||
CheckUserPostLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourcePostID string, sourceUrl string) (bool, error)
|
CheckUserPostLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourcePostID string, sourceUrl string) (bool, error)
|
||||||
|
|
||||||
|
// GetPostByAnthroveID retrieves a post by its Anthrove ID.
|
||||||
GetPostByAnthroveID(ctx context.Context, anthrovePost *models.Post) (*models.Post, error)
|
GetPostByAnthroveID(ctx context.Context, anthrovePost *models.Post) (*models.Post, error)
|
||||||
|
|
||||||
|
// GetPostBySourceURL retrieves a post by its source URL.
|
||||||
GetPostBySourceURL(ctx context.Context, sourceUrl string) (*models.Post, error)
|
GetPostBySourceURL(ctx context.Context, sourceUrl string) (*models.Post, error)
|
||||||
|
|
||||||
|
// GetPostBySourceID retrieves a post by its source ID.
|
||||||
GetPostBySourceID(ctx context.Context, sourcePostID string) (*models.Post, error)
|
GetPostBySourceID(ctx context.Context, sourcePostID string) (*models.Post, error)
|
||||||
|
|
||||||
|
// GetUserFavoriteCount retrieves the count of a user's favorites.
|
||||||
GetUserFavoriteCount(ctx context.Context, anthroveUserID models.AnthroveUserID) (int64, error)
|
GetUserFavoriteCount(ctx context.Context, anthroveUserID models.AnthroveUserID) (int64, error)
|
||||||
|
|
||||||
|
// GetUserSourceLinks retrieves the source links of a user.
|
||||||
GetUserSourceLinks(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error)
|
GetUserSourceLinks(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error)
|
||||||
|
|
||||||
|
// GetSpecifiedUserSourceLink retrieves a specified source link of a user.
|
||||||
GetSpecifiedUserSourceLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]models.UserSource, error)
|
GetSpecifiedUserSourceLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]models.UserSource, error)
|
||||||
|
|
||||||
GetAnthroveUser(ctx context.Context, anthroveUserID models.AnthroveUserID) (*models.User, error)
|
// GetAllAnthroveUserIDs retrieves all Anthrove user IDs.
|
||||||
|
|
||||||
GetAllAnthroveUserIDs(ctx context.Context) ([]models.AnthroveUserID, error)
|
GetAllAnthroveUserIDs(ctx context.Context) ([]models.AnthroveUserID, error)
|
||||||
|
|
||||||
|
// GetUserFavoritePostsWithPagination retrieves a user's favorite posts with pagination.
|
||||||
GetUserFavoritePostsWithPagination(ctx context.Context, anthroveUserID models.AnthroveUserID, skip int, limit int) (*models.FavoriteList, error)
|
GetUserFavoritePostsWithPagination(ctx context.Context, anthroveUserID models.AnthroveUserID, skip int, limit int) (*models.FavoriteList, error)
|
||||||
|
|
||||||
|
// GetUserTagsTroughFavedPosts retrieves a user's tags through their favorited posts.
|
||||||
GetUserTagsTroughFavedPosts(ctx context.Context, anthroveUserID models.AnthroveUserID) ([]models.TagsWithFrequency, error)
|
GetUserTagsTroughFavedPosts(ctx context.Context, anthroveUserID models.AnthroveUserID) ([]models.TagsWithFrequency, error)
|
||||||
|
|
||||||
|
// GetAllTags retrieves all tags.
|
||||||
GetAllTags(ctx context.Context) ([]models.TagsWithFrequency, error)
|
GetAllTags(ctx context.Context) ([]models.TagsWithFrequency, error)
|
||||||
|
|
||||||
|
// GetAllSources retrieves all sources.
|
||||||
GetAllSources(ctx context.Context) ([]models.Source, error)
|
GetAllSources(ctx context.Context) ([]models.Source, error)
|
||||||
|
|
||||||
|
// GetSourceByURL retrieves a source by its URL.
|
||||||
GetSourceByURL(ctx context.Context, sourceUrl string) (*models.Source, error)
|
GetSourceByURL(ctx context.Context, sourceUrl string) (*models.Source, error)
|
||||||
}
|
}
|
||||||
|
@ -109,17 +109,13 @@ func (p *postgresqlConnection) GetUserFavoriteCount(ctx context.Context, anthrov
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *postgresqlConnection) GetUserSourceLinks(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error) {
|
func (p *postgresqlConnection) GetUserSourceLinks(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error) {
|
||||||
return postgres.GetUserSourceLink(ctx, p.db, anthroveUserID)
|
return postgres.GetUserSourceLinks(ctx, p.db, anthroveUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *postgresqlConnection) GetSpecifiedUserSourceLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]models.UserSource, error) {
|
func (p *postgresqlConnection) GetSpecifiedUserSourceLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]models.UserSource, error) {
|
||||||
return postgres.GetSpecifiedUserSourceLink(ctx, p.db, anthroveUserID, sourceDisplayName)
|
return postgres.GetSpecifiedUserSourceLink(ctx, p.db, anthroveUserID, sourceDisplayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *postgresqlConnection) GetAnthroveUser(ctx context.Context, anthroveUserID models.AnthroveUserID) (*models.User, error) {
|
|
||||||
return postgres.GetAnthroveUser(ctx, p.db, anthroveUserID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *postgresqlConnection) GetAllAnthroveUserIDs(ctx context.Context) ([]models.AnthroveUserID, error) {
|
func (p *postgresqlConnection) GetAllAnthroveUserIDs(ctx context.Context) ([]models.AnthroveUserID, error) {
|
||||||
return postgres.GetAllAnthroveUserIDs(ctx, p.db)
|
return postgres.GetAllAnthroveUserIDs(ctx, p.db)
|
||||||
}
|
}
|
||||||
|
@ -13,5 +13,5 @@ func (UserFavorite) TableName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FavoriteList struct {
|
type FavoriteList struct {
|
||||||
fenpaws marked this conversation as resolved
Outdated
|
|||||||
Posts []UserFavorite `json:"posts,omitempty"`
|
Posts []Post `json:"posts,omitempty"`
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user
I am unsure... what is your opinion about moving specific structs thats are only for SDK Responses to an own file like
api.go
in this package?That makes sense, so we can distinguish it easier