Received: from mail.netlandish.com (mail.netlandish.com [174.136.98.166])
	by code.netlandish.com (Postfix) with ESMTP id 07A00162
	for <~netlandish/links-dev@lists.code.netlandish.com>; Wed, 21 May 2025 18:55:02 +0000 (UTC)
Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.219.169; helo=mail-yb1-f169.google.com; envelope-from=peter@netlandish.com; receiver=<UNKNOWN> 
Authentication-Results: mail.netlandish.com;
	dkim=pass (1024-bit key; unprotected) header.d=netlandish.com header.i=@netlandish.com header.b=mc8KbCTt
Received: from mail-yb1-f169.google.com (mail-yb1-f169.google.com [209.85.219.169])
	by mail.netlandish.com (Postfix) with ESMTP id B8C241D6462
	for <~netlandish/links-dev@lists.code.netlandish.com>; Wed, 21 May 2025 18:55:20 +0000 (UTC)
Received: by mail-yb1-f169.google.com with SMTP id 3f1490d57ef6-e7d664bcd34so620497276.0
        for <~netlandish/links-dev@lists.code.netlandish.com>; Wed, 21 May 2025 11:55:20 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=netlandish.com; s=google; t=1747853719; x=1748458519; darn=lists.code.netlandish.com;
        h=content-transfer-encoding:mime-version:message-id:date:subject:cc
         :to:from:from:to:cc:subject:date:message-id:reply-to;
        bh=nD3Atxlpdy7FHibkLQbahFNunHhnXea4XqREvXQWkD4=;
        b=mc8KbCTtOmlwJHPbCUTW+QsRSST3qaYUw8KLM6sFRGxYqJA193ouWsE+AYaU1ceexr
         WcPLnloAmLQD93iq3cuWMNmxs0f04Md9aU9AHVtTX4RFCzoYJVZKrhJFeAsZts+bmu4a
         //p/+jSpXgLUfa01507IpcWqDPt4WnIEtZXgo=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20230601; t=1747853719; x=1748458519;
        h=content-transfer-encoding:mime-version:message-id:date:subject:cc
         :to:from:x-gm-message-state:from:to:cc:subject:date:message-id
         :reply-to;
        bh=nD3Atxlpdy7FHibkLQbahFNunHhnXea4XqREvXQWkD4=;
        b=gXK54EgHZnh7SA6mHm3XbB5ToQxO2dii1odpmgYmJSNdUzROWGZTtYn27uESvlCYyh
         +r1vryOCtPR2r+IuSz8s4dxZZ98dFg7cuWBu/6F469vFqxxeGKlztZMUGC6CHwTc+2N6
         LiVDRyMkqVPMWG0BNv+ygqfbM6jlDrVr+ju1r/FGJJgx4zQTwD4EcFPqLm3rBN6Er4ZR
         L/+5wNWvTX7WpNRewPlnL5FVpO73j/BeGuDyEuDrp4WSe/o+HL1CqHNCUaOmqrHU5jYY
         uPTTb3HzdjGKd3gkcUCmxtwbs1ClbSjePJSRFAQlbw6bCGRVIf+esF/FLcRFY3lDyCtj
         Jttw==
X-Gm-Message-State: AOJu0YyJcsklOrcL/MNBX8lrqazVPk5/sA8QqAAWBORIiygk3EwA24G4
	RIp2gAEqTMPB0y/N89zkTdKS9v7i1KKoI0NsvgVaw9SqdyNw79eQE/spkai7268A4fOrfKCxTrR
	VtODXRlw/9TwT
X-Gm-Gg: ASbGncsPzXNfXQ4f51MjHD93IgEhw2PKxuTcwMV6yEJsiXNsawdGoTnoEScqvYsP9Bj
	B5HF8egmdf2e7xflT6tTiUTHRB0ZpUmeX9BytABnHPQizqwhePNc3+jR1hSICB7CKhV4TqDglpT
	M18puhoLUGTwleAcs4sRG77xlIFyx2k4wf5LkY0Llm/0FbabWceOj12EGDg06rODEEOICjAlSZo
	EjAzsoWK0HBTvW72XqNxvYv1emFgRmIIp+ARFP7421NjlatpA4PRdSjhT/UTXw82VK++rzShQwB
	l7tPJ5fDMogWBU8D4+mPnEM0nMYoItIKKRtYusVw09eJAByVKQ==
X-Google-Smtp-Source: AGHT+IFvsd1BFg5Nz2dRmjHs4urraVXT2tGVRij0hc0R1ZjXsJK9KHqkdFhgKycaCZPjOwYUzwj5og==
X-Received: by 2002:a05:6902:6c17:b0:e7b:6915:de20 with SMTP id 3f1490d57ef6-e7b6a42cb6dmr26413085276.42.1747853719406;
        Wed, 21 May 2025 11:55:19 -0700 (PDT)
Received: from localhost ([2800:e2:37f:ee6c:b36f:76e4:f6f8:a062])
        by smtp.gmail.com with ESMTPSA id 3f1490d57ef6-e7b6acb1ed4sm4139654276.30.2025.05.21.11.55.18
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Wed, 21 May 2025 11:55:18 -0700 (PDT)
From: Peter Sanchez <peter@netlandish.com>
To: ~netlandish/links-dev@lists.code.netlandish.com
Cc: Peter Sanchez <peter@netlandish.com>
Subject: [PATCH links] Update how base_url counter is updated. This is a more accurate way of dealing with this.
Date: Wed, 21 May 2025 12:55:13 -0600
Message-ID: <20250521185516.12459-1-peter@netlandish.com>
X-Mailer: git-send-email 2.47.2
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

Also always update base_url counter when calling `updateLink` mutation.
Found an edge case where counters were higher than they should be.

Changelog-Changed: How `BaseURL.UpdateCounter` works. Now uses a subselect
  to set proper count
Changelog-Changed: Now will alwyas call `UpdateCounter` when calling the
  `updateLink` mutation. This addresses a small counter bug / edge case.
---
 api/graph/schema.resolvers.go | 61 ++++++++++++++++++-----------------
 models/base_url.go            | 21 ++++++------
 2 files changed, 42 insertions(+), 40 deletions(-)

diff --git a/api/graph/schema.resolvers.go b/api/graph/schema.resolvers.go
index 18a5734..8bd3f3d 100644
--- a/api/graph/schema.resolvers.go
+++ b/api/graph/schema.resolvers.go
@@ -558,12 +558,9 @@ func (r *mutationResolver) AddLink(ctx context.Context, input *model.LinkInput)
 		}
 	}
 
-	// If the link if public, add +1 to the base url counter
-	if OrgLink.Visibility == models.OrgLinkVisibilityPublic {
-		err = BaseURL.UpdateCounter(ctx, true)
-		if err != nil {
-			return nil, err
-		}
+	err = BaseURL.UpdateCounter(ctx)
+	if err != nil {
+		return nil, err
 	}
 
 	c := server.EchoForContext(ctx)
@@ -665,6 +662,8 @@ func (r *mutationResolver) UpdateLink(ctx context.Context, input *model.UpdateLi
 	}
 	srv := server.ForContext(ctx)
 
+	var BaseURL *models.BaseURL
+
 	// If the input has changed
 	if input.URL != nil {
 		if orgLink.Type == models.NoteType {
@@ -673,7 +672,7 @@ func (r *mutationResolver) UpdateLink(ctx context.Context, input *model.UpdateLi
 				WithCode(valid.ErrValidationCode)
 			return nil, nil
 		}
-		BaseURL := &models.BaseURL{
+		BaseURL = &models.BaseURL{
 			URL: links.StripURLFragment(*input.URL),
 		}
 		err = BaseURL.Store(ctx)
@@ -699,17 +698,13 @@ func (r *mutationResolver) UpdateLink(ctx context.Context, input *model.UpdateLi
 			return nil, nil
 		} else if string(*input.Visibility) == models.OrgLinkVisibilityPublic && orgLink.Type == models.NoteType {
 			// NOTE: when making a note public we want to process its url and creata a base url obj
-			BaseURL := &models.BaseURL{
+			BaseURL = &models.BaseURL{
 				URL: orgLink.URL,
 			}
 			err = BaseURL.Store(ctx)
 			if err != nil {
 				return nil, err
 			}
-			err = BaseURL.UpdateCounter(ctx, true)
-			if err != nil {
-				return nil, err
-			}
 			srv.QueueTask("general", core.ParseBaseURLTask(srv, BaseURL, nil))
 		}
 		orgLink.Visibility = string(*input.Visibility)
@@ -773,6 +768,19 @@ func (r *mutationResolver) UpdateLink(ctx context.Context, input *model.UpdateLi
 		}
 	}
 
+	// Update BaseURL counter
+	if BaseURL == nil {
+		BaseURL = &models.BaseURL{ID: orgLink.BaseURLID}
+		err := BaseURL.Load(ctx)
+		if err != nil {
+			return nil, err
+		}
+	}
+	err = BaseURL.UpdateCounter(ctx)
+	if err != nil {
+		return nil, err
+	}
+
 	c := server.EchoForContext(ctx)
 	mdata := make(map[string]any)
 	mdata["org_id"] = org.ID
@@ -860,23 +868,20 @@ func (r *mutationResolver) DeleteLink(ctx context.Context, hash string) (*model.
 	}
 
 	deletedID := link.Hash
-	visibility := link.Visibility
 	baseURLID := link.BaseURLID
 	err = link.Delete(ctx)
 	if err != nil {
 		return nil, err
 	}
-	// If the link if public, add +1 to the base url counter
-	if visibility == models.OrgLinkVisibilityPublic {
-		baseURL := &models.BaseURL{ID: baseURLID}
-		err = baseURL.Load(ctx)
-		if err != nil {
-			return nil, err
-		}
-		err = baseURL.UpdateCounter(ctx, false)
-		if err != nil {
-			return nil, err
-		}
+
+	baseURL := &models.BaseURL{ID: baseURLID}
+	err = baseURL.Load(ctx)
+	if err != nil {
+		return nil, err
+	}
+	err = baseURL.UpdateCounter(ctx)
+	if err != nil {
+		return nil, err
 	}
 
 	c := server.EchoForContext(ctx)
@@ -1001,11 +1006,9 @@ func (r *mutationResolver) AddNote(ctx context.Context, input *model.NoteInput)
 		return nil, err
 	}
 
-	if string(input.Visibility) == models.OrgLinkVisibilityPublic {
-		err = BaseURL.UpdateCounter(ctx, true)
-		if err != nil {
-			return nil, err
-		}
+	err = BaseURL.UpdateCounter(ctx)
+	if err != nil {
+		return nil, err
 	}
 
 	OrgLinkNote := &models.OrgLink{
diff --git a/models/base_url.go b/models/base_url.go
index b552287..affaa04 100644
--- a/models/base_url.go
+++ b/models/base_url.go
@@ -220,23 +220,22 @@ func (b *BaseURL) ToLocalTZ(tz string) error {
 }
 
 // UpdateCounter ...
-func (b *BaseURL) UpdateCounter(ctx context.Context, add bool) error {
-	// XXX Probably should change this to just use a subselect count(*)
-	op := "+"
-	if !add {
-		op = "-"
-	}
-	query := fmt.Sprintf(`
+func (b *BaseURL) UpdateCounter(ctx context.Context) error {
+	query := `
 		UPDATE base_urls
-		SET counter = counter%s1
+		SET counter = (
+			SELECT count(*)
+			FROM org_links
+			WHERE base_url_id=$1
+			AND visibility='PUBLIC'
+		)
 		WHERE id = $1
 		RETURNING (updated_on)
-	`, op)
-	err := database.WithTx(ctx, nil, func(tx *sql.Tx) error {
+	`
+	return database.WithTx(ctx, nil, func(tx *sql.Tx) error {
 		row := tx.QueryRowContext(ctx, query, b.ID)
 		return row.Scan(&b.UpdatedOn)
 	})
-	return err
 }
 
 // TagsToString will convert linked tags to a comma separated string (used in forms)
-- 
2.47.2

