Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
|
|
@ -0,0 +1,56 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
|
||||
domaintenant "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/tenant"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/repository/tenant/models"
|
||||
)
|
||||
|
||||
// Create creates a new tenant
|
||||
// Uses batched writes to maintain consistency across denormalized tables
|
||||
func (r *repository) Create(ctx context.Context, t *domaintenant.Tenant) error {
|
||||
// Convert to table models
|
||||
tenantByID := models.FromTenant(t)
|
||||
tenantBySlug := models.FromTenantBySlug(t)
|
||||
tenantByStatus := models.FromTenantByStatus(t)
|
||||
|
||||
// Create batch for atomic write
|
||||
batch := r.session.NewBatch(gocql.LoggedBatch)
|
||||
|
||||
// Insert into tenants_by_id table
|
||||
batch.Query(`INSERT INTO tenants_by_id (id, name, slug, status, created_at, updated_at,
|
||||
created_from_ip_address, created_from_ip_timestamp, modified_from_ip_address, modified_from_ip_timestamp)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
tenantByID.ID, tenantByID.Name, tenantByID.Slug, tenantByID.Status,
|
||||
tenantByID.CreatedAt, tenantByID.UpdatedAt,
|
||||
tenantByID.CreatedFromIPAddress, tenantByID.CreatedFromIPTimestamp,
|
||||
tenantByID.ModifiedFromIPAddress, tenantByID.ModifiedFromIPTimestamp)
|
||||
|
||||
// Insert into tenants_by_slug table
|
||||
batch.Query(`INSERT INTO tenants_by_slug (slug, id, name, status, created_at, updated_at,
|
||||
created_from_ip_address, created_from_ip_timestamp, modified_from_ip_address, modified_from_ip_timestamp)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
tenantBySlug.Slug, tenantBySlug.ID, tenantBySlug.Name, tenantBySlug.Status,
|
||||
tenantBySlug.CreatedAt, tenantBySlug.UpdatedAt,
|
||||
tenantBySlug.CreatedFromIPAddress, tenantBySlug.CreatedFromIPTimestamp,
|
||||
tenantBySlug.ModifiedFromIPAddress, tenantBySlug.ModifiedFromIPTimestamp)
|
||||
|
||||
// Insert into tenants_by_status table
|
||||
batch.Query(`INSERT INTO tenants_by_status (status, id, name, slug, created_at, updated_at,
|
||||
created_from_ip_address, created_from_ip_timestamp, modified_from_ip_address, modified_from_ip_timestamp)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
tenantByStatus.Status, tenantByStatus.ID, tenantByStatus.Name, tenantByStatus.Slug,
|
||||
tenantByStatus.CreatedAt, tenantByStatus.UpdatedAt,
|
||||
tenantByStatus.CreatedFromIPAddress, tenantByStatus.CreatedFromIPTimestamp,
|
||||
tenantByStatus.ModifiedFromIPAddress, tenantByStatus.ModifiedFromIPTimestamp)
|
||||
|
||||
// Execute batch
|
||||
if err := r.session.ExecuteBatch(batch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Delete deletes a tenant from all tables
|
||||
// Uses batched writes to maintain consistency across denormalized tables
|
||||
// Note: Consider implementing soft delete (status = 'deleted') instead
|
||||
func (r *repository) Delete(ctx context.Context, id string) error {
|
||||
// First, get the tenant to retrieve the slug and status
|
||||
// (needed to delete from tenants_by_slug and tenants_by_status tables)
|
||||
tenant, err := r.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create batch for atomic delete
|
||||
batch := r.session.NewBatch(gocql.LoggedBatch)
|
||||
|
||||
// Delete from tenants_by_id table
|
||||
batch.Query(`DELETE FROM tenants_by_id WHERE id = ?`, id)
|
||||
|
||||
// Delete from tenants_by_slug table
|
||||
batch.Query(`DELETE FROM tenants_by_slug WHERE slug = ?`, tenant.Slug)
|
||||
|
||||
// Delete from tenants_by_status table
|
||||
batch.Query(`DELETE FROM tenants_by_status WHERE status = ? AND id = ?`,
|
||||
string(tenant.Status), id)
|
||||
|
||||
// Execute batch
|
||||
if err := r.session.ExecuteBatch(batch); err != nil {
|
||||
r.logger.Error("failed to delete tenant",
|
||||
zap.String("tenant_id", id),
|
||||
zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
62
cloud/maplepress-backend/internal/repository/tenant/get.go
Normal file
62
cloud/maplepress-backend/internal/repository/tenant/get.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
|
||||
domaintenant "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/tenant"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/repository/tenant/models"
|
||||
)
|
||||
|
||||
// GetByID retrieves a tenant by ID
|
||||
func (r *repository) GetByID(ctx context.Context, id string) (*domaintenant.Tenant, error) {
|
||||
var tenantByID models.TenantByID
|
||||
|
||||
query := `SELECT id, name, slug, status, created_at, updated_at,
|
||||
created_from_ip_address, created_from_ip_timestamp, modified_from_ip_address, modified_from_ip_timestamp
|
||||
FROM tenants_by_id
|
||||
WHERE id = ?`
|
||||
|
||||
err := r.session.Query(query, id).
|
||||
Consistency(gocql.Quorum).
|
||||
Scan(&tenantByID.ID, &tenantByID.Name, &tenantByID.Slug, &tenantByID.Status,
|
||||
&tenantByID.CreatedAt, &tenantByID.UpdatedAt,
|
||||
&tenantByID.CreatedFromIPAddress, &tenantByID.CreatedFromIPTimestamp,
|
||||
&tenantByID.ModifiedFromIPAddress, &tenantByID.ModifiedFromIPTimestamp)
|
||||
|
||||
if err != nil {
|
||||
if err == gocql.ErrNotFound {
|
||||
return nil, domaintenant.ErrTenantNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tenantByID.ToTenant(), nil
|
||||
}
|
||||
|
||||
// GetBySlug retrieves a tenant by slug
|
||||
func (r *repository) GetBySlug(ctx context.Context, slug string) (*domaintenant.Tenant, error) {
|
||||
var tenantBySlug models.TenantBySlug
|
||||
|
||||
query := `SELECT slug, id, name, status, created_at, updated_at,
|
||||
created_from_ip_address, created_from_ip_timestamp, modified_from_ip_address, modified_from_ip_timestamp
|
||||
FROM tenants_by_slug
|
||||
WHERE slug = ?`
|
||||
|
||||
err := r.session.Query(query, slug).
|
||||
Consistency(gocql.Quorum).
|
||||
Scan(&tenantBySlug.Slug, &tenantBySlug.ID, &tenantBySlug.Name, &tenantBySlug.Status,
|
||||
&tenantBySlug.CreatedAt, &tenantBySlug.UpdatedAt,
|
||||
&tenantBySlug.CreatedFromIPAddress, &tenantBySlug.CreatedFromIPTimestamp,
|
||||
&tenantBySlug.ModifiedFromIPAddress, &tenantBySlug.ModifiedFromIPTimestamp)
|
||||
|
||||
if err != nil {
|
||||
if err == gocql.ErrNotFound {
|
||||
return nil, domaintenant.ErrTenantNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tenantBySlug.ToTenant(), nil
|
||||
}
|
||||
21
cloud/maplepress-backend/internal/repository/tenant/impl.go
Normal file
21
cloud/maplepress-backend/internal/repository/tenant/impl.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"github.com/gocql/gocql"
|
||||
"go.uber.org/zap"
|
||||
|
||||
domaintenant "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/tenant"
|
||||
)
|
||||
|
||||
type repository struct {
|
||||
session *gocql.Session
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// ProvideRepository creates a new tenant repository
|
||||
func ProvideRepository(session *gocql.Session, logger *zap.Logger) domaintenant.Repository {
|
||||
return &repository{
|
||||
session: session,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
37
cloud/maplepress-backend/internal/repository/tenant/list.go
Normal file
37
cloud/maplepress-backend/internal/repository/tenant/list.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
|
||||
domaintenant "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/tenant"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/repository/tenant/models"
|
||||
)
|
||||
|
||||
// List retrieves all tenants (paginated)
|
||||
// Note: This is a table scan and should be used sparingly in production
|
||||
// Consider adding a tenants_by_status table for filtered queries
|
||||
func (r *repository) List(ctx context.Context, limit int) ([]*domaintenant.Tenant, error) {
|
||||
query := `SELECT id, name, slug, status, created_at, updated_at
|
||||
FROM tenants_by_id
|
||||
LIMIT ?`
|
||||
|
||||
iter := r.session.Query(query, limit).
|
||||
Consistency(gocql.Quorum).
|
||||
Iter()
|
||||
|
||||
var tenants []*domaintenant.Tenant
|
||||
var tenantByID models.TenantByID
|
||||
|
||||
for iter.Scan(&tenantByID.ID, &tenantByID.Name, &tenantByID.Slug, &tenantByID.Status,
|
||||
&tenantByID.CreatedAt, &tenantByID.UpdatedAt) {
|
||||
tenants = append(tenants, tenantByID.ToTenant())
|
||||
}
|
||||
|
||||
if err := iter.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tenants, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
|
||||
domaintenant "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/tenant"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/repository/tenant/models"
|
||||
)
|
||||
|
||||
// ListByStatus retrieves all tenants with the specified status (paginated)
|
||||
// Uses the tenants_by_status table for efficient filtering
|
||||
func (r *repository) ListByStatus(ctx context.Context, status domaintenant.Status, limit int) ([]*domaintenant.Tenant, error) {
|
||||
query := `SELECT status, id, name, slug, created_at, updated_at,
|
||||
created_from_ip_address, created_from_ip_timestamp, modified_from_ip_address, modified_from_ip_timestamp
|
||||
FROM tenants_by_status
|
||||
WHERE status = ?
|
||||
LIMIT ?`
|
||||
|
||||
iter := r.session.Query(query, string(status), limit).
|
||||
Consistency(gocql.Quorum).
|
||||
Iter()
|
||||
|
||||
var tenants []*domaintenant.Tenant
|
||||
var tenantByStatus models.TenantByStatus
|
||||
|
||||
for iter.Scan(&tenantByStatus.Status, &tenantByStatus.ID, &tenantByStatus.Name, &tenantByStatus.Slug,
|
||||
&tenantByStatus.CreatedAt, &tenantByStatus.UpdatedAt,
|
||||
&tenantByStatus.CreatedFromIPAddress, &tenantByStatus.CreatedFromIPTimestamp,
|
||||
&tenantByStatus.ModifiedFromIPAddress, &tenantByStatus.ModifiedFromIPTimestamp) {
|
||||
tenants = append(tenants, tenantByStatus.ToTenant())
|
||||
}
|
||||
|
||||
if err := iter.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tenants, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/tenant"
|
||||
)
|
||||
|
||||
// TenantByID represents the tenants_by_id table
|
||||
// Query pattern: Get tenant by ID
|
||||
// Primary key: id
|
||||
type TenantByID struct {
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Slug string `db:"slug"`
|
||||
Status string `db:"status"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
|
||||
// CWE-359: IP address tracking for GDPR compliance
|
||||
CreatedFromIPAddress string `db:"created_from_ip_address"`
|
||||
CreatedFromIPTimestamp time.Time `db:"created_from_ip_timestamp"`
|
||||
ModifiedFromIPAddress string `db:"modified_from_ip_address"`
|
||||
ModifiedFromIPTimestamp time.Time `db:"modified_from_ip_timestamp"`
|
||||
}
|
||||
|
||||
// ToTenant converts table model to domain entity
|
||||
func (t *TenantByID) ToTenant() *tenant.Tenant {
|
||||
return &tenant.Tenant{
|
||||
ID: t.ID,
|
||||
Name: t.Name,
|
||||
Slug: t.Slug,
|
||||
Status: tenant.Status(t.Status),
|
||||
CreatedAt: t.CreatedAt,
|
||||
UpdatedAt: t.UpdatedAt,
|
||||
|
||||
// CWE-359: IP address tracking
|
||||
CreatedFromIPAddress: t.CreatedFromIPAddress,
|
||||
CreatedFromIPTimestamp: t.CreatedFromIPTimestamp,
|
||||
ModifiedFromIPAddress: t.ModifiedFromIPAddress,
|
||||
ModifiedFromIPTimestamp: t.ModifiedFromIPTimestamp,
|
||||
}
|
||||
}
|
||||
|
||||
// FromTenant converts domain entity to table model
|
||||
func FromTenant(t *tenant.Tenant) *TenantByID {
|
||||
return &TenantByID{
|
||||
ID: t.ID,
|
||||
Name: t.Name,
|
||||
Slug: t.Slug,
|
||||
Status: string(t.Status),
|
||||
CreatedAt: t.CreatedAt,
|
||||
UpdatedAt: t.UpdatedAt,
|
||||
|
||||
// CWE-359: IP address tracking
|
||||
CreatedFromIPAddress: t.CreatedFromIPAddress,
|
||||
CreatedFromIPTimestamp: t.CreatedFromIPTimestamp,
|
||||
ModifiedFromIPAddress: t.ModifiedFromIPAddress,
|
||||
ModifiedFromIPTimestamp: t.ModifiedFromIPTimestamp,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/tenant"
|
||||
)
|
||||
|
||||
// TenantBySlug represents the tenants_by_slug table
|
||||
// Query pattern: Get tenant by slug (URL-friendly identifier)
|
||||
// Primary key: slug
|
||||
type TenantBySlug struct {
|
||||
Slug string `db:"slug"`
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Status string `db:"status"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
|
||||
// CWE-359: IP address tracking for GDPR compliance
|
||||
CreatedFromIPAddress string `db:"created_from_ip_address"`
|
||||
CreatedFromIPTimestamp time.Time `db:"created_from_ip_timestamp"`
|
||||
ModifiedFromIPAddress string `db:"modified_from_ip_address"`
|
||||
ModifiedFromIPTimestamp time.Time `db:"modified_from_ip_timestamp"`
|
||||
}
|
||||
|
||||
// ToTenant converts table model to domain entity
|
||||
func (t *TenantBySlug) ToTenant() *tenant.Tenant {
|
||||
return &tenant.Tenant{
|
||||
ID: t.ID,
|
||||
Name: t.Name,
|
||||
Slug: t.Slug,
|
||||
Status: tenant.Status(t.Status),
|
||||
CreatedAt: t.CreatedAt,
|
||||
UpdatedAt: t.UpdatedAt,
|
||||
|
||||
// CWE-359: IP address tracking
|
||||
CreatedFromIPAddress: t.CreatedFromIPAddress,
|
||||
CreatedFromIPTimestamp: t.CreatedFromIPTimestamp,
|
||||
ModifiedFromIPAddress: t.ModifiedFromIPAddress,
|
||||
ModifiedFromIPTimestamp: t.ModifiedFromIPTimestamp,
|
||||
}
|
||||
}
|
||||
|
||||
// FromTenantBySlug converts domain entity to table model
|
||||
func FromTenantBySlug(t *tenant.Tenant) *TenantBySlug {
|
||||
return &TenantBySlug{
|
||||
Slug: t.Slug,
|
||||
ID: t.ID,
|
||||
Name: t.Name,
|
||||
Status: string(t.Status),
|
||||
CreatedAt: t.CreatedAt,
|
||||
UpdatedAt: t.UpdatedAt,
|
||||
|
||||
// CWE-359: IP address tracking
|
||||
CreatedFromIPAddress: t.CreatedFromIPAddress,
|
||||
CreatedFromIPTimestamp: t.CreatedFromIPTimestamp,
|
||||
ModifiedFromIPAddress: t.ModifiedFromIPAddress,
|
||||
ModifiedFromIPTimestamp: t.ModifiedFromIPTimestamp,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/tenant"
|
||||
)
|
||||
|
||||
// TenantByStatus represents the tenants_by_status table
|
||||
// Query pattern: List tenants by status (e.g., active, inactive, suspended)
|
||||
// Primary key: (status, id) - status is partition key, id is clustering key
|
||||
type TenantByStatus struct {
|
||||
Status string `db:"status"`
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Slug string `db:"slug"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
|
||||
// CWE-359: IP address tracking for GDPR compliance
|
||||
CreatedFromIPAddress string `db:"created_from_ip_address"`
|
||||
CreatedFromIPTimestamp time.Time `db:"created_from_ip_timestamp"`
|
||||
ModifiedFromIPAddress string `db:"modified_from_ip_address"`
|
||||
ModifiedFromIPTimestamp time.Time `db:"modified_from_ip_timestamp"`
|
||||
}
|
||||
|
||||
// ToTenant converts table model to domain entity
|
||||
func (t *TenantByStatus) ToTenant() *tenant.Tenant {
|
||||
return &tenant.Tenant{
|
||||
ID: t.ID,
|
||||
Name: t.Name,
|
||||
Slug: t.Slug,
|
||||
Status: tenant.Status(t.Status),
|
||||
CreatedAt: t.CreatedAt,
|
||||
UpdatedAt: t.UpdatedAt,
|
||||
|
||||
// CWE-359: IP address tracking
|
||||
CreatedFromIPAddress: t.CreatedFromIPAddress,
|
||||
CreatedFromIPTimestamp: t.CreatedFromIPTimestamp,
|
||||
ModifiedFromIPAddress: t.ModifiedFromIPAddress,
|
||||
ModifiedFromIPTimestamp: t.ModifiedFromIPTimestamp,
|
||||
}
|
||||
}
|
||||
|
||||
// FromTenantByStatus converts domain entity to table model
|
||||
func FromTenantByStatus(t *tenant.Tenant) *TenantByStatus {
|
||||
return &TenantByStatus{
|
||||
Status: string(t.Status),
|
||||
ID: t.ID,
|
||||
Name: t.Name,
|
||||
Slug: t.Slug,
|
||||
CreatedAt: t.CreatedAt,
|
||||
UpdatedAt: t.UpdatedAt,
|
||||
|
||||
// CWE-359: IP address tracking
|
||||
CreatedFromIPAddress: t.CreatedFromIPAddress,
|
||||
CreatedFromIPTimestamp: t.CreatedFromIPTimestamp,
|
||||
ModifiedFromIPAddress: t.ModifiedFromIPAddress,
|
||||
ModifiedFromIPTimestamp: t.ModifiedFromIPTimestamp,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
|
||||
domaintenant "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/tenant"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/repository/tenant/models"
|
||||
)
|
||||
|
||||
// Update updates an existing tenant
|
||||
// Uses batched writes to maintain consistency across denormalized tables
|
||||
func (r *repository) Update(ctx context.Context, t *domaintenant.Tenant) error {
|
||||
// Get the old tenant to check if status changed
|
||||
oldTenant, err := r.GetByID(ctx, t.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Convert to table models
|
||||
tenantByID := models.FromTenant(t)
|
||||
tenantBySlug := models.FromTenantBySlug(t)
|
||||
tenantByStatus := models.FromTenantByStatus(t)
|
||||
|
||||
// Create batch for atomic write
|
||||
batch := r.session.NewBatch(gocql.LoggedBatch)
|
||||
|
||||
// Update tenants_by_id table
|
||||
batch.Query(`UPDATE tenants_by_id SET name = ?, slug = ?, status = ?, updated_at = ?
|
||||
WHERE id = ?`,
|
||||
tenantByID.Name, tenantByID.Slug, tenantByID.Status, tenantByID.UpdatedAt,
|
||||
tenantByID.ID)
|
||||
|
||||
// Update tenants_by_slug table
|
||||
// Note: If slug changed, we need to delete old slug entry and insert new one
|
||||
// For simplicity, we'll update in place (slug changes require delete + create)
|
||||
batch.Query(`UPDATE tenants_by_slug SET id = ?, name = ?, status = ?, updated_at = ?
|
||||
WHERE slug = ?`,
|
||||
tenantBySlug.ID, tenantBySlug.Name, tenantBySlug.Status, tenantBySlug.UpdatedAt,
|
||||
tenantBySlug.Slug)
|
||||
|
||||
// Handle tenants_by_status table
|
||||
// If status changed, delete from old partition and insert into new one
|
||||
if oldTenant.Status != t.Status {
|
||||
// Delete from old status partition
|
||||
batch.Query(`DELETE FROM tenants_by_status WHERE status = ? AND id = ?`,
|
||||
string(oldTenant.Status), t.ID)
|
||||
// Insert into new status partition
|
||||
batch.Query(`INSERT INTO tenants_by_status (status, id, name, slug, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?)`,
|
||||
tenantByStatus.Status, tenantByStatus.ID, tenantByStatus.Name, tenantByStatus.Slug,
|
||||
tenantByStatus.CreatedAt, tenantByStatus.UpdatedAt)
|
||||
} else {
|
||||
// Status didn't change, just update in place
|
||||
batch.Query(`UPDATE tenants_by_status SET name = ?, slug = ?, updated_at = ?
|
||||
WHERE status = ? AND id = ?`,
|
||||
tenantByStatus.Name, tenantByStatus.Slug, tenantByStatus.UpdatedAt,
|
||||
tenantByStatus.Status, tenantByStatus.ID)
|
||||
}
|
||||
|
||||
// Execute batch
|
||||
if err := r.session.ExecuteBatch(batch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue