Received: from mail.netlandish.com (mail.netlandish.com [174.136.98.166])
	by code.netlandish.com (Postfix) with ESMTP id 12740352
	for <~netlandish/links-dev@lists.code.netlandish.com>; Thu, 26 Feb 2026 13:54:42 +0000 (UTC)
Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=74.125.224.67; helo=mail-yx1-f67.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=ZWL/cFQ8
Received: from mail-yx1-f67.google.com (mail-yx1-f67.google.com [74.125.224.67])
	by mail.netlandish.com (Postfix) with ESMTP id 3534D1D6434
	for <~netlandish/links-dev@lists.code.netlandish.com>; Thu, 26 Feb 2026 13:54:40 +0000 (UTC)
Received: by mail-yx1-f67.google.com with SMTP id 956f58d0204a3-64ad9fabd08so981660d50.2
        for <~netlandish/links-dev@lists.code.netlandish.com>; Thu, 26 Feb 2026 05:54:39 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=netlandish.com; s=google; t=1772114079; x=1772718879; 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=fvZMxjfkFoOb7OTwl6dEQLR68Es6Lgb3MSbl6vacJS8=;
        b=ZWL/cFQ8oNXJhAcZBV4Sny9oQ7ELdekY5CckEiatptBH5EYwL3iH0N/J8YBeWfFCFx
         56/PRVvVENyGVs0JmBGPHfu5xYuHzgzP+oFpNlBSYtW19xxL4ilAXwgxYxeJFEem1lGs
         SDAuwfyQDxXm8t5uzclJm95/FRUg8f5kSMeTk=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20230601; t=1772114079; x=1772718879;
        h=content-transfer-encoding:mime-version:message-id:date:subject:cc
         :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date
         :message-id:reply-to;
        bh=fvZMxjfkFoOb7OTwl6dEQLR68Es6Lgb3MSbl6vacJS8=;
        b=wKN1DTnE9bLXQKhojotQlipKh9ZXNb7CmR+n1XSHVl1/M0kI0Vu5oHAoyj81+TygVt
         54P3rDA9Fc/dZpBkzSP/TP1/aKoSmn8XxCtse5xNrJS0JKvcNaKcf3wZeZLvGuM/pnrw
         JCjP+pli85lO2xpwxaxmriHGVcZSZK6h6b4Y8PqQM4brdS5JhUYInPuNs0/MpuLajJQv
         AbLUIiPRIb3/OeGMlr13fV5kP5UevQ7jeCv+0d+6XNIUmTbkdAhFRHaDpQWcJGzyCZ71
         6EaAlr53K7GCSl3n/s/4tfIb/MBh9mnx7N36Olvw8B3cmeoX7Od7uGxASL/qc8yAUJkY
         KNLQ==
X-Gm-Message-State: AOJu0YybELUyizmrMKMSXnUW5lcjWbXNf2X1hmwSX0BM9xTe84BOhyRU
	xgimCsGEIqM9yptX/jz8atc+V28s8Tt8I+OEu6PLDIx0vdyAsHJt8G86IYfTuYVo3XFCJsIXZie
	Y4SFV5SwsCQ==
X-Gm-Gg: ATEYQzzRymqEvSXCsXSvLakH0t89ivwJyfKZjpI7CJee5IfDaZb9TEtAmHTsLB1B90j
	Dkr7ajEOGqW4WIXj65aRw5He/95IV9q6UDQ8z7sEz9ZEUCpK7N4dWnRt4/+QtgAjRwFPWlgQMDY
	dqTXM7IACjRoQC7ZnjiUkfSTTAdlncU2zF4C6SOFMfFBMzduHy2uiKqZ9JC2Jmn7dYgwgSqeRTO
	nfi7yZNl7BlDq7ktu/Q7/G+0yuqHZT/XtXw37ziQ4OaEubZpJYmPlmn740IRka8Q4C0eVoZ3too
	5d5Ua8OsXq1VmW37bi1pzqLd1TSp1FGG8TfDvvSn1bc7TGyVFJgtvdmReBwAO6z8gCuPPi5FhPK
	S1Ju7vCGozi4xmodQv8cHw6+ESbcSwq3xr9h5Dvss9JiM7ysYDbGsIkkKQQo5SAvmRO/y1E0p0Y
	2pQAQ/k2F9GDkudB/rEnfO7hXP7H9pNxUuVSQ=
X-Received: by 2002:a53:d008:0:b0:64a:cee0:fa8 with SMTP id 956f58d0204a3-64c790a7a37mr15529876d50.88.1772114079160;
        Thu, 26 Feb 2026 05:54:39 -0800 (PST)
Received: from localhost ([2803:2d60:1107:87f:1b92:37b1:8826:5b32])
        by smtp.gmail.com with ESMTPSA id 00721157ae682-79876c3fe5asm9012557b3.35.2026.02.26.05.54.38
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Thu, 26 Feb 2026 05:54:38 -0800 (PST)
From: Peter Sanchez <peter@netlandish.com>
To: ~netlandish/links-dev@lists.code.netlandish.com
Cc: Peter Sanchez <peter@netlandish.com>
Subject: [PATCH links] api: fix `createdOn` assignment when fetching tags for individual bookmarks, shorts, listings.
Date: Thu, 26 Feb 2026 07:54:33 -0600
Message-ID: <20260226135436.31634-1-peter@netlandish.com>
X-Mailer: git-send-email 2.52.0
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

Changelog-fixed: Issue setting createdOn value for tags associated with
 bookmarks, shorts, listings.
Changelog-updated: API server version to 0.10.2
---
 api/graph/schema.resolvers.go | 2 +-
 models/base_url.go            | 2 +-
 models/link_short.go          | 4 ++--
 models/listing.go             | 4 ++--
 models/org_link.go            | 4 ++--
 5 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/api/graph/schema.resolvers.go b/api/graph/schema.resolvers.go
index 2c11efb..bf295fd 100644
--- a/api/graph/schema.resolvers.go
+++ b/api/graph/schema.resolvers.go
@@ -5126,7 +5126,7 @@ func (r *queryResolver) Version(ctx context.Context) (*model.Version, error) {
 	return &model.Version{
 		Major:           0,
 		Minor:           10,
-		Patch:           1,
+		Patch:           2,
 		DeprecationDate: nil,
 	}, nil
 }
diff --git a/models/base_url.go b/models/base_url.go
index 8a88578..5510991 100644
--- a/models/base_url.go
+++ b/models/base_url.go
@@ -65,7 +65,7 @@ func GetBaseURLs(ctx context.Context, opts *database.FilterOptions) ([]*BaseURL,
 		rows, err := q.
 			Columns("b.id", "b.url", "b.title", "b.counter", "b.data", "b.public_ready", "b.hash",
 				"b.parse_attempts", "b.last_parse_attempt", "b.created_on", "b.visibility",
-				fmt.Sprintf("json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'created_on', t.created_on) END ORDER BY %s)::jsonb", tagOrder)).
+				fmt.Sprintf("json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'createdOn', t.created_on) END ORDER BY %s)::jsonb", tagOrder)).
 			From("base_urls b").
 			LeftJoin("org_links ol ON ol.base_url_id = b.id").
 			LeftJoin("organizations o ON o.id = ol.org_id").
diff --git a/models/link_short.go b/models/link_short.go
index a2b03bf..c8cae2e 100644
--- a/models/link_short.go
+++ b/models/link_short.go
@@ -22,7 +22,7 @@ func GetLinkShorts(ctx context.Context, opts *database.FilterOptions) ([]*LinkSh
 		q := opts.GetBuilder(nil)
 		rows, err := q.
 			Columns("l.id", "l.title", "l.url", "l.short_code", "l.domain_id", "l.org_id", "l.user_id",
-				"l.created_on", "l.updated_on", "d.lookup_name", "json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'created_on', t.created_on) END)::jsonb").
+				"l.created_on", "l.updated_on", "d.lookup_name", "json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'createdOn', t.created_on) END)::jsonb").
 			From("link_shorts AS l").
 			InnerJoin("domains d ON l.domain_id = d.id").
 			LeftJoin("tag_link_shorts tl ON tl.link_short_id = l.id").
@@ -236,7 +236,7 @@ func ExportLinkShorts(ctx context.Context, opts *database.FilterOptions) ([]*Exp
 	if err := database.WithTx(ctx, database.TxOptionsRO, func(tx *sql.Tx) error {
 		q := opts.GetBuilder(nil)
 		rows, err := q.
-			Columns("l.id", "l.title", "l.url", "l.short_code", "l.created_on", "json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'created_on', t.created_on) END)::jsonb").
+			Columns("l.id", "l.title", "l.url", "l.short_code", "l.created_on", "json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'createdOn', t.created_on) END)::jsonb").
 			From("link_shorts AS l").
 			LeftJoin("tag_link_shorts tl ON tl.link_short_id = l.id").
 			LeftJoin("tags t ON t.id = tl.tag_id").
diff --git a/models/listing.go b/models/listing.go
index b7c9636..410f2ef 100644
--- a/models/listing.go
+++ b/models/listing.go
@@ -22,7 +22,7 @@ func GetListings(ctx context.Context, opts *database.FilterOptions) ([]*Listing,
 		rows, err := q.
 			Columns("l.id", "l.title", "l.slug", "l.image", "l.metadata", "l.domain_id", "l.org_id",
 				"l.user_id", "l.is_default", "l.is_active", "l.created_on", "l.updated_on", "d.lookup_name",
-				"json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'created_on', t.created_on) END)::jsonb").
+				"json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'createdOn', t.created_on) END)::jsonb").
 			From("listings l").
 			InnerJoin("domains d ON l.domain_id = d.id").
 			InnerJoin("organizations o ON l.org_id = o.id").
@@ -220,7 +220,7 @@ func ExportListings(ctx context.Context, opts *database.FilterOptions) ([]*Expor
 	if err := database.WithTx(ctx, database.TxOptionsRO, func(tx *sql.Tx) error {
 		q := opts.GetBuilder(nil)
 		rows, err := q.
-			Columns("l.id", "l.title", "l.slug", "l.created_on", "json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'created_on', t.created_on) END)::jsonb", "json_agg(ll)::jsonb").
+			Columns("l.id", "l.title", "l.slug", "l.created_on", "json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'createdOn', t.created_on) END)::jsonb", "json_agg(ll)::jsonb").
 			From("listings l").
 			LeftJoin("listing_links ll ON l.id = ll.listing_id").
 			LeftJoin("tag_listings tl ON tl.listing_id = l.id").
diff --git a/models/org_link.go b/models/org_link.go
index 0148c5b..19a0a1e 100644
--- a/models/org_link.go
+++ b/models/org_link.go
@@ -37,7 +37,7 @@ func GetOrgLinks(ctx context.Context, opts *database.FilterOptions) ([]*OrgLink,
 		rows, err := q.
 			Columns("ol.id", "ol.title", "ol.url", "ol.description", "ol.base_url_id", "ol.org_id", "ol.user_id",
 				"ol.visibility", "ol.unread", "ol.starred", "ol.archive_url", "ol.type", "ol.hash",
-				"ol.created_on", "ol.updated_on", "o.slug", "u.full_name", fmt.Sprintf("json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'created_on', t.created_on) END ORDER BY %s)::jsonb", tagOrder), "b.data", "b.counter", "b.hash").
+				"ol.created_on", "ol.updated_on", "o.slug", "u.full_name", fmt.Sprintf("json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'createdOn', t.created_on) END ORDER BY %s)::jsonb", tagOrder), "b.data", "b.counter", "b.hash").
 			From("org_links ol").
 			Join("organizations o ON o.id = ol.org_id").
 			Join("users u ON ol.user_id = u.id").
@@ -325,7 +325,7 @@ func ExportOrgLinks(ctx context.Context, opts *database.FilterOptions) ([]*Expor
 		q := opts.GetBuilder(nil)
 		rows, err := q.
 			Columns("ol.id", "ol.title", "ol.url", "ol.description", "ol.visibility",
-				"ol.unread", "ol.starred", "ol.hash", "ol.created_on", fmt.Sprintf("json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'created_on', t.created_on) END ORDER BY %s)::jsonb", tagOrder)).
+				"ol.unread", "ol.starred", "ol.hash", "ol.created_on", fmt.Sprintf("json_agg(CASE WHEN t.id IS NOT NULL THEN json_build_object('id', t.id, 'name', tl.name, 'slug', t.slug, 'createdOn', t.created_on) END ORDER BY %s)::jsonb", tagOrder)).
 			From("org_links ol").
 			LeftJoin("tag_links tl ON tl.org_link_id = ol.id").
 			LeftJoin("tags t ON t.id = tl.tag_id").
-- 
2.52.0

