3
0

Ported messaging to new store

This commit is contained in:
Denis Arh
2020-09-01 10:31:18 +02:00
parent 3833f25b89
commit e2c9b96ea9
35 changed files with 2598 additions and 207 deletions

View File

@@ -16,7 +16,7 @@ type (
With(ctx context.Context, db *factory.DB) AttachmentRepository
FindAttachmentByID(id uint64) (*types.Attachment, error)
FindAttachmentByMessageID(IDs ...uint64) (types.MessageAttachmentSet, error)
FindAttachmentByMessageID(IDs ...uint64) (types.AttachmentSet, error)
CreateAttachment(mod *types.Attachment) (*types.Attachment, error)
DeleteAttachmentByID(id uint64) error
@@ -96,8 +96,8 @@ func (r attachment) findOneBy(field string, value interface{}) (*types.Attachmen
return p, nil
}
func (r attachment) FindAttachmentByMessageID(IDs ...uint64) (rval types.MessageAttachmentSet, err error) {
rval = types.MessageAttachmentSet{}
func (r attachment) FindAttachmentByMessageID(IDs ...uint64) (rval types.AttachmentSet, err error) {
rval = types.AttachmentSet{}
if len(IDs) == 0 {
return

View File

@@ -111,9 +111,9 @@ func (r channel) findOneBy(cnd squirrel.Sqlizer) (*types.Channel, error) {
func (r channel) Find(filter types.ChannelFilter) (set types.ChannelSet, f types.ChannelFilter, err error) {
f = filter
if f.Sort == "" {
f.Sort = "c.name ASC"
}
//if f.Sort == "" {
// f.Sort = "c.name ASC"
//}
query := r.query()
@@ -139,13 +139,13 @@ func (r channel) Find(filter types.ChannelFilter) (set types.ChannelSet, f types
})
}
var orderBy []string
if orderBy, err = rh.ParseOrder(f.Sort, r.columns()...); err != nil {
return
} else {
query = query.OrderBy(orderBy...)
}
//var orderBy []string
//
//if orderBy, err = rh.ParseOrder(f.Sort, r.columns()...); err != nil {
// return
//} else {
// query = query.OrderBy(orderBy...)
//}
return set, f, rh.FetchAll(r.db(), query, &set)
}

View File

@@ -126,9 +126,9 @@ func (svc attachment) CreateMessageAttachment(name string, size int64, fh io.Rea
}
att = &types.Attachment{
ID: factory.Sonyflake.NextID(),
UserID: currentUserID,
Name: strings.TrimSpace(name),
ID: factory.Sonyflake.NextID(),
OwnerID: currentUserID,
Name: strings.TrimSpace(name),
}
err = svc.create(name, size, fh, att)

View File

@@ -175,7 +175,7 @@ func (p attachmentActionProps) serialize() actionlog.Meta {
m.Set("attachment.url", p.attachment.Url, true)
m.Set("attachment.previewUrl", p.attachment.PreviewUrl, true)
m.Set("attachment.meta", p.attachment.Meta, true)
m.Set("attachment.userID", p.attachment.UserID, true)
m.Set("attachment.ownerID", p.attachment.OwnerID, true)
m.Set("attachment.ID", p.attachment.ID, true)
}
if p.channel != nil {
@@ -239,7 +239,7 @@ func (p attachmentActionProps) tr(in string, err error) string {
p.attachment.Url,
p.attachment.PreviewUrl,
p.attachment.Meta,
p.attachment.UserID,
p.attachment.OwnerID,
p.attachment.ID,
),
)
@@ -247,7 +247,7 @@ func (p attachmentActionProps) tr(in string, err error) string {
pairs = append(pairs, "{attachment.url}", fns(p.attachment.Url))
pairs = append(pairs, "{attachment.previewUrl}", fns(p.attachment.PreviewUrl))
pairs = append(pairs, "{attachment.meta}", fns(p.attachment.Meta))
pairs = append(pairs, "{attachment.userID}", fns(p.attachment.UserID))
pairs = append(pairs, "{attachment.ownerID}", fns(p.attachment.OwnerID))
pairs = append(pairs, "{attachment.ID}", fns(p.attachment.ID))
}

View File

@@ -24,7 +24,7 @@ props:
- name: url
- name: attachment
type: "*types.Attachment"
fields: [ name, url, previewUrl, meta, userID, ID ]
fields: [ name, url, previewUrl, meta, ownerID, ID ]
- name: channel
type: "*types.Channel"
fields: [ name, topic, type, ID ]

View File

@@ -655,7 +655,7 @@ func (svc message) preloadMentions(mm types.MessageSet) (err error) {
func (svc message) preloadAttachments(mm types.MessageSet) (err error) {
var (
ids []uint64
aa types.MessageAttachmentSet
aa types.AttachmentSet
)
err = mm.Walk(func(m *types.Message) error {
@@ -672,15 +672,17 @@ func (svc message) preloadAttachments(mm types.MessageSet) (err error) {
if aa, err = svc.attachment.FindAttachmentByMessageID(ids...); err != nil {
return
} else {
return aa.Walk(func(a *types.MessageAttachment) error {
if a.MessageID > 0 {
if m := mm.FindByID(a.MessageID); m != nil {
m.Attachment = &a.Attachment
}
}
return nil
})
_ = aa
//return aa.Walk(func(a *types.Attachment) error {
// if a.MessageID > 0 {
// if m := mm.FindByID(a.MessageID); m != nil {
// m.Attachment = &a.Attachment
// }
// }
//
// return nil
//})
return
}
}

View File

@@ -10,15 +10,28 @@ import (
type (
Attachment struct {
ID uint64 `db:"id" json:"ID,omitempty"`
UserID uint64 `db:"rel_user" json:"userID,omitempty"`
Url string `db:"url" json:"url,omitempty"`
PreviewUrl string `db:"preview_url"json:"previewUrl,omitempty"`
Name string `db:"name" json:"name,omitempty"`
Meta attachmentMeta `db:"meta" json:"meta"`
CreatedAt time.Time `db:"created_at" json:"createdAt,omitempty"`
UpdatedAt *time.Time `db:"updated_at" json:"updatedAt,omitempty"`
DeletedAt *time.Time `db:"deleted_at" json:"deletedAt,omitempty"`
ID uint64 `json:"ID,omitempty"`
OwnerID uint64 `json:"userID,omitempty"`
Url string `json:"url,omitempty"`
PreviewUrl string `json:"previewUrl,omitempty"`
Name string `json:"name,omitempty"`
Meta attachmentMeta `json:"meta"`
CreatedAt time.Time `json:"createdAt,omitempty"`
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
DeletedAt *time.Time `json:"deletedAt,omitempty"`
MessageID uint64 `json:"-"`
}
// AttachmentFilter is used for filtering and as a return value from Find
AttachmentFilter struct {
MessageID []uint64
// Check fn is called by store backend for each resource found function can
// modify the resource and return false if store should not return it
//
// Store then loads additional resources to satisfy the paging parameters
Check func(*Attachment) (bool, error)
}
attachmentImageMeta struct {
@@ -38,11 +51,6 @@ type (
Original attachmentFileMeta `json:"original"`
Preview *attachmentFileMeta `json:"preview,omitempty"`
}
MessageAttachment struct {
Attachment
MessageID uint64 `db:"rel_message" json:"-"`
}
)
func (a *Attachment) SetOriginalImageMeta(width, height int, animated bool) *attachmentFileMeta {

View File

@@ -1,6 +1,8 @@
package types
import (
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/rh"
"time"
"github.com/jmoiron/sqlx/types"
@@ -59,9 +61,20 @@ type (
CurrentUserID uint64
// Do not filter out deleted channels
// @deprecated
IncludeDeleted bool
Sort string `json:"sort"`
Deleted rh.FilterState `json:"deleted"`
// Check fn is called by store backend for each resource found function can
// modify the resource and return false if store should not return it
//
// Store then loads additional resources to satisfy the paging parameters
Check func(channel *Channel) (bool, error) `json:"-"`
// Standard helpers for paging and sorting
filter.Sorting
filter.Paging
}
ChannelMembershipPolicy string

View File

@@ -10,7 +10,7 @@ func TestMentionSet_Diff(t *testing.T) {
ex := MentionSet{&Mention{ID: 1000}, &Mention{ID: 1001}}
add, upd, del := ex.Diff(MentionSet{&Mention{ID: 1001}, &Mention{UserID: 1}})
require.True(t, len(add) == 1 && len(add.FindByUserID(1)) == 1, "Did not find expected mention (UserID:1) for creation")
require.True(t, len(add) == 1 && len(add.FindByUserID(1)) == 1, "Did not find expected mention (OwnerID:1) for creation")
require.True(t, len(upd) == 1 && upd.FindByID(1001) != nil, "Did not find expected mention (id:1001) for update")
require.True(t, len(del) == 1 && del.FindByID(1000) != nil, "Did not find expected mention (id:1000) for removal")
}

View File

@@ -10,6 +10,11 @@ package types
type (
// AttachmentSet slice of Attachment
//
// This type is auto-generated.
AttachmentSet []*Attachment
// ChannelSet slice of Channel
//
// This type is auto-generated.
@@ -40,11 +45,6 @@ type (
// This type is auto-generated.
MessageSet []*Message
// MessageAttachmentSet slice of MessageAttachment
//
// This type is auto-generated.
MessageAttachmentSet []*MessageAttachment
// MessageFlagSet slice of MessageFlag
//
// This type is auto-generated.
@@ -56,6 +56,62 @@ type (
UnreadSet []*Unread
)
// Walk iterates through every slice item and calls w(Attachment) err
//
// This function is auto-generated.
func (set AttachmentSet) Walk(w func(*Attachment) error) (err error) {
for i := range set {
if err = w(set[i]); err != nil {
return
}
}
return
}
// Filter iterates through every slice item, calls f(Attachment) (bool, err) and return filtered slice
//
// This function is auto-generated.
func (set AttachmentSet) Filter(f func(*Attachment) (bool, error)) (out AttachmentSet, err error) {
var ok bool
out = AttachmentSet{}
for i := range set {
if ok, err = f(set[i]); err != nil {
return
} else if ok {
out = append(out, set[i])
}
}
return
}
// FindByID finds items from slice by its ID property
//
// This function is auto-generated.
func (set AttachmentSet) FindByID(ID uint64) *Attachment {
for i := range set {
if set[i].ID == ID {
return set[i]
}
}
return nil
}
// IDs returns a slice of uint64s from all items in the set
//
// This function is auto-generated.
func (set AttachmentSet) IDs() (IDs []uint64) {
IDs = make([]uint64, len(set))
for i := range set {
IDs[i] = set[i].ID
}
return
}
// Walk iterates through every slice item and calls w(Channel) err
//
// This function is auto-generated.
@@ -314,62 +370,6 @@ func (set MessageSet) IDs() (IDs []uint64) {
return
}
// Walk iterates through every slice item and calls w(MessageAttachment) err
//
// This function is auto-generated.
func (set MessageAttachmentSet) Walk(w func(*MessageAttachment) error) (err error) {
for i := range set {
if err = w(set[i]); err != nil {
return
}
}
return
}
// Filter iterates through every slice item, calls f(MessageAttachment) (bool, err) and return filtered slice
//
// This function is auto-generated.
func (set MessageAttachmentSet) Filter(f func(*MessageAttachment) (bool, error)) (out MessageAttachmentSet, err error) {
var ok bool
out = MessageAttachmentSet{}
for i := range set {
if ok, err = f(set[i]); err != nil {
return
} else if ok {
out = append(out, set[i])
}
}
return
}
// FindByID finds items from slice by its ID property
//
// This function is auto-generated.
func (set MessageAttachmentSet) FindByID(ID uint64) *MessageAttachment {
for i := range set {
if set[i].ID == ID {
return set[i]
}
}
return nil
}
// IDs returns a slice of uint64s from all items in the set
//
// This function is auto-generated.
func (set MessageAttachmentSet) IDs() (IDs []uint64) {
IDs = make([]uint64, len(set))
for i := range set {
IDs[i] = set[i].ID
}
return
}
// Walk iterates through every slice item and calls w(MessageFlag) err
//
// This function is auto-generated.

View File

@@ -14,6 +14,96 @@ import (
"testing"
)
func TestAttachmentSetWalk(t *testing.T) {
var (
value = make(AttachmentSet, 3)
req = require.New(t)
)
// check walk with no errors
{
err := value.Walk(func(*Attachment) error {
return nil
})
req.NoError(err)
}
// check walk with error
req.Error(value.Walk(func(*Attachment) error { return fmt.Errorf("walk error") }))
}
func TestAttachmentSetFilter(t *testing.T) {
var (
value = make(AttachmentSet, 3)
req = require.New(t)
)
// filter nothing
{
set, err := value.Filter(func(*Attachment) (bool, error) {
return true, nil
})
req.NoError(err)
req.Equal(len(set), len(value))
}
// filter one item
{
found := false
set, err := value.Filter(func(*Attachment) (bool, error) {
if !found {
found = true
return found, nil
}
return false, nil
})
req.NoError(err)
req.Len(set, 1)
}
// filter error
{
_, err := value.Filter(func(*Attachment) (bool, error) {
return false, fmt.Errorf("filter error")
})
req.Error(err)
}
}
func TestAttachmentSetIDs(t *testing.T) {
var (
value = make(AttachmentSet, 3)
req = require.New(t)
)
// construct objects
value[0] = new(Attachment)
value[1] = new(Attachment)
value[2] = new(Attachment)
// set ids
value[0].ID = 1
value[1].ID = 2
value[2].ID = 3
// Find existing
{
val := value.FindByID(2)
req.Equal(uint64(2), val.ID)
}
// Find non-existing
{
val := value.FindByID(4)
req.Nil(val)
}
// List IDs from set
{
val := value.IDs()
req.Equal(len(val), len(value))
}
}
func TestChannelSetWalk(t *testing.T) {
var (
value = make(ChannelSet, 3)
@@ -452,96 +542,6 @@ func TestMessageSetIDs(t *testing.T) {
}
}
func TestMessageAttachmentSetWalk(t *testing.T) {
var (
value = make(MessageAttachmentSet, 3)
req = require.New(t)
)
// check walk with no errors
{
err := value.Walk(func(*MessageAttachment) error {
return nil
})
req.NoError(err)
}
// check walk with error
req.Error(value.Walk(func(*MessageAttachment) error { return fmt.Errorf("walk error") }))
}
func TestMessageAttachmentSetFilter(t *testing.T) {
var (
value = make(MessageAttachmentSet, 3)
req = require.New(t)
)
// filter nothing
{
set, err := value.Filter(func(*MessageAttachment) (bool, error) {
return true, nil
})
req.NoError(err)
req.Equal(len(set), len(value))
}
// filter one item
{
found := false
set, err := value.Filter(func(*MessageAttachment) (bool, error) {
if !found {
found = true
return found, nil
}
return false, nil
})
req.NoError(err)
req.Len(set, 1)
}
// filter error
{
_, err := value.Filter(func(*MessageAttachment) (bool, error) {
return false, fmt.Errorf("filter error")
})
req.Error(err)
}
}
func TestMessageAttachmentSetIDs(t *testing.T) {
var (
value = make(MessageAttachmentSet, 3)
req = require.New(t)
)
// construct objects
value[0] = new(MessageAttachment)
value[1] = new(MessageAttachment)
value[2] = new(MessageAttachment)
// set ids
value[0].ID = 1
value[1].ID = 2
value[2].ID = 3
// Find existing
{
val := value.FindByID(2)
req.Equal(uint64(2), val.ID)
}
// Find non-existing
{
val := value.FindByID(4)
req.Nil(val)
}
// List IDs from set
{
val := value.IDs()
req.Equal(len(val), len(value))
}
}
func TestMessageFlagSetWalk(t *testing.T) {
var (
value = make(MessageFlagSet, 3)

View File

@@ -1,5 +1,5 @@
types:
MessageAttachment:
Attachment:
Mention:
MessageFlag:
Message:

View File

@@ -222,7 +222,7 @@ func Import(ctx context.Context, iss []types.ImportSource, ns *cct.Namespace, cf
rr.Walk(func(r *cct.Record) error {
vr := r.Values.Get("sys_legacy_ref_id", 0)
vu := r.Values.Get("UserID", 0)
vu := r.Values.Get("OwnerID", 0)
u, err := strconv.ParseUint(vu.Value, 10, 64)
if err != nil {
return err

View File

@@ -281,7 +281,7 @@ func Attachment(in *messagingTypes.Attachment, userID uint64) *outgoing.Attachme
return &outgoing.Attachment{
ID: Uint64toa(in.ID),
UserID: Uint64toa(in.UserID),
UserID: Uint64toa(in.OwnerID),
Url: fmt.Sprintf(attachmentURL, in.ID, url.PathEscape(in.Name)) + signParams,
PreviewUrl: preview + signParams,
Meta: in.Meta,

View File

@@ -16,6 +16,11 @@ package store
// - store/compose_record_values.yaml
// - store/compose_records.yaml
// - store/credentials.yaml
// - store/messaging_attachments.yaml
// - store/messaging_channel_members.yaml
// - store/messaging_channels.yaml
// - store/messaging_messages.yaml
// - store/messaging_unread.yaml
// - store/rbac_rules.yaml
// - store/reminders.yaml
// - store/role_members.yaml
@@ -52,6 +57,11 @@ type (
ComposeRecordValues
ComposeRecords
Credentials
MessagingAttachments
MessagingChannelMembers
MessagingChannels
MessagingMessages
MessagingUnreads
RbacRules
Reminders
RoleMembers

View File

@@ -0,0 +1,83 @@
package store
// This file is auto-generated.
//
// Template: pkg/codegen/assets/store_base.gen.go.tpl
// Definitions: store/messaging_attachments.yaml
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
import (
"context"
"github.com/cortezaproject/corteza-server/messaging/types"
)
type (
MessagingAttachments interface {
SearchMessagingAttachments(ctx context.Context, f types.AttachmentFilter) (types.AttachmentSet, types.AttachmentFilter, error)
LookupMessagingAttachmentByID(ctx context.Context, id uint64) (*types.Attachment, error)
CreateMessagingAttachment(ctx context.Context, rr ...*types.Attachment) error
UpdateMessagingAttachment(ctx context.Context, rr ...*types.Attachment) error
PartialMessagingAttachmentUpdate(ctx context.Context, onlyColumns []string, rr ...*types.Attachment) error
UpsertMessagingAttachment(ctx context.Context, rr ...*types.Attachment) error
DeleteMessagingAttachment(ctx context.Context, rr ...*types.Attachment) error
DeleteMessagingAttachmentByID(ctx context.Context, ID uint64) error
TruncateMessagingAttachments(ctx context.Context) error
}
)
var _ *types.Attachment
var _ context.Context
// SearchMessagingAttachments returns all matching MessagingAttachments from store
func SearchMessagingAttachments(ctx context.Context, s MessagingAttachments, f types.AttachmentFilter) (types.AttachmentSet, types.AttachmentFilter, error) {
return s.SearchMessagingAttachments(ctx, f)
}
// LookupMessagingAttachmentByID searches for attachment by its ID
//
// It returns attachment even if deleted
func LookupMessagingAttachmentByID(ctx context.Context, s MessagingAttachments, id uint64) (*types.Attachment, error) {
return s.LookupMessagingAttachmentByID(ctx, id)
}
// CreateMessagingAttachment creates one or more MessagingAttachments in store
func CreateMessagingAttachment(ctx context.Context, s MessagingAttachments, rr ...*types.Attachment) error {
return s.CreateMessagingAttachment(ctx, rr...)
}
// UpdateMessagingAttachment updates one or more (existing) MessagingAttachments in store
func UpdateMessagingAttachment(ctx context.Context, s MessagingAttachments, rr ...*types.Attachment) error {
return s.UpdateMessagingAttachment(ctx, rr...)
}
// PartialMessagingAttachmentUpdate updates one or more existing MessagingAttachments in store
func PartialMessagingAttachmentUpdate(ctx context.Context, s MessagingAttachments, onlyColumns []string, rr ...*types.Attachment) error {
return s.PartialMessagingAttachmentUpdate(ctx, onlyColumns, rr...)
}
// UpsertMessagingAttachment creates new or updates existing one or more MessagingAttachments in store
func UpsertMessagingAttachment(ctx context.Context, s MessagingAttachments, rr ...*types.Attachment) error {
return s.UpsertMessagingAttachment(ctx, rr...)
}
// DeleteMessagingAttachment Deletes one or more MessagingAttachments from store
func DeleteMessagingAttachment(ctx context.Context, s MessagingAttachments, rr ...*types.Attachment) error {
return s.DeleteMessagingAttachment(ctx, rr...)
}
// DeleteMessagingAttachmentByID Deletes MessagingAttachment from store
func DeleteMessagingAttachmentByID(ctx context.Context, s MessagingAttachments, ID uint64) error {
return s.DeleteMessagingAttachmentByID(ctx, ID)
}
// TruncateMessagingAttachments Deletes all MessagingAttachments from store
func TruncateMessagingAttachments(ctx context.Context, s MessagingAttachments) error {
return s.TruncateMessagingAttachments(ctx)
}

View File

@@ -0,0 +1,32 @@
import:
- github.com/cortezaproject/corteza-server/messaging/types
types:
type: types.Attachment
fields:
- { field: ID }
- { field: Url }
- { field: PreviewUrl }
- { field: Name }
- { field: Meta }
- { field: OwnerID }
- { field: CreatedAt }
- { field: UpdatedAt }
- { field: DeletedAt }
lookups:
- fields: [ ID ]
description: |-
searches for attachment by its ID
It returns attachment even if deleted
search:
enableSorting: false
enablePaging: false
rdbms:
alias: att
table: messaging_attachment
customFilterConverter: true

View File

@@ -0,0 +1,75 @@
package store
// This file is auto-generated.
//
// Template: pkg/codegen/assets/store_base.gen.go.tpl
// Definitions: store/messaging_channel_members.yaml
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
import (
"context"
"github.com/cortezaproject/corteza-server/messaging/types"
)
type (
MessagingChannelMembers interface {
SearchMessagingChannelMembers(ctx context.Context, f types.ChannelMemberFilter) (types.ChannelMemberSet, types.ChannelMemberFilter, error)
CreateMessagingChannelMember(ctx context.Context, rr ...*types.ChannelMember) error
UpdateMessagingChannelMember(ctx context.Context, rr ...*types.ChannelMember) error
PartialMessagingChannelMemberUpdate(ctx context.Context, onlyColumns []string, rr ...*types.ChannelMember) error
UpsertMessagingChannelMember(ctx context.Context, rr ...*types.ChannelMember) error
DeleteMessagingChannelMember(ctx context.Context, rr ...*types.ChannelMember) error
DeleteMessagingChannelMemberByChannelIDUserID(ctx context.Context, channelID uint64, userID uint64) error
TruncateMessagingChannelMembers(ctx context.Context) error
}
)
var _ *types.ChannelMember
var _ context.Context
// SearchMessagingChannelMembers returns all matching MessagingChannelMembers from store
func SearchMessagingChannelMembers(ctx context.Context, s MessagingChannelMembers, f types.ChannelMemberFilter) (types.ChannelMemberSet, types.ChannelMemberFilter, error) {
return s.SearchMessagingChannelMembers(ctx, f)
}
// CreateMessagingChannelMember creates one or more MessagingChannelMembers in store
func CreateMessagingChannelMember(ctx context.Context, s MessagingChannelMembers, rr ...*types.ChannelMember) error {
return s.CreateMessagingChannelMember(ctx, rr...)
}
// UpdateMessagingChannelMember updates one or more (existing) MessagingChannelMembers in store
func UpdateMessagingChannelMember(ctx context.Context, s MessagingChannelMembers, rr ...*types.ChannelMember) error {
return s.UpdateMessagingChannelMember(ctx, rr...)
}
// PartialMessagingChannelMemberUpdate updates one or more existing MessagingChannelMembers in store
func PartialMessagingChannelMemberUpdate(ctx context.Context, s MessagingChannelMembers, onlyColumns []string, rr ...*types.ChannelMember) error {
return s.PartialMessagingChannelMemberUpdate(ctx, onlyColumns, rr...)
}
// UpsertMessagingChannelMember creates new or updates existing one or more MessagingChannelMembers in store
func UpsertMessagingChannelMember(ctx context.Context, s MessagingChannelMembers, rr ...*types.ChannelMember) error {
return s.UpsertMessagingChannelMember(ctx, rr...)
}
// DeleteMessagingChannelMember Deletes one or more MessagingChannelMembers from store
func DeleteMessagingChannelMember(ctx context.Context, s MessagingChannelMembers, rr ...*types.ChannelMember) error {
return s.DeleteMessagingChannelMember(ctx, rr...)
}
// DeleteMessagingChannelMemberByChannelIDUserID Deletes MessagingChannelMember from store
func DeleteMessagingChannelMemberByChannelIDUserID(ctx context.Context, s MessagingChannelMembers, channelID uint64, userID uint64) error {
return s.DeleteMessagingChannelMemberByChannelIDUserID(ctx, channelID, userID)
}
// TruncateMessagingChannelMembers Deletes all MessagingChannelMembers from store
func TruncateMessagingChannelMembers(ctx context.Context, s MessagingChannelMembers) error {
return s.TruncateMessagingChannelMembers(ctx)
}

View File

@@ -0,0 +1,22 @@
import:
- github.com/cortezaproject/corteza-server/messaging/types
types:
type: types.ChannelMember
fields:
- { field: ChannelID, isPrimaryKey: true }
- { field: UserID, isPrimaryKey: true }
- { field: Type }
- { field: Flag }
- { field: CreatedAt }
- { field: UpdatedAt }
rdbms:
alias: mcm
table: messaging_channel_member
search:
enableSorting: false
enablePaging: false
enableFilterCheckFunction: false

View File

@@ -0,0 +1,83 @@
package store
// This file is auto-generated.
//
// Template: pkg/codegen/assets/store_base.gen.go.tpl
// Definitions: store/messaging_channels.yaml
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
import (
"context"
"github.com/cortezaproject/corteza-server/messaging/types"
)
type (
MessagingChannels interface {
SearchMessagingChannels(ctx context.Context, f types.ChannelFilter) (types.ChannelSet, types.ChannelFilter, error)
LookupMessagingChannelByID(ctx context.Context, id uint64) (*types.Channel, error)
CreateMessagingChannel(ctx context.Context, rr ...*types.Channel) error
UpdateMessagingChannel(ctx context.Context, rr ...*types.Channel) error
PartialMessagingChannelUpdate(ctx context.Context, onlyColumns []string, rr ...*types.Channel) error
UpsertMessagingChannel(ctx context.Context, rr ...*types.Channel) error
DeleteMessagingChannel(ctx context.Context, rr ...*types.Channel) error
DeleteMessagingChannelByID(ctx context.Context, ID uint64) error
TruncateMessagingChannels(ctx context.Context) error
}
)
var _ *types.Channel
var _ context.Context
// SearchMessagingChannels returns all matching MessagingChannels from store
func SearchMessagingChannels(ctx context.Context, s MessagingChannels, f types.ChannelFilter) (types.ChannelSet, types.ChannelFilter, error) {
return s.SearchMessagingChannels(ctx, f)
}
// LookupMessagingChannelByID searches for attachment by its ID
//
// It returns attachment even if deleted
func LookupMessagingChannelByID(ctx context.Context, s MessagingChannels, id uint64) (*types.Channel, error) {
return s.LookupMessagingChannelByID(ctx, id)
}
// CreateMessagingChannel creates one or more MessagingChannels in store
func CreateMessagingChannel(ctx context.Context, s MessagingChannels, rr ...*types.Channel) error {
return s.CreateMessagingChannel(ctx, rr...)
}
// UpdateMessagingChannel updates one or more (existing) MessagingChannels in store
func UpdateMessagingChannel(ctx context.Context, s MessagingChannels, rr ...*types.Channel) error {
return s.UpdateMessagingChannel(ctx, rr...)
}
// PartialMessagingChannelUpdate updates one or more existing MessagingChannels in store
func PartialMessagingChannelUpdate(ctx context.Context, s MessagingChannels, onlyColumns []string, rr ...*types.Channel) error {
return s.PartialMessagingChannelUpdate(ctx, onlyColumns, rr...)
}
// UpsertMessagingChannel creates new or updates existing one or more MessagingChannels in store
func UpsertMessagingChannel(ctx context.Context, s MessagingChannels, rr ...*types.Channel) error {
return s.UpsertMessagingChannel(ctx, rr...)
}
// DeleteMessagingChannel Deletes one or more MessagingChannels from store
func DeleteMessagingChannel(ctx context.Context, s MessagingChannels, rr ...*types.Channel) error {
return s.DeleteMessagingChannel(ctx, rr...)
}
// DeleteMessagingChannelByID Deletes MessagingChannel from store
func DeleteMessagingChannelByID(ctx context.Context, s MessagingChannels, ID uint64) error {
return s.DeleteMessagingChannelByID(ctx, ID)
}
// TruncateMessagingChannels Deletes all MessagingChannels from store
func TruncateMessagingChannels(ctx context.Context, s MessagingChannels) error {
return s.TruncateMessagingChannels(ctx)
}

View File

@@ -0,0 +1,32 @@
import:
- github.com/cortezaproject/corteza-server/messaging/types
types:
type: types.Channel
fields:
- { field: ID }
- { field: Name }
- { field: Topic }
- { field: Type }
- { field: Meta }
- { field: MembershipPolicy }
- { field: CreatorID }
- { field: OrganisationID }
- { field: CreatedAt }
- { field: UpdatedAt }
- { field: ArchivedAt }
- { field: DeletedAt }
- { field: LastMessageID }
lookups:
- fields: [ ID ]
description: |-
searches for attachment by its ID
It returns attachment even if deleted
rdbms:
alias: mch
table: messaging_channel

View File

@@ -0,0 +1,83 @@
package store
// This file is auto-generated.
//
// Template: pkg/codegen/assets/store_base.gen.go.tpl
// Definitions: store/messaging_messages.yaml
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
import (
"context"
"github.com/cortezaproject/corteza-server/messaging/types"
)
type (
MessagingMessages interface {
SearchMessagingMessages(ctx context.Context, f types.MessageFilter) (types.MessageSet, types.MessageFilter, error)
LookupMessagingMessageByID(ctx context.Context, id uint64) (*types.Message, error)
CreateMessagingMessage(ctx context.Context, rr ...*types.Message) error
UpdateMessagingMessage(ctx context.Context, rr ...*types.Message) error
PartialMessagingMessageUpdate(ctx context.Context, onlyColumns []string, rr ...*types.Message) error
UpsertMessagingMessage(ctx context.Context, rr ...*types.Message) error
DeleteMessagingMessage(ctx context.Context, rr ...*types.Message) error
DeleteMessagingMessageByID(ctx context.Context, ID uint64) error
TruncateMessagingMessages(ctx context.Context) error
}
)
var _ *types.Message
var _ context.Context
// SearchMessagingMessages returns all matching MessagingMessages from store
func SearchMessagingMessages(ctx context.Context, s MessagingMessages, f types.MessageFilter) (types.MessageSet, types.MessageFilter, error) {
return s.SearchMessagingMessages(ctx, f)
}
// LookupMessagingMessageByID searches for attachment by its ID
//
// It returns attachment even if deleted
func LookupMessagingMessageByID(ctx context.Context, s MessagingMessages, id uint64) (*types.Message, error) {
return s.LookupMessagingMessageByID(ctx, id)
}
// CreateMessagingMessage creates one or more MessagingMessages in store
func CreateMessagingMessage(ctx context.Context, s MessagingMessages, rr ...*types.Message) error {
return s.CreateMessagingMessage(ctx, rr...)
}
// UpdateMessagingMessage updates one or more (existing) MessagingMessages in store
func UpdateMessagingMessage(ctx context.Context, s MessagingMessages, rr ...*types.Message) error {
return s.UpdateMessagingMessage(ctx, rr...)
}
// PartialMessagingMessageUpdate updates one or more existing MessagingMessages in store
func PartialMessagingMessageUpdate(ctx context.Context, s MessagingMessages, onlyColumns []string, rr ...*types.Message) error {
return s.PartialMessagingMessageUpdate(ctx, onlyColumns, rr...)
}
// UpsertMessagingMessage creates new or updates existing one or more MessagingMessages in store
func UpsertMessagingMessage(ctx context.Context, s MessagingMessages, rr ...*types.Message) error {
return s.UpsertMessagingMessage(ctx, rr...)
}
// DeleteMessagingMessage Deletes one or more MessagingMessages from store
func DeleteMessagingMessage(ctx context.Context, s MessagingMessages, rr ...*types.Message) error {
return s.DeleteMessagingMessage(ctx, rr...)
}
// DeleteMessagingMessageByID Deletes MessagingMessage from store
func DeleteMessagingMessageByID(ctx context.Context, s MessagingMessages, ID uint64) error {
return s.DeleteMessagingMessageByID(ctx, ID)
}
// TruncateMessagingMessages Deletes all MessagingMessages from store
func TruncateMessagingMessages(ctx context.Context, s MessagingMessages) error {
return s.TruncateMessagingMessages(ctx)
}

View File

@@ -0,0 +1,34 @@
import:
- github.com/cortezaproject/corteza-server/messaging/types
types:
type: types.Message
fields:
- { field: ID }
- { field: Type }
- { field: Message }
- { field: Meta }
- { field: UserID }
- { field: ChannelID }
- { field: ReplyTo }
- { field: Replies }
- { field: CreatedAt }
- { field: UpdatedAt }
- { field: DeletedAt }
lookups:
- fields: [ ID ]
description: |-
searches for attachment by its ID
It returns attachment even if deleted
rdbms:
alias: msg
table: messaging_messages
search:
enablePaging: false
enableSorting: false
enableFilterCheckFunction: false

View File

@@ -0,0 +1,68 @@
package store
// This file is auto-generated.
//
// Template: pkg/codegen/assets/store_base.gen.go.tpl
// Definitions: store/messaging_unread.yaml
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
import (
"context"
"github.com/cortezaproject/corteza-server/messaging/types"
)
type (
MessagingUnreads interface {
CreateMessagingUnread(ctx context.Context, rr ...*types.Unread) error
UpdateMessagingUnread(ctx context.Context, rr ...*types.Unread) error
PartialMessagingUnreadUpdate(ctx context.Context, onlyColumns []string, rr ...*types.Unread) error
UpsertMessagingUnread(ctx context.Context, rr ...*types.Unread) error
DeleteMessagingUnread(ctx context.Context, rr ...*types.Unread) error
DeleteMessagingUnreadByChannelIDReplyToUserID(ctx context.Context, channelID uint64, replyTo uint64, userID uint64) error
TruncateMessagingUnreads(ctx context.Context) error
}
)
var _ *types.Unread
var _ context.Context
// CreateMessagingUnread creates one or more MessagingUnreads in store
func CreateMessagingUnread(ctx context.Context, s MessagingUnreads, rr ...*types.Unread) error {
return s.CreateMessagingUnread(ctx, rr...)
}
// UpdateMessagingUnread updates one or more (existing) MessagingUnreads in store
func UpdateMessagingUnread(ctx context.Context, s MessagingUnreads, rr ...*types.Unread) error {
return s.UpdateMessagingUnread(ctx, rr...)
}
// PartialMessagingUnreadUpdate updates one or more existing MessagingUnreads in store
func PartialMessagingUnreadUpdate(ctx context.Context, s MessagingUnreads, onlyColumns []string, rr ...*types.Unread) error {
return s.PartialMessagingUnreadUpdate(ctx, onlyColumns, rr...)
}
// UpsertMessagingUnread creates new or updates existing one or more MessagingUnreads in store
func UpsertMessagingUnread(ctx context.Context, s MessagingUnreads, rr ...*types.Unread) error {
return s.UpsertMessagingUnread(ctx, rr...)
}
// DeleteMessagingUnread Deletes one or more MessagingUnreads from store
func DeleteMessagingUnread(ctx context.Context, s MessagingUnreads, rr ...*types.Unread) error {
return s.DeleteMessagingUnread(ctx, rr...)
}
// DeleteMessagingUnreadByChannelIDReplyToUserID Deletes MessagingUnread from store
func DeleteMessagingUnreadByChannelIDReplyToUserID(ctx context.Context, s MessagingUnreads, channelID uint64, replyTo uint64, userID uint64) error {
return s.DeleteMessagingUnreadByChannelIDReplyToUserID(ctx, channelID, replyTo, userID)
}
// TruncateMessagingUnreads Deletes all MessagingUnreads from store
func TruncateMessagingUnreads(ctx context.Context, s MessagingUnreads) error {
return s.TruncateMessagingUnreads(ctx)
}

View File

@@ -0,0 +1,19 @@
import:
- github.com/cortezaproject/corteza-server/messaging/types
types:
type: types.Unread
fields:
- { field: ChannelID, type: uint64, isPrimaryKey: true }
- { field: ReplyTo, type: uint64, isPrimaryKey: true }
- { field: UserID, type: uint64, isPrimaryKey: true }
- { field: LastMessageID, type: uint64 }
- { field: Count, type: uint32 }
rdbms:
alias: mur
table: messaging_unread
search:
enable: false

View File

@@ -64,6 +64,10 @@ func (g genericUpgrades) Upgrade(ctx context.Context, t *ddl.Table) error {
g.AlterUsersDropOrganisation,
g.AlterUsersDropRelatedUser,
)
case "messaging_attachment":
return g.all(ctx,
g.AlterMessageAttachmentsRenameOwner,
)
//case "compose_attachment_binds":
// return g.all(ctx,
// g.MigrateComposeAttachmentsToBindsTable,
@@ -337,3 +341,8 @@ func (g genericUpgrades) RenameTable(ctx context.Context, old, new string) error
//
// return nil
//}
func (g genericUpgrades) AlterMessageAttachmentsRenameOwner(ctx context.Context) error {
_, err := g.u.RenameColumn(ctx, "messaging_attachment", "rel_user", "rel_owner")
return err
}

View File

@@ -0,0 +1,336 @@
package rdbms
// This file is an auto-generated file
//
// Template: pkg/codegen/assets/store_rdbms.gen.go.tpl
// Definitions: store/messaging_attachments.yaml
//
// Changes to this file may cause incorrect behavior
// and will be lost if the code is regenerated.
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/Masterminds/squirrel"
"github.com/cortezaproject/corteza-server/messaging/types"
"github.com/cortezaproject/corteza-server/store"
)
var _ = errors.Is
// SearchMessagingAttachments returns all matching rows
//
// This function calls convertMessagingAttachmentFilter with the given
// types.AttachmentFilter and expects to receive a working squirrel.SelectBuilder
func (s Store) SearchMessagingAttachments(ctx context.Context, f types.AttachmentFilter) (types.AttachmentSet, types.AttachmentFilter, error) {
var (
err error
set []*types.Attachment
q squirrel.SelectBuilder
)
q, err = s.convertMessagingAttachmentFilter(f)
if err != nil {
return nil, f, err
}
return set, f, s.config.ErrorHandler(func() error {
set, _, _, err = s.QueryMessagingAttachments(ctx, q, f.Check)
return err
}())
}
// QueryMessagingAttachments queries the database, converts and checks each row and
// returns collected set
//
// Fn also returns total number of fetched items and last fetched item so that the caller can construct cursor
// for next page of results
func (s Store) QueryMessagingAttachments(
ctx context.Context,
q squirrel.SelectBuilder,
check func(*types.Attachment) (bool, error),
) ([]*types.Attachment, uint, *types.Attachment, error) {
var (
set = make([]*types.Attachment, 0, DefaultSliceCapacity)
res *types.Attachment
// Query rows with
rows, err = s.Query(ctx, q)
fetched uint
)
if err != nil {
return nil, 0, nil, err
}
defer rows.Close()
for rows.Next() {
fetched++
if err = rows.Err(); err == nil {
res, err = s.internalMessagingAttachmentRowScanner(rows)
}
if err != nil {
return nil, 0, nil, err
}
// If check function is set, call it and act accordingly
if check != nil {
if chk, err := check(res); err != nil {
return nil, 0, nil, err
} else if !chk {
// did not pass the check
// go with the next row
continue
}
}
set = append(set, res)
}
return set, fetched, res, rows.Err()
}
// LookupMessagingAttachmentByID searches for attachment by its ID
//
// It returns attachment even if deleted
func (s Store) LookupMessagingAttachmentByID(ctx context.Context, id uint64) (*types.Attachment, error) {
return s.execLookupMessagingAttachment(ctx, squirrel.Eq{
s.preprocessColumn("att.id", ""): s.preprocessValue(id, ""),
})
}
// CreateMessagingAttachment creates one or more rows in messaging_attachment table
func (s Store) CreateMessagingAttachment(ctx context.Context, rr ...*types.Attachment) (err error) {
for _, res := range rr {
err = s.checkMessagingAttachmentConstraints(ctx, res)
if err != nil {
return err
}
err = s.execCreateMessagingAttachments(ctx, s.internalMessagingAttachmentEncoder(res))
if err != nil {
return err
}
}
return
}
// UpdateMessagingAttachment updates one or more existing rows in messaging_attachment
func (s Store) UpdateMessagingAttachment(ctx context.Context, rr ...*types.Attachment) error {
return s.config.ErrorHandler(s.PartialMessagingAttachmentUpdate(ctx, nil, rr...))
}
// PartialMessagingAttachmentUpdate updates one or more existing rows in messaging_attachment
func (s Store) PartialMessagingAttachmentUpdate(ctx context.Context, onlyColumns []string, rr ...*types.Attachment) (err error) {
for _, res := range rr {
err = s.checkMessagingAttachmentConstraints(ctx, res)
if err != nil {
return err
}
err = s.execUpdateMessagingAttachments(
ctx,
squirrel.Eq{
s.preprocessColumn("att.id", ""): s.preprocessValue(res.ID, ""),
},
s.internalMessagingAttachmentEncoder(res).Skip("id").Only(onlyColumns...))
if err != nil {
return s.config.ErrorHandler(err)
}
}
return
}
// UpsertMessagingAttachment updates one or more existing rows in messaging_attachment
func (s Store) UpsertMessagingAttachment(ctx context.Context, rr ...*types.Attachment) (err error) {
for _, res := range rr {
err = s.checkMessagingAttachmentConstraints(ctx, res)
if err != nil {
return err
}
err = s.config.ErrorHandler(s.execUpsertMessagingAttachments(ctx, s.internalMessagingAttachmentEncoder(res)))
if err != nil {
return err
}
}
return nil
}
// DeleteMessagingAttachment Deletes one or more rows from messaging_attachment table
func (s Store) DeleteMessagingAttachment(ctx context.Context, rr ...*types.Attachment) (err error) {
for _, res := range rr {
err = s.execDeleteMessagingAttachments(ctx, squirrel.Eq{
s.preprocessColumn("att.id", ""): s.preprocessValue(res.ID, ""),
})
if err != nil {
return s.config.ErrorHandler(err)
}
}
return nil
}
// DeleteMessagingAttachmentByID Deletes row from the messaging_attachment table
func (s Store) DeleteMessagingAttachmentByID(ctx context.Context, ID uint64) error {
return s.execDeleteMessagingAttachments(ctx, squirrel.Eq{
s.preprocessColumn("att.id", ""): s.preprocessValue(ID, ""),
})
}
// TruncateMessagingAttachments Deletes all rows from the messaging_attachment table
func (s Store) TruncateMessagingAttachments(ctx context.Context) error {
return s.config.ErrorHandler(s.Truncate(ctx, s.messagingAttachmentTable()))
}
// execLookupMessagingAttachment prepares MessagingAttachment query and executes it,
// returning types.Attachment (or error)
func (s Store) execLookupMessagingAttachment(ctx context.Context, cnd squirrel.Sqlizer) (res *types.Attachment, err error) {
var (
row rowScanner
)
row, err = s.QueryRow(ctx, s.messagingAttachmentsSelectBuilder().Where(cnd))
if err != nil {
return
}
res, err = s.internalMessagingAttachmentRowScanner(row)
if err != nil {
return
}
return res, nil
}
// execCreateMessagingAttachments updates all matched (by cnd) rows in messaging_attachment with given data
func (s Store) execCreateMessagingAttachments(ctx context.Context, payload store.Payload) error {
return s.config.ErrorHandler(s.Exec(ctx, s.InsertBuilder(s.messagingAttachmentTable()).SetMap(payload)))
}
// execUpdateMessagingAttachments updates all matched (by cnd) rows in messaging_attachment with given data
func (s Store) execUpdateMessagingAttachments(ctx context.Context, cnd squirrel.Sqlizer, set store.Payload) error {
return s.config.ErrorHandler(s.Exec(ctx, s.UpdateBuilder(s.messagingAttachmentTable("att")).Where(cnd).SetMap(set)))
}
// execUpsertMessagingAttachments inserts new or updates matching (by-primary-key) rows in messaging_attachment with given data
func (s Store) execUpsertMessagingAttachments(ctx context.Context, set store.Payload) error {
upsert, err := s.config.UpsertBuilder(
s.config,
s.messagingAttachmentTable(),
set,
"id",
)
if err != nil {
return err
}
return s.config.ErrorHandler(s.Exec(ctx, upsert))
}
// execDeleteMessagingAttachments Deletes all matched (by cnd) rows in messaging_attachment with given data
func (s Store) execDeleteMessagingAttachments(ctx context.Context, cnd squirrel.Sqlizer) error {
return s.config.ErrorHandler(s.Exec(ctx, s.DeleteBuilder(s.messagingAttachmentTable("att")).Where(cnd)))
}
func (s Store) internalMessagingAttachmentRowScanner(row rowScanner) (res *types.Attachment, err error) {
res = &types.Attachment{}
if _, has := s.config.RowScanners["messagingAttachment"]; has {
scanner := s.config.RowScanners["messagingAttachment"].(func(_ rowScanner, _ *types.Attachment) error)
err = scanner(row, res)
} else {
err = row.Scan(
&res.ID,
&res.Url,
&res.PreviewUrl,
&res.Name,
&res.Meta,
&res.OwnerID,
&res.CreatedAt,
&res.UpdatedAt,
&res.DeletedAt,
)
}
if err == sql.ErrNoRows {
return nil, store.ErrNotFound
}
if err != nil {
return nil, fmt.Errorf("could not scan db row for MessagingAttachment: %w", err)
} else {
return res, nil
}
}
// QueryMessagingAttachments returns squirrel.SelectBuilder with set table and all columns
func (s Store) messagingAttachmentsSelectBuilder() squirrel.SelectBuilder {
return s.SelectBuilder(s.messagingAttachmentTable("att"), s.messagingAttachmentColumns("att")...)
}
// messagingAttachmentTable name of the db table
func (Store) messagingAttachmentTable(aa ...string) string {
var alias string
if len(aa) > 0 {
alias = " AS " + aa[0]
}
return "messaging_attachment" + alias
}
// MessagingAttachmentColumns returns all defined table columns
//
// With optional string arg, all columns are returned aliased
func (Store) messagingAttachmentColumns(aa ...string) []string {
var alias string
if len(aa) > 0 {
alias = aa[0] + "."
}
return []string{
alias + "id",
alias + "url",
alias + "preview_url",
alias + "name",
alias + "meta",
alias + "rel_owner",
alias + "created_at",
alias + "updated_at",
alias + "deleted_at",
}
}
// {true true false false true}
// internalMessagingAttachmentEncoder encodes fields from types.Attachment to store.Payload (map)
//
// Encoding is done by using generic approach or by calling encodeMessagingAttachment
// func when rdbms.customEncoder=true
func (s Store) internalMessagingAttachmentEncoder(res *types.Attachment) store.Payload {
return store.Payload{
"id": res.ID,
"url": res.Url,
"preview_url": res.PreviewUrl,
"name": res.Name,
"meta": res.Meta,
"rel_owner": res.OwnerID,
"created_at": res.CreatedAt,
"updated_at": res.UpdatedAt,
"deleted_at": res.DeletedAt,
}
}
func (s *Store) checkMessagingAttachmentConstraints(ctx context.Context, res *types.Attachment) error {
return nil
}

View File

@@ -0,0 +1,14 @@
package rdbms
import (
"github.com/Masterminds/squirrel"
"github.com/cortezaproject/corteza-server/messaging/types"
)
func (s Store) convertMessagingAttachmentFilter(f types.AttachmentFilter) (query squirrel.SelectBuilder, err error) {
query = s.composePagesSelectBuilder()
// @todo join & filter by message
return
}

View File

@@ -0,0 +1,306 @@
package rdbms
// This file is an auto-generated file
//
// Template: pkg/codegen/assets/store_rdbms.gen.go.tpl
// Definitions: store/messaging_channel_members.yaml
//
// Changes to this file may cause incorrect behavior
// and will be lost if the code is regenerated.
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/Masterminds/squirrel"
"github.com/cortezaproject/corteza-server/messaging/types"
"github.com/cortezaproject/corteza-server/store"
)
var _ = errors.Is
// SearchMessagingChannelMembers returns all matching rows
//
// This function calls convertMessagingChannelMemberFilter with the given
// types.ChannelMemberFilter and expects to receive a working squirrel.SelectBuilder
func (s Store) SearchMessagingChannelMembers(ctx context.Context, f types.ChannelMemberFilter) (types.ChannelMemberSet, types.ChannelMemberFilter, error) {
var (
err error
set []*types.ChannelMember
q squirrel.SelectBuilder
)
q = s.messagingChannelMembersSelectBuilder()
return set, f, s.config.ErrorHandler(func() error {
set, _, _, err = s.QueryMessagingChannelMembers(ctx, q, nil)
return err
}())
}
// QueryMessagingChannelMembers queries the database, converts and checks each row and
// returns collected set
//
// Fn also returns total number of fetched items and last fetched item so that the caller can construct cursor
// for next page of results
func (s Store) QueryMessagingChannelMembers(
ctx context.Context,
q squirrel.SelectBuilder,
check func(*types.ChannelMember) (bool, error),
) ([]*types.ChannelMember, uint, *types.ChannelMember, error) {
var (
set = make([]*types.ChannelMember, 0, DefaultSliceCapacity)
res *types.ChannelMember
// Query rows with
rows, err = s.Query(ctx, q)
fetched uint
)
if err != nil {
return nil, 0, nil, err
}
defer rows.Close()
for rows.Next() {
fetched++
if err = rows.Err(); err == nil {
res, err = s.internalMessagingChannelMemberRowScanner(rows)
}
if err != nil {
return nil, 0, nil, err
}
set = append(set, res)
}
return set, fetched, res, rows.Err()
}
// CreateMessagingChannelMember creates one or more rows in messaging_channel_member table
func (s Store) CreateMessagingChannelMember(ctx context.Context, rr ...*types.ChannelMember) (err error) {
for _, res := range rr {
err = s.checkMessagingChannelMemberConstraints(ctx, res)
if err != nil {
return err
}
err = s.execCreateMessagingChannelMembers(ctx, s.internalMessagingChannelMemberEncoder(res))
if err != nil {
return err
}
}
return
}
// UpdateMessagingChannelMember updates one or more existing rows in messaging_channel_member
func (s Store) UpdateMessagingChannelMember(ctx context.Context, rr ...*types.ChannelMember) error {
return s.config.ErrorHandler(s.PartialMessagingChannelMemberUpdate(ctx, nil, rr...))
}
// PartialMessagingChannelMemberUpdate updates one or more existing rows in messaging_channel_member
func (s Store) PartialMessagingChannelMemberUpdate(ctx context.Context, onlyColumns []string, rr ...*types.ChannelMember) (err error) {
for _, res := range rr {
err = s.checkMessagingChannelMemberConstraints(ctx, res)
if err != nil {
return err
}
err = s.execUpdateMessagingChannelMembers(
ctx,
squirrel.Eq{
s.preprocessColumn("mcm.rel_channel", ""): s.preprocessValue(res.ChannelID, ""), s.preprocessColumn("mcm.rel_user", ""): s.preprocessValue(res.UserID, ""),
},
s.internalMessagingChannelMemberEncoder(res).Skip("rel_channel", "rel_user").Only(onlyColumns...))
if err != nil {
return s.config.ErrorHandler(err)
}
}
return
}
// UpsertMessagingChannelMember updates one or more existing rows in messaging_channel_member
func (s Store) UpsertMessagingChannelMember(ctx context.Context, rr ...*types.ChannelMember) (err error) {
for _, res := range rr {
err = s.checkMessagingChannelMemberConstraints(ctx, res)
if err != nil {
return err
}
err = s.config.ErrorHandler(s.execUpsertMessagingChannelMembers(ctx, s.internalMessagingChannelMemberEncoder(res)))
if err != nil {
return err
}
}
return nil
}
// DeleteMessagingChannelMember Deletes one or more rows from messaging_channel_member table
func (s Store) DeleteMessagingChannelMember(ctx context.Context, rr ...*types.ChannelMember) (err error) {
for _, res := range rr {
err = s.execDeleteMessagingChannelMembers(ctx, squirrel.Eq{
s.preprocessColumn("mcm.rel_channel", ""): s.preprocessValue(res.ChannelID, ""), s.preprocessColumn("mcm.rel_user", ""): s.preprocessValue(res.UserID, ""),
})
if err != nil {
return s.config.ErrorHandler(err)
}
}
return nil
}
// DeleteMessagingChannelMemberByChannelIDUserID Deletes row from the messaging_channel_member table
func (s Store) DeleteMessagingChannelMemberByChannelIDUserID(ctx context.Context, channelID uint64, userID uint64) error {
return s.execDeleteMessagingChannelMembers(ctx, squirrel.Eq{
s.preprocessColumn("mcm.rel_channel", ""): s.preprocessValue(channelID, ""),
s.preprocessColumn("mcm.rel_user", ""): s.preprocessValue(userID, ""),
})
}
// TruncateMessagingChannelMembers Deletes all rows from the messaging_channel_member table
func (s Store) TruncateMessagingChannelMembers(ctx context.Context) error {
return s.config.ErrorHandler(s.Truncate(ctx, s.messagingChannelMemberTable()))
}
// execLookupMessagingChannelMember prepares MessagingChannelMember query and executes it,
// returning types.ChannelMember (or error)
func (s Store) execLookupMessagingChannelMember(ctx context.Context, cnd squirrel.Sqlizer) (res *types.ChannelMember, err error) {
var (
row rowScanner
)
row, err = s.QueryRow(ctx, s.messagingChannelMembersSelectBuilder().Where(cnd))
if err != nil {
return
}
res, err = s.internalMessagingChannelMemberRowScanner(row)
if err != nil {
return
}
return res, nil
}
// execCreateMessagingChannelMembers updates all matched (by cnd) rows in messaging_channel_member with given data
func (s Store) execCreateMessagingChannelMembers(ctx context.Context, payload store.Payload) error {
return s.config.ErrorHandler(s.Exec(ctx, s.InsertBuilder(s.messagingChannelMemberTable()).SetMap(payload)))
}
// execUpdateMessagingChannelMembers updates all matched (by cnd) rows in messaging_channel_member with given data
func (s Store) execUpdateMessagingChannelMembers(ctx context.Context, cnd squirrel.Sqlizer, set store.Payload) error {
return s.config.ErrorHandler(s.Exec(ctx, s.UpdateBuilder(s.messagingChannelMemberTable("mcm")).Where(cnd).SetMap(set)))
}
// execUpsertMessagingChannelMembers inserts new or updates matching (by-primary-key) rows in messaging_channel_member with given data
func (s Store) execUpsertMessagingChannelMembers(ctx context.Context, set store.Payload) error {
upsert, err := s.config.UpsertBuilder(
s.config,
s.messagingChannelMemberTable(),
set,
"rel_channel",
"rel_user",
)
if err != nil {
return err
}
return s.config.ErrorHandler(s.Exec(ctx, upsert))
}
// execDeleteMessagingChannelMembers Deletes all matched (by cnd) rows in messaging_channel_member with given data
func (s Store) execDeleteMessagingChannelMembers(ctx context.Context, cnd squirrel.Sqlizer) error {
return s.config.ErrorHandler(s.Exec(ctx, s.DeleteBuilder(s.messagingChannelMemberTable("mcm")).Where(cnd)))
}
func (s Store) internalMessagingChannelMemberRowScanner(row rowScanner) (res *types.ChannelMember, err error) {
res = &types.ChannelMember{}
if _, has := s.config.RowScanners["messagingChannelMember"]; has {
scanner := s.config.RowScanners["messagingChannelMember"].(func(_ rowScanner, _ *types.ChannelMember) error)
err = scanner(row, res)
} else {
err = row.Scan(
&res.ChannelID,
&res.UserID,
&res.Type,
&res.Flag,
&res.CreatedAt,
&res.UpdatedAt,
)
}
if err == sql.ErrNoRows {
return nil, store.ErrNotFound
}
if err != nil {
return nil, fmt.Errorf("could not scan db row for MessagingChannelMember: %w", err)
} else {
return res, nil
}
}
// QueryMessagingChannelMembers returns squirrel.SelectBuilder with set table and all columns
func (s Store) messagingChannelMembersSelectBuilder() squirrel.SelectBuilder {
return s.SelectBuilder(s.messagingChannelMemberTable("mcm"), s.messagingChannelMemberColumns("mcm")...)
}
// messagingChannelMemberTable name of the db table
func (Store) messagingChannelMemberTable(aa ...string) string {
var alias string
if len(aa) > 0 {
alias = " AS " + aa[0]
}
return "messaging_channel_member" + alias
}
// MessagingChannelMemberColumns returns all defined table columns
//
// With optional string arg, all columns are returned aliased
func (Store) messagingChannelMemberColumns(aa ...string) []string {
var alias string
if len(aa) > 0 {
alias = aa[0] + "."
}
return []string{
alias + "rel_channel",
alias + "rel_user",
alias + "type",
alias + "flag",
alias + "created_at",
alias + "updated_at",
}
}
// {true true false false false}
// internalMessagingChannelMemberEncoder encodes fields from types.ChannelMember to store.Payload (map)
//
// Encoding is done by using generic approach or by calling encodeMessagingChannelMember
// func when rdbms.customEncoder=true
func (s Store) internalMessagingChannelMemberEncoder(res *types.ChannelMember) store.Payload {
return store.Payload{
"rel_channel": res.ChannelID,
"rel_user": res.UserID,
"type": res.Type,
"flag": res.Flag,
"created_at": res.CreatedAt,
"updated_at": res.UpdatedAt,
}
}
func (s *Store) checkMessagingChannelMemberConstraints(ctx context.Context, res *types.ChannelMember) error {
return nil
}

View File

@@ -0,0 +1,518 @@
package rdbms
// This file is an auto-generated file
//
// Template: pkg/codegen/assets/store_rdbms.gen.go.tpl
// Definitions: store/messaging_channels.yaml
//
// Changes to this file may cause incorrect behavior
// and will be lost if the code is regenerated.
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/Masterminds/squirrel"
"github.com/cortezaproject/corteza-server/messaging/types"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/store"
)
var _ = errors.Is
// SearchMessagingChannels returns all matching rows
//
// This function calls convertMessagingChannelFilter with the given
// types.ChannelFilter and expects to receive a working squirrel.SelectBuilder
func (s Store) SearchMessagingChannels(ctx context.Context, f types.ChannelFilter) (types.ChannelSet, types.ChannelFilter, error) {
var (
err error
set []*types.Channel
q squirrel.SelectBuilder
)
q = s.messagingChannelsSelectBuilder()
// Cleanup anything we've accidentally received...
f.PrevPage, f.NextPage = nil, nil
// When cursor for a previous page is used it's marked as reversed
// This tells us to flip the descending flag on all used sort keys
reversedCursor := f.PageCursor != nil && f.PageCursor.Reverse
// If paging with reverse cursor, change the sorting
// direction for all columns we're sorting by
curSort := f.Sort.Clone()
if reversedCursor {
curSort.Reverse()
}
return set, f, s.config.ErrorHandler(func() error {
set, err = s.fetchFullPageOfMessagingChannels(ctx, q, curSort, f.PageCursor, f.Limit, f.Check)
if err != nil {
return err
}
if f.Limit > 0 && len(set) > 0 {
if f.PageCursor != nil && (!f.PageCursor.Reverse || uint(len(set)) == f.Limit) {
f.PrevPage = s.collectMessagingChannelCursorValues(set[0], curSort.Columns()...)
f.PrevPage.Reverse = true
}
// Less items fetched then requested by page-limit
// not very likely there's another page
f.NextPage = s.collectMessagingChannelCursorValues(set[len(set)-1], curSort.Columns()...)
}
f.PageCursor = nil
return nil
}())
}
// fetchFullPageOfMessagingChannels collects all requested results.
//
// Function applies:
// - cursor conditions (where ...)
// - sorting rules (order by ...)
// - limit
//
// Main responsibility of this function is to perform additional sequential queries in case when not enough results
// are collected due to failed check on a specific row (by check fn). Function then moves cursor to the last item fetched
func (s Store) fetchFullPageOfMessagingChannels(
ctx context.Context,
q squirrel.SelectBuilder,
sort filter.SortExprSet,
cursor *filter.PagingCursor,
limit uint,
check func(*types.Channel) (bool, error),
) ([]*types.Channel, error) {
var (
set = make([]*types.Channel, 0, DefaultSliceCapacity)
aux []*types.Channel
last *types.Channel
// When cursor for a previous page is used it's marked as reversed
// This tells us to flip the descending flag on all used sort keys
reversedCursor = cursor != nil && cursor.Reverse
// copy of the select builder
tryQuery squirrel.SelectBuilder
fetched uint
err error
)
// Make sure we always end our sort by primary keys
if sort.Get("id") == nil {
sort = append(sort, &filter.SortExpr{Column: "id"})
}
// Apply sorting expr from filter to query
if q, err = setOrderBy(q, sort, s.sortableMessagingChannelColumns()...); err != nil {
return nil, err
}
for try := 0; try < MaxRefetches; try++ {
tryQuery = setCursorCond(q, cursor)
if limit > 0 {
tryQuery = tryQuery.Limit(uint64(limit))
}
if aux, fetched, last, err = s.QueryMessagingChannels(ctx, tryQuery, check); err != nil {
return nil, err
}
if limit > 0 && uint(len(aux)) >= limit {
// we should use only as much as requested
set = append(set, aux[0:limit]...)
break
} else {
set = append(set, aux...)
}
// if limit is not set or we've already collected enough items
// we can break the loop right away
if limit == 0 || fetched == 0 || fetched < limit {
break
}
// In case limit is set very low and we've missed records in the first fetch,
// make sure next fetch limit is a bit higher
if limit < MinEnsureFetchLimit {
limit = MinEnsureFetchLimit
}
// @todo improve strategy for collecting next page with lower limit
// Point cursor to the last fetched element
if cursor = s.collectMessagingChannelCursorValues(last, sort.Columns()...); cursor == nil {
break
}
}
if reversedCursor {
// Cursor for previous page was used
// Fetched set needs to be reverseCursor because we've forced a descending order to
// get the previous page
for i, j := 0, len(set)-1; i < j; i, j = i+1, j-1 {
set[i], set[j] = set[j], set[i]
}
}
return set, nil
}
// QueryMessagingChannels queries the database, converts and checks each row and
// returns collected set
//
// Fn also returns total number of fetched items and last fetched item so that the caller can construct cursor
// for next page of results
func (s Store) QueryMessagingChannels(
ctx context.Context,
q squirrel.SelectBuilder,
check func(*types.Channel) (bool, error),
) ([]*types.Channel, uint, *types.Channel, error) {
var (
set = make([]*types.Channel, 0, DefaultSliceCapacity)
res *types.Channel
// Query rows with
rows, err = s.Query(ctx, q)
fetched uint
)
if err != nil {
return nil, 0, nil, err
}
defer rows.Close()
for rows.Next() {
fetched++
if err = rows.Err(); err == nil {
res, err = s.internalMessagingChannelRowScanner(rows)
}
if err != nil {
return nil, 0, nil, err
}
// If check function is set, call it and act accordingly
if check != nil {
if chk, err := check(res); err != nil {
return nil, 0, nil, err
} else if !chk {
// did not pass the check
// go with the next row
continue
}
}
set = append(set, res)
}
return set, fetched, res, rows.Err()
}
// LookupMessagingChannelByID searches for attachment by its ID
//
// It returns attachment even if deleted
func (s Store) LookupMessagingChannelByID(ctx context.Context, id uint64) (*types.Channel, error) {
return s.execLookupMessagingChannel(ctx, squirrel.Eq{
s.preprocessColumn("mch.id", ""): s.preprocessValue(id, ""),
})
}
// CreateMessagingChannel creates one or more rows in messaging_channel table
func (s Store) CreateMessagingChannel(ctx context.Context, rr ...*types.Channel) (err error) {
for _, res := range rr {
err = s.checkMessagingChannelConstraints(ctx, res)
if err != nil {
return err
}
err = s.execCreateMessagingChannels(ctx, s.internalMessagingChannelEncoder(res))
if err != nil {
return err
}
}
return
}
// UpdateMessagingChannel updates one or more existing rows in messaging_channel
func (s Store) UpdateMessagingChannel(ctx context.Context, rr ...*types.Channel) error {
return s.config.ErrorHandler(s.PartialMessagingChannelUpdate(ctx, nil, rr...))
}
// PartialMessagingChannelUpdate updates one or more existing rows in messaging_channel
func (s Store) PartialMessagingChannelUpdate(ctx context.Context, onlyColumns []string, rr ...*types.Channel) (err error) {
for _, res := range rr {
err = s.checkMessagingChannelConstraints(ctx, res)
if err != nil {
return err
}
err = s.execUpdateMessagingChannels(
ctx,
squirrel.Eq{
s.preprocessColumn("mch.id", ""): s.preprocessValue(res.ID, ""),
},
s.internalMessagingChannelEncoder(res).Skip("id").Only(onlyColumns...))
if err != nil {
return s.config.ErrorHandler(err)
}
}
return
}
// UpsertMessagingChannel updates one or more existing rows in messaging_channel
func (s Store) UpsertMessagingChannel(ctx context.Context, rr ...*types.Channel) (err error) {
for _, res := range rr {
err = s.checkMessagingChannelConstraints(ctx, res)
if err != nil {
return err
}
err = s.config.ErrorHandler(s.execUpsertMessagingChannels(ctx, s.internalMessagingChannelEncoder(res)))
if err != nil {
return err
}
}
return nil
}
// DeleteMessagingChannel Deletes one or more rows from messaging_channel table
func (s Store) DeleteMessagingChannel(ctx context.Context, rr ...*types.Channel) (err error) {
for _, res := range rr {
err = s.execDeleteMessagingChannels(ctx, squirrel.Eq{
s.preprocessColumn("mch.id", ""): s.preprocessValue(res.ID, ""),
})
if err != nil {
return s.config.ErrorHandler(err)
}
}
return nil
}
// DeleteMessagingChannelByID Deletes row from the messaging_channel table
func (s Store) DeleteMessagingChannelByID(ctx context.Context, ID uint64) error {
return s.execDeleteMessagingChannels(ctx, squirrel.Eq{
s.preprocessColumn("mch.id", ""): s.preprocessValue(ID, ""),
})
}
// TruncateMessagingChannels Deletes all rows from the messaging_channel table
func (s Store) TruncateMessagingChannels(ctx context.Context) error {
return s.config.ErrorHandler(s.Truncate(ctx, s.messagingChannelTable()))
}
// execLookupMessagingChannel prepares MessagingChannel query and executes it,
// returning types.Channel (or error)
func (s Store) execLookupMessagingChannel(ctx context.Context, cnd squirrel.Sqlizer) (res *types.Channel, err error) {
var (
row rowScanner
)
row, err = s.QueryRow(ctx, s.messagingChannelsSelectBuilder().Where(cnd))
if err != nil {
return
}
res, err = s.internalMessagingChannelRowScanner(row)
if err != nil {
return
}
return res, nil
}
// execCreateMessagingChannels updates all matched (by cnd) rows in messaging_channel with given data
func (s Store) execCreateMessagingChannels(ctx context.Context, payload store.Payload) error {
return s.config.ErrorHandler(s.Exec(ctx, s.InsertBuilder(s.messagingChannelTable()).SetMap(payload)))
}
// execUpdateMessagingChannels updates all matched (by cnd) rows in messaging_channel with given data
func (s Store) execUpdateMessagingChannels(ctx context.Context, cnd squirrel.Sqlizer, set store.Payload) error {
return s.config.ErrorHandler(s.Exec(ctx, s.UpdateBuilder(s.messagingChannelTable("mch")).Where(cnd).SetMap(set)))
}
// execUpsertMessagingChannels inserts new or updates matching (by-primary-key) rows in messaging_channel with given data
func (s Store) execUpsertMessagingChannels(ctx context.Context, set store.Payload) error {
upsert, err := s.config.UpsertBuilder(
s.config,
s.messagingChannelTable(),
set,
"id",
)
if err != nil {
return err
}
return s.config.ErrorHandler(s.Exec(ctx, upsert))
}
// execDeleteMessagingChannels Deletes all matched (by cnd) rows in messaging_channel with given data
func (s Store) execDeleteMessagingChannels(ctx context.Context, cnd squirrel.Sqlizer) error {
return s.config.ErrorHandler(s.Exec(ctx, s.DeleteBuilder(s.messagingChannelTable("mch")).Where(cnd)))
}
func (s Store) internalMessagingChannelRowScanner(row rowScanner) (res *types.Channel, err error) {
res = &types.Channel{}
if _, has := s.config.RowScanners["messagingChannel"]; has {
scanner := s.config.RowScanners["messagingChannel"].(func(_ rowScanner, _ *types.Channel) error)
err = scanner(row, res)
} else {
err = row.Scan(
&res.ID,
&res.Name,
&res.Topic,
&res.Type,
&res.Meta,
&res.MembershipPolicy,
&res.CreatorID,
&res.OrganisationID,
&res.CreatedAt,
&res.UpdatedAt,
&res.ArchivedAt,
&res.DeletedAt,
&res.LastMessageID,
)
}
if err == sql.ErrNoRows {
return nil, store.ErrNotFound
}
if err != nil {
return nil, fmt.Errorf("could not scan db row for MessagingChannel: %w", err)
} else {
return res, nil
}
}
// QueryMessagingChannels returns squirrel.SelectBuilder with set table and all columns
func (s Store) messagingChannelsSelectBuilder() squirrel.SelectBuilder {
return s.SelectBuilder(s.messagingChannelTable("mch"), s.messagingChannelColumns("mch")...)
}
// messagingChannelTable name of the db table
func (Store) messagingChannelTable(aa ...string) string {
var alias string
if len(aa) > 0 {
alias = " AS " + aa[0]
}
return "messaging_channel" + alias
}
// MessagingChannelColumns returns all defined table columns
//
// With optional string arg, all columns are returned aliased
func (Store) messagingChannelColumns(aa ...string) []string {
var alias string
if len(aa) > 0 {
alias = aa[0] + "."
}
return []string{
alias + "id",
alias + "name",
alias + "topic",
alias + "type",
alias + "meta",
alias + "membership_policy",
alias + "rel_creator",
alias + "rel_organisation",
alias + "created_at",
alias + "updated_at",
alias + "archived_at",
alias + "deleted_at",
alias + "rel_last_message",
}
}
// {true true true true true}
// sortableMessagingChannelColumns returns all MessagingChannel columns flagged as sortable
//
// With optional string arg, all columns are returned aliased
func (Store) sortableMessagingChannelColumns() []string {
return []string{
"id",
}
}
// internalMessagingChannelEncoder encodes fields from types.Channel to store.Payload (map)
//
// Encoding is done by using generic approach or by calling encodeMessagingChannel
// func when rdbms.customEncoder=true
func (s Store) internalMessagingChannelEncoder(res *types.Channel) store.Payload {
return store.Payload{
"id": res.ID,
"name": res.Name,
"topic": res.Topic,
"type": res.Type,
"meta": res.Meta,
"membership_policy": res.MembershipPolicy,
"rel_creator": res.CreatorID,
"rel_organisation": res.OrganisationID,
"created_at": res.CreatedAt,
"updated_at": res.UpdatedAt,
"archived_at": res.ArchivedAt,
"deleted_at": res.DeletedAt,
"rel_last_message": res.LastMessageID,
}
}
// collectMessagingChannelCursorValues collects values from the given resource that and sets them to the cursor
// to be used for pagination
//
// Values that are collected must come from sortable, unique or primary columns/fields
// At least one of the collected columns must be flagged as unique, otherwise fn appends primary keys at the end
//
// Known issue:
// when collecting cursor values for query that sorts by unique column with partial index (ie: unique handle on
// undeleted items)
func (s Store) collectMessagingChannelCursorValues(res *types.Channel, cc ...string) *filter.PagingCursor {
var (
cursor = &filter.PagingCursor{}
hasUnique bool
// All known primary key columns
pkId bool
collect = func(cc ...string) {
for _, c := range cc {
switch c {
case "id":
cursor.Set(c, res.ID, false)
pkId = true
}
}
}
)
collect(cc...)
if !hasUnique || !(pkId && true) {
collect("id")
}
return cursor
}
func (s *Store) checkMessagingChannelConstraints(ctx context.Context, res *types.Channel) error {
return nil
}

View File

@@ -0,0 +1,328 @@
package rdbms
// This file is an auto-generated file
//
// Template: pkg/codegen/assets/store_rdbms.gen.go.tpl
// Definitions: store/messaging_messages.yaml
//
// Changes to this file may cause incorrect behavior
// and will be lost if the code is regenerated.
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/Masterminds/squirrel"
"github.com/cortezaproject/corteza-server/messaging/types"
"github.com/cortezaproject/corteza-server/store"
)
var _ = errors.Is
// SearchMessagingMessages returns all matching rows
//
// This function calls convertMessagingMessageFilter with the given
// types.MessageFilter and expects to receive a working squirrel.SelectBuilder
func (s Store) SearchMessagingMessages(ctx context.Context, f types.MessageFilter) (types.MessageSet, types.MessageFilter, error) {
var (
err error
set []*types.Message
q squirrel.SelectBuilder
)
q = s.messagingMessagesSelectBuilder()
return set, f, s.config.ErrorHandler(func() error {
set, _, _, err = s.QueryMessagingMessages(ctx, q, nil)
return err
}())
}
// QueryMessagingMessages queries the database, converts and checks each row and
// returns collected set
//
// Fn also returns total number of fetched items and last fetched item so that the caller can construct cursor
// for next page of results
func (s Store) QueryMessagingMessages(
ctx context.Context,
q squirrel.SelectBuilder,
check func(*types.Message) (bool, error),
) ([]*types.Message, uint, *types.Message, error) {
var (
set = make([]*types.Message, 0, DefaultSliceCapacity)
res *types.Message
// Query rows with
rows, err = s.Query(ctx, q)
fetched uint
)
if err != nil {
return nil, 0, nil, err
}
defer rows.Close()
for rows.Next() {
fetched++
if err = rows.Err(); err == nil {
res, err = s.internalMessagingMessageRowScanner(rows)
}
if err != nil {
return nil, 0, nil, err
}
set = append(set, res)
}
return set, fetched, res, rows.Err()
}
// LookupMessagingMessageByID searches for attachment by its ID
//
// It returns attachment even if deleted
func (s Store) LookupMessagingMessageByID(ctx context.Context, id uint64) (*types.Message, error) {
return s.execLookupMessagingMessage(ctx, squirrel.Eq{
s.preprocessColumn("msg.id", ""): s.preprocessValue(id, ""),
})
}
// CreateMessagingMessage creates one or more rows in messaging_messages table
func (s Store) CreateMessagingMessage(ctx context.Context, rr ...*types.Message) (err error) {
for _, res := range rr {
err = s.checkMessagingMessageConstraints(ctx, res)
if err != nil {
return err
}
err = s.execCreateMessagingMessages(ctx, s.internalMessagingMessageEncoder(res))
if err != nil {
return err
}
}
return
}
// UpdateMessagingMessage updates one or more existing rows in messaging_messages
func (s Store) UpdateMessagingMessage(ctx context.Context, rr ...*types.Message) error {
return s.config.ErrorHandler(s.PartialMessagingMessageUpdate(ctx, nil, rr...))
}
// PartialMessagingMessageUpdate updates one or more existing rows in messaging_messages
func (s Store) PartialMessagingMessageUpdate(ctx context.Context, onlyColumns []string, rr ...*types.Message) (err error) {
for _, res := range rr {
err = s.checkMessagingMessageConstraints(ctx, res)
if err != nil {
return err
}
err = s.execUpdateMessagingMessages(
ctx,
squirrel.Eq{
s.preprocessColumn("msg.id", ""): s.preprocessValue(res.ID, ""),
},
s.internalMessagingMessageEncoder(res).Skip("id").Only(onlyColumns...))
if err != nil {
return s.config.ErrorHandler(err)
}
}
return
}
// UpsertMessagingMessage updates one or more existing rows in messaging_messages
func (s Store) UpsertMessagingMessage(ctx context.Context, rr ...*types.Message) (err error) {
for _, res := range rr {
err = s.checkMessagingMessageConstraints(ctx, res)
if err != nil {
return err
}
err = s.config.ErrorHandler(s.execUpsertMessagingMessages(ctx, s.internalMessagingMessageEncoder(res)))
if err != nil {
return err
}
}
return nil
}
// DeleteMessagingMessage Deletes one or more rows from messaging_messages table
func (s Store) DeleteMessagingMessage(ctx context.Context, rr ...*types.Message) (err error) {
for _, res := range rr {
err = s.execDeleteMessagingMessages(ctx, squirrel.Eq{
s.preprocessColumn("msg.id", ""): s.preprocessValue(res.ID, ""),
})
if err != nil {
return s.config.ErrorHandler(err)
}
}
return nil
}
// DeleteMessagingMessageByID Deletes row from the messaging_messages table
func (s Store) DeleteMessagingMessageByID(ctx context.Context, ID uint64) error {
return s.execDeleteMessagingMessages(ctx, squirrel.Eq{
s.preprocessColumn("msg.id", ""): s.preprocessValue(ID, ""),
})
}
// TruncateMessagingMessages Deletes all rows from the messaging_messages table
func (s Store) TruncateMessagingMessages(ctx context.Context) error {
return s.config.ErrorHandler(s.Truncate(ctx, s.messagingMessageTable()))
}
// execLookupMessagingMessage prepares MessagingMessage query and executes it,
// returning types.Message (or error)
func (s Store) execLookupMessagingMessage(ctx context.Context, cnd squirrel.Sqlizer) (res *types.Message, err error) {
var (
row rowScanner
)
row, err = s.QueryRow(ctx, s.messagingMessagesSelectBuilder().Where(cnd))
if err != nil {
return
}
res, err = s.internalMessagingMessageRowScanner(row)
if err != nil {
return
}
return res, nil
}
// execCreateMessagingMessages updates all matched (by cnd) rows in messaging_messages with given data
func (s Store) execCreateMessagingMessages(ctx context.Context, payload store.Payload) error {
return s.config.ErrorHandler(s.Exec(ctx, s.InsertBuilder(s.messagingMessageTable()).SetMap(payload)))
}
// execUpdateMessagingMessages updates all matched (by cnd) rows in messaging_messages with given data
func (s Store) execUpdateMessagingMessages(ctx context.Context, cnd squirrel.Sqlizer, set store.Payload) error {
return s.config.ErrorHandler(s.Exec(ctx, s.UpdateBuilder(s.messagingMessageTable("msg")).Where(cnd).SetMap(set)))
}
// execUpsertMessagingMessages inserts new or updates matching (by-primary-key) rows in messaging_messages with given data
func (s Store) execUpsertMessagingMessages(ctx context.Context, set store.Payload) error {
upsert, err := s.config.UpsertBuilder(
s.config,
s.messagingMessageTable(),
set,
"id",
)
if err != nil {
return err
}
return s.config.ErrorHandler(s.Exec(ctx, upsert))
}
// execDeleteMessagingMessages Deletes all matched (by cnd) rows in messaging_messages with given data
func (s Store) execDeleteMessagingMessages(ctx context.Context, cnd squirrel.Sqlizer) error {
return s.config.ErrorHandler(s.Exec(ctx, s.DeleteBuilder(s.messagingMessageTable("msg")).Where(cnd)))
}
func (s Store) internalMessagingMessageRowScanner(row rowScanner) (res *types.Message, err error) {
res = &types.Message{}
if _, has := s.config.RowScanners["messagingMessage"]; has {
scanner := s.config.RowScanners["messagingMessage"].(func(_ rowScanner, _ *types.Message) error)
err = scanner(row, res)
} else {
err = row.Scan(
&res.ID,
&res.Type,
&res.Message,
&res.Meta,
&res.UserID,
&res.ChannelID,
&res.ReplyTo,
&res.Replies,
&res.CreatedAt,
&res.UpdatedAt,
&res.DeletedAt,
)
}
if err == sql.ErrNoRows {
return nil, store.ErrNotFound
}
if err != nil {
return nil, fmt.Errorf("could not scan db row for MessagingMessage: %w", err)
} else {
return res, nil
}
}
// QueryMessagingMessages returns squirrel.SelectBuilder with set table and all columns
func (s Store) messagingMessagesSelectBuilder() squirrel.SelectBuilder {
return s.SelectBuilder(s.messagingMessageTable("msg"), s.messagingMessageColumns("msg")...)
}
// messagingMessageTable name of the db table
func (Store) messagingMessageTable(aa ...string) string {
var alias string
if len(aa) > 0 {
alias = " AS " + aa[0]
}
return "messaging_messages" + alias
}
// MessagingMessageColumns returns all defined table columns
//
// With optional string arg, all columns are returned aliased
func (Store) messagingMessageColumns(aa ...string) []string {
var alias string
if len(aa) > 0 {
alias = aa[0] + "."
}
return []string{
alias + "id",
alias + "type",
alias + "message",
alias + "meta",
alias + "rel_user",
alias + "rel_channel",
alias + "reply_to",
alias + "replies",
alias + "created_at",
alias + "updated_at",
alias + "deleted_at",
}
}
// {true true false false false}
// internalMessagingMessageEncoder encodes fields from types.Message to store.Payload (map)
//
// Encoding is done by using generic approach or by calling encodeMessagingMessage
// func when rdbms.customEncoder=true
func (s Store) internalMessagingMessageEncoder(res *types.Message) store.Payload {
return store.Payload{
"id": res.ID,
"type": res.Type,
"message": res.Message,
"meta": res.Meta,
"rel_user": res.UserID,
"rel_channel": res.ChannelID,
"reply_to": res.ReplyTo,
"replies": res.Replies,
"created_at": res.CreatedAt,
"updated_at": res.UpdatedAt,
"deleted_at": res.DeletedAt,
}
}
func (s *Store) checkMessagingMessageConstraints(ctx context.Context, res *types.Message) error {
return nil
}

View File

@@ -0,0 +1,286 @@
package rdbms
// This file is an auto-generated file
//
// Template: pkg/codegen/assets/store_rdbms.gen.go.tpl
// Definitions: store/messaging_unread.yaml
//
// Changes to this file may cause incorrect behavior
// and will be lost if the code is regenerated.
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/Masterminds/squirrel"
"github.com/cortezaproject/corteza-server/messaging/types"
"github.com/cortezaproject/corteza-server/store"
)
var _ = errors.Is
// QueryMessagingUnreads queries the database, converts and checks each row and
// returns collected set
//
// Fn also returns total number of fetched items and last fetched item so that the caller can construct cursor
// for next page of results
func (s Store) QueryMessagingUnreads(
ctx context.Context,
q squirrel.SelectBuilder,
check func(*types.Unread) (bool, error),
) ([]*types.Unread, uint, *types.Unread, error) {
var (
set = make([]*types.Unread, 0, DefaultSliceCapacity)
res *types.Unread
// Query rows with
rows, err = s.Query(ctx, q)
fetched uint
)
if err != nil {
return nil, 0, nil, err
}
defer rows.Close()
for rows.Next() {
fetched++
if err = rows.Err(); err == nil {
res, err = s.internalMessagingUnreadRowScanner(rows)
}
if err != nil {
return nil, 0, nil, err
}
set = append(set, res)
}
return set, fetched, res, rows.Err()
}
// CreateMessagingUnread creates one or more rows in messaging_unread table
func (s Store) CreateMessagingUnread(ctx context.Context, rr ...*types.Unread) (err error) {
for _, res := range rr {
err = s.checkMessagingUnreadConstraints(ctx, res)
if err != nil {
return err
}
err = s.execCreateMessagingUnreads(ctx, s.internalMessagingUnreadEncoder(res))
if err != nil {
return err
}
}
return
}
// UpdateMessagingUnread updates one or more existing rows in messaging_unread
func (s Store) UpdateMessagingUnread(ctx context.Context, rr ...*types.Unread) error {
return s.config.ErrorHandler(s.PartialMessagingUnreadUpdate(ctx, nil, rr...))
}
// PartialMessagingUnreadUpdate updates one or more existing rows in messaging_unread
func (s Store) PartialMessagingUnreadUpdate(ctx context.Context, onlyColumns []string, rr ...*types.Unread) (err error) {
for _, res := range rr {
err = s.checkMessagingUnreadConstraints(ctx, res)
if err != nil {
return err
}
err = s.execUpdateMessagingUnreads(
ctx,
squirrel.Eq{
s.preprocessColumn("mur.rel_channel", ""): s.preprocessValue(res.ChannelID, ""), s.preprocessColumn("mur.reply_to", ""): s.preprocessValue(res.ReplyTo, ""), s.preprocessColumn("mur.rel_user", ""): s.preprocessValue(res.UserID, ""),
},
s.internalMessagingUnreadEncoder(res).Skip("rel_channel", "reply_to", "rel_user").Only(onlyColumns...))
if err != nil {
return s.config.ErrorHandler(err)
}
}
return
}
// UpsertMessagingUnread updates one or more existing rows in messaging_unread
func (s Store) UpsertMessagingUnread(ctx context.Context, rr ...*types.Unread) (err error) {
for _, res := range rr {
err = s.checkMessagingUnreadConstraints(ctx, res)
if err != nil {
return err
}
err = s.config.ErrorHandler(s.execUpsertMessagingUnreads(ctx, s.internalMessagingUnreadEncoder(res)))
if err != nil {
return err
}
}
return nil
}
// DeleteMessagingUnread Deletes one or more rows from messaging_unread table
func (s Store) DeleteMessagingUnread(ctx context.Context, rr ...*types.Unread) (err error) {
for _, res := range rr {
err = s.execDeleteMessagingUnreads(ctx, squirrel.Eq{
s.preprocessColumn("mur.rel_channel", ""): s.preprocessValue(res.ChannelID, ""), s.preprocessColumn("mur.reply_to", ""): s.preprocessValue(res.ReplyTo, ""), s.preprocessColumn("mur.rel_user", ""): s.preprocessValue(res.UserID, ""),
})
if err != nil {
return s.config.ErrorHandler(err)
}
}
return nil
}
// DeleteMessagingUnreadByChannelIDReplyToUserID Deletes row from the messaging_unread table
func (s Store) DeleteMessagingUnreadByChannelIDReplyToUserID(ctx context.Context, channelID uint64, replyTo uint64, userID uint64) error {
return s.execDeleteMessagingUnreads(ctx, squirrel.Eq{
s.preprocessColumn("mur.rel_channel", ""): s.preprocessValue(channelID, ""),
s.preprocessColumn("mur.reply_to", ""): s.preprocessValue(replyTo, ""),
s.preprocessColumn("mur.rel_user", ""): s.preprocessValue(userID, ""),
})
}
// TruncateMessagingUnreads Deletes all rows from the messaging_unread table
func (s Store) TruncateMessagingUnreads(ctx context.Context) error {
return s.config.ErrorHandler(s.Truncate(ctx, s.messagingUnreadTable()))
}
// execLookupMessagingUnread prepares MessagingUnread query and executes it,
// returning types.Unread (or error)
func (s Store) execLookupMessagingUnread(ctx context.Context, cnd squirrel.Sqlizer) (res *types.Unread, err error) {
var (
row rowScanner
)
row, err = s.QueryRow(ctx, s.messagingUnreadsSelectBuilder().Where(cnd))
if err != nil {
return
}
res, err = s.internalMessagingUnreadRowScanner(row)
if err != nil {
return
}
return res, nil
}
// execCreateMessagingUnreads updates all matched (by cnd) rows in messaging_unread with given data
func (s Store) execCreateMessagingUnreads(ctx context.Context, payload store.Payload) error {
return s.config.ErrorHandler(s.Exec(ctx, s.InsertBuilder(s.messagingUnreadTable()).SetMap(payload)))
}
// execUpdateMessagingUnreads updates all matched (by cnd) rows in messaging_unread with given data
func (s Store) execUpdateMessagingUnreads(ctx context.Context, cnd squirrel.Sqlizer, set store.Payload) error {
return s.config.ErrorHandler(s.Exec(ctx, s.UpdateBuilder(s.messagingUnreadTable("mur")).Where(cnd).SetMap(set)))
}
// execUpsertMessagingUnreads inserts new or updates matching (by-primary-key) rows in messaging_unread with given data
func (s Store) execUpsertMessagingUnreads(ctx context.Context, set store.Payload) error {
upsert, err := s.config.UpsertBuilder(
s.config,
s.messagingUnreadTable(),
set,
"rel_channel",
"reply_to",
"rel_user",
)
if err != nil {
return err
}
return s.config.ErrorHandler(s.Exec(ctx, upsert))
}
// execDeleteMessagingUnreads Deletes all matched (by cnd) rows in messaging_unread with given data
func (s Store) execDeleteMessagingUnreads(ctx context.Context, cnd squirrel.Sqlizer) error {
return s.config.ErrorHandler(s.Exec(ctx, s.DeleteBuilder(s.messagingUnreadTable("mur")).Where(cnd)))
}
func (s Store) internalMessagingUnreadRowScanner(row rowScanner) (res *types.Unread, err error) {
res = &types.Unread{}
if _, has := s.config.RowScanners["messagingUnread"]; has {
scanner := s.config.RowScanners["messagingUnread"].(func(_ rowScanner, _ *types.Unread) error)
err = scanner(row, res)
} else {
err = row.Scan(
&res.ChannelID,
&res.ReplyTo,
&res.UserID,
&res.LastMessageID,
&res.Count,
)
}
if err == sql.ErrNoRows {
return nil, store.ErrNotFound
}
if err != nil {
return nil, fmt.Errorf("could not scan db row for MessagingUnread: %w", err)
} else {
return res, nil
}
}
// QueryMessagingUnreads returns squirrel.SelectBuilder with set table and all columns
func (s Store) messagingUnreadsSelectBuilder() squirrel.SelectBuilder {
return s.SelectBuilder(s.messagingUnreadTable("mur"), s.messagingUnreadColumns("mur")...)
}
// messagingUnreadTable name of the db table
func (Store) messagingUnreadTable(aa ...string) string {
var alias string
if len(aa) > 0 {
alias = " AS " + aa[0]
}
return "messaging_unread" + alias
}
// MessagingUnreadColumns returns all defined table columns
//
// With optional string arg, all columns are returned aliased
func (Store) messagingUnreadColumns(aa ...string) []string {
var alias string
if len(aa) > 0 {
alias = aa[0] + "."
}
return []string{
alias + "rel_channel",
alias + "reply_to",
alias + "rel_user",
alias + "rel_last_message",
alias + "count",
}
}
// {false true false false false}
// internalMessagingUnreadEncoder encodes fields from types.Unread to store.Payload (map)
//
// Encoding is done by using generic approach or by calling encodeMessagingUnread
// func when rdbms.customEncoder=true
func (s Store) internalMessagingUnreadEncoder(res *types.Unread) store.Payload {
return store.Payload{
"rel_channel": res.ChannelID,
"reply_to": res.ReplyTo,
"rel_user": res.UserID,
"rel_last_message": res.LastMessageID,
"count": res.Count,
}
}
func (s *Store) checkMessagingUnreadConstraints(ctx context.Context, res *types.Unread) error {
return nil
}

View File

@@ -384,7 +384,7 @@ func (Schema) MessagingAttachment() *Table {
// @todo merge with general attachment table
return TableDef("messaging_attachment",
ID,
ColumnDef("rel_user", ColumnTypeIdentifier), // @todo rename => rel_owner
ColumnDef("rel_owner", ColumnTypeIdentifier),
ColumnDef("url", ColumnTypeText),
ColumnDef("preview_url", ColumnTypeText),
ColumnDef("name", ColumnTypeText),

View File

@@ -14,6 +14,11 @@ package tests
// - store/compose_namespaces.yaml
// - store/compose_pages.yaml
// - store/credentials.yaml
// - store/messaging_attachments.yaml
// - store/messaging_channel_members.yaml
// - store/messaging_channels.yaml
// - store/messaging_messages.yaml
// - store/messaging_unread.yaml
// - store/rbac_rules.yaml
// - store/reminders.yaml
// - store/role_members.yaml
@@ -92,6 +97,31 @@ func testAllGenerated(t *testing.T, s store.Storable) {
testCredentials(t, s)
})
// Run generated tests for MessagingAttachments
t.Run("MessagingAttachments", func(t *testing.T) {
testMessagingAttachments(t, s)
})
// Run generated tests for MessagingChannelMembers
t.Run("MessagingChannelMembers", func(t *testing.T) {
testMessagingChannelMembers(t, s)
})
// Run generated tests for MessagingChannels
t.Run("MessagingChannels", func(t *testing.T) {
testMessagingChannels(t, s)
})
// Run generated tests for MessagingMessages
t.Run("MessagingMessages", func(t *testing.T) {
testMessagingMessages(t, s)
})
// Run generated tests for MessagingUnread
t.Run("MessagingUnread", func(t *testing.T) {
testMessagingUnread(t, s)
})
// Run generated tests for RbacRules
t.Run("RbacRules", func(t *testing.T) {
testRbacRules(t, s)

View File

@@ -17,8 +17,8 @@ func testRoleMembers(t *testing.T, s store.RoleMembers) {
makeNew = func(nn ...string) *types.RoleMember {
// minimum data set for new RoleMember
return &types.RoleMember{
RoleID: id.Next(),
UserID: id.Next(),
RoleID: id.Next(),
UserID: id.Next(),
}
}
@@ -62,7 +62,7 @@ func testRoleMembers(t *testing.T, s store.RoleMembers) {
req.Len(roleMembers, 0)
})
t.Run("by RoleID and UserID", func(t *testing.T) {
t.Run("by RoleID and OwnerID", func(t *testing.T) {
req, roleMember := truncAndCreate(t)
req.NoError(s.DeleteRoleMemberByUserIDRoleID(ctx, roleMember.UserID, roleMember.RoleID))
roleMembers, _, _ := s.SearchRoleMembers(ctx, types.RoleMemberFilter{UserID: roleMember.UserID, RoleID: roleMember.RoleID})
@@ -75,14 +75,14 @@ func testRoleMembers(t *testing.T, s store.RoleMembers) {
// newID := id.Next()
// roleMember = &types.RoleMember{
// UserID: roleMember.UserID,
// OwnerID: roleMember.OwnerID,
// RoleID: newID,
// }
// req.NoError(s.UpdateRoleMember(ctx, roleMember))
// updated, f, err := s.SearchRoleMembers(ctx, types.RoleMemberFilter{UserID: roleMember.UserID})
// updated, f, err := s.SearchRoleMembers(ctx, types.RoleMemberFilter{OwnerID: roleMember.OwnerID})
// req.NoError(err)
// req.Equal(updated[0].UserID, f.UserID)
// req.Equal(updated[0].OwnerID, f.OwnerID)
// })
// t.Run("search", func(t *testing.T) {