diff --git a/messaging/repository/attachment.go b/messaging/repository/attachment.go index b6217cc7e..6bce36d29 100644 --- a/messaging/repository/attachment.go +++ b/messaging/repository/attachment.go @@ -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 diff --git a/messaging/repository/channel.go b/messaging/repository/channel.go index 4743eaeb6..af3bd23cd 100644 --- a/messaging/repository/channel.go +++ b/messaging/repository/channel.go @@ -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) } diff --git a/messaging/service/attachment.go b/messaging/service/attachment.go index 3ffd386e2..4c8d5c08b 100644 --- a/messaging/service/attachment.go +++ b/messaging/service/attachment.go @@ -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) diff --git a/messaging/service/attachment_actions.gen.go b/messaging/service/attachment_actions.gen.go index 25a1ed805..c285fa5ba 100644 --- a/messaging/service/attachment_actions.gen.go +++ b/messaging/service/attachment_actions.gen.go @@ -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)) } diff --git a/messaging/service/attachment_actions.yaml b/messaging/service/attachment_actions.yaml index 9740c61ea..28f9a8cd1 100644 --- a/messaging/service/attachment_actions.yaml +++ b/messaging/service/attachment_actions.yaml @@ -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 ] diff --git a/messaging/service/message.go b/messaging/service/message.go index 4aa021891..994b4dde0 100644 --- a/messaging/service/message.go +++ b/messaging/service/message.go @@ -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 } } diff --git a/messaging/types/attachment.go b/messaging/types/attachment.go index 37a4de642..fefcc015a 100644 --- a/messaging/types/attachment.go +++ b/messaging/types/attachment.go @@ -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 { diff --git a/messaging/types/channel.go b/messaging/types/channel.go index d21af7620..6b7fc54b2 100644 --- a/messaging/types/channel.go +++ b/messaging/types/channel.go @@ -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 diff --git a/messaging/types/mention_test.go b/messaging/types/mention_test.go index c02844518..08536015b 100644 --- a/messaging/types/mention_test.go +++ b/messaging/types/mention_test.go @@ -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") } diff --git a/messaging/types/type_set.gen.go b/messaging/types/type_set.gen.go index d616c179d..498699193 100644 --- a/messaging/types/type_set.gen.go +++ b/messaging/types/type_set.gen.go @@ -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. diff --git a/messaging/types/type_set.gen_test.go b/messaging/types/type_set.gen_test.go index 1e80462a6..f096e4b90 100644 --- a/messaging/types/type_set.gen_test.go +++ b/messaging/types/type_set.gen_test.go @@ -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) diff --git a/messaging/types/types.yaml b/messaging/types/types.yaml index 133694584..67bc46609 100644 --- a/messaging/types/types.yaml +++ b/messaging/types/types.yaml @@ -1,5 +1,5 @@ types: - MessageAttachment: + Attachment: Mention: MessageFlag: Message: diff --git a/pkg/ngimporter/main.go b/pkg/ngimporter/main.go index 77f31c60b..218572f20 100644 --- a/pkg/ngimporter/main.go +++ b/pkg/ngimporter/main.go @@ -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 diff --git a/pkg/payload/outgoing.go b/pkg/payload/outgoing.go index b7039331d..d8dc5af19 100644 --- a/pkg/payload/outgoing.go +++ b/pkg/payload/outgoing.go @@ -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, diff --git a/store/interfaces.gen.go b/store/interfaces.gen.go index 64dcf3c1b..ff3d41ff0 100644 --- a/store/interfaces.gen.go +++ b/store/interfaces.gen.go @@ -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 diff --git a/store/messaging_attachments.gen.go b/store/messaging_attachments.gen.go new file mode 100644 index 000000000..637938ba8 --- /dev/null +++ b/store/messaging_attachments.gen.go @@ -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) +} diff --git a/store/messaging_attachments.yaml b/store/messaging_attachments.yaml new file mode 100644 index 000000000..683260356 --- /dev/null +++ b/store/messaging_attachments.yaml @@ -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 diff --git a/store/messaging_channel_members.gen.go b/store/messaging_channel_members.gen.go new file mode 100644 index 000000000..3dc77b698 --- /dev/null +++ b/store/messaging_channel_members.gen.go @@ -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) +} diff --git a/store/messaging_channel_members.yaml b/store/messaging_channel_members.yaml new file mode 100644 index 000000000..05f6de879 --- /dev/null +++ b/store/messaging_channel_members.yaml @@ -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 diff --git a/store/messaging_channels.gen.go b/store/messaging_channels.gen.go new file mode 100644 index 000000000..a6170c32e --- /dev/null +++ b/store/messaging_channels.gen.go @@ -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) +} diff --git a/store/messaging_channels.yaml b/store/messaging_channels.yaml new file mode 100644 index 000000000..7d152d629 --- /dev/null +++ b/store/messaging_channels.yaml @@ -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 diff --git a/store/messaging_messages.gen.go b/store/messaging_messages.gen.go new file mode 100644 index 000000000..8942b8b69 --- /dev/null +++ b/store/messaging_messages.gen.go @@ -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) +} diff --git a/store/messaging_messages.yaml b/store/messaging_messages.yaml new file mode 100644 index 000000000..50a4a713f --- /dev/null +++ b/store/messaging_messages.yaml @@ -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 diff --git a/store/messaging_unread.gen.go b/store/messaging_unread.gen.go new file mode 100644 index 000000000..120cb7c13 --- /dev/null +++ b/store/messaging_unread.gen.go @@ -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) +} diff --git a/store/messaging_unread.yaml b/store/messaging_unread.yaml new file mode 100644 index 000000000..9ddfedd97 --- /dev/null +++ b/store/messaging_unread.yaml @@ -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 diff --git a/store/rdbms/generic_upgrades.go b/store/rdbms/generic_upgrades.go index fece789be..3077add5c 100644 --- a/store/rdbms/generic_upgrades.go +++ b/store/rdbms/generic_upgrades.go @@ -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 +} diff --git a/store/rdbms/messaging_attachments.gen.go b/store/rdbms/messaging_attachments.gen.go new file mode 100644 index 000000000..cffbedc7e --- /dev/null +++ b/store/rdbms/messaging_attachments.gen.go @@ -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 +} diff --git a/store/rdbms/messaging_attachments.go b/store/rdbms/messaging_attachments.go new file mode 100644 index 000000000..f9b9529d9 --- /dev/null +++ b/store/rdbms/messaging_attachments.go @@ -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 +} diff --git a/store/rdbms/messaging_channel_members.gen.go b/store/rdbms/messaging_channel_members.gen.go new file mode 100644 index 000000000..89b3103d7 --- /dev/null +++ b/store/rdbms/messaging_channel_members.gen.go @@ -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 +} diff --git a/store/rdbms/messaging_channels.gen.go b/store/rdbms/messaging_channels.gen.go new file mode 100644 index 000000000..343fdea62 --- /dev/null +++ b/store/rdbms/messaging_channels.gen.go @@ -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 +} diff --git a/store/rdbms/messaging_messages.gen.go b/store/rdbms/messaging_messages.gen.go new file mode 100644 index 000000000..2fbf0fc60 --- /dev/null +++ b/store/rdbms/messaging_messages.gen.go @@ -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 +} diff --git a/store/rdbms/messaging_unread.gen.go b/store/rdbms/messaging_unread.gen.go new file mode 100644 index 000000000..7f88cc837 --- /dev/null +++ b/store/rdbms/messaging_unread.gen.go @@ -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 +} diff --git a/store/rdbms/rdbms_schema.go b/store/rdbms/rdbms_schema.go index d57676811..32e9af0fb 100644 --- a/store/rdbms/rdbms_schema.go +++ b/store/rdbms/rdbms_schema.go @@ -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), diff --git a/store/tests/gen_test.go b/store/tests/gen_test.go index 43c092e40..50dde2c40 100644 --- a/store/tests/gen_test.go +++ b/store/tests/gen_test.go @@ -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) diff --git a/store/tests/role_members_test.go b/store/tests/role_members_test.go index 481f1e0ba..66e688435 100644 --- a/store/tests/role_members_test.go +++ b/store/tests/role_members_test.go @@ -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) {