From f1712ce1c1fb23e84bfedd851530dbe700e04ab8 Mon Sep 17 00:00:00 2001 From: ShradhaGupta31 Date: Thu, 20 Aug 2026 10:54:14 +0530 Subject: [PATCH 1/2] refactor: denormalize currentMode/discovered into device columns Addresses: https://github.com/device-management-toolkit/console/issues/1210 - Mirror the deviceinfo currentMode and discovered JSON fields into dedicated queryable device columns, synced on every insert/update from the deviceinfo blob (source of truth). - Adds nullable columns via migration and wires the write path across sqldb (Postgres/SQLite) and mongo backends. No API or behaviour change: the columns are written but not yet read. Signed-off-by: ShradhaGupta31 --- .../20260820000000_migrate_device_mode_discovered.down.sql | 7 +++++++ .../20260820000000_migrate_device_mode_discovered.up.sql | 7 +++++++ internal/entity/device.go | 3 +++ internal/usecase/devices/repo_test.go | 1 + internal/usecase/devices/usecase.go | 6 ++++++ internal/usecase/nosqldb/mongo/device.go | 4 ++++ internal/usecase/sqldb/device.go | 6 ++++-- internal/usecase/sqldb/device_test.go | 6 +++++- 8 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 internal/app/migrations/20260820000000_migrate_device_mode_discovered.down.sql create mode 100644 internal/app/migrations/20260820000000_migrate_device_mode_discovered.up.sql diff --git a/internal/app/migrations/20260820000000_migrate_device_mode_discovered.down.sql b/internal/app/migrations/20260820000000_migrate_device_mode_discovered.down.sql new file mode 100644 index 000000000..4ffd656e8 --- /dev/null +++ b/internal/app/migrations/20260820000000_migrate_device_mode_discovered.down.sql @@ -0,0 +1,7 @@ +/********************************************************************* +* Copyright (c) Intel Corporation 2026 +* SPDX-License-Identifier: Apache-2.0 +**********************************************************************/ + +ALTER TABLE devices DROP COLUMN currentmode; +ALTER TABLE devices DROP COLUMN discovered; diff --git a/internal/app/migrations/20260820000000_migrate_device_mode_discovered.up.sql b/internal/app/migrations/20260820000000_migrate_device_mode_discovered.up.sql new file mode 100644 index 000000000..50c54ca94 --- /dev/null +++ b/internal/app/migrations/20260820000000_migrate_device_mode_discovered.up.sql @@ -0,0 +1,7 @@ +/********************************************************************* +* Copyright (c) Intel Corporation 2026 +* SPDX-License-Identifier: Apache-2.0 +**********************************************************************/ + +ALTER TABLE devices ADD COLUMN currentmode TEXT; +ALTER TABLE devices ADD COLUMN discovered BOOLEAN; diff --git a/internal/entity/device.go b/internal/entity/device.go index 6baa9cea2..3944f317b 100644 --- a/internal/entity/device.go +++ b/internal/entity/device.go @@ -25,6 +25,9 @@ type Device struct { UseTLS bool `bson:"usetls"` AllowSelfSigned bool `bson:"allowselfsigned"` CertHash *string `bson:"certhash"` + // Queryable mirrors of the matching deviceinfo JSON fields, synced on every insert/update. + CurrentMode string `bson:"currentmode"` + Discovered *bool `bson:"discovered"` } type Explorer struct { diff --git a/internal/usecase/devices/repo_test.go b/internal/usecase/devices/repo_test.go index c5ff390b5..ae51b5dfb 100644 --- a/internal/usecase/devices/repo_test.go +++ b/internal/usecase/devices/repo_test.go @@ -805,6 +805,7 @@ func TestUpdatePartial(t *testing.T) { Password: "encrypted", MPSPassword: ptr("encrypted"), MEBXPassword: ptr("encrypted"), + Discovered: boolPtr(true), } expectedDTO := &dto.Device{ diff --git a/internal/usecase/devices/usecase.go b/internal/usecase/devices/usecase.go index 711a39dc4..87e3c37b9 100644 --- a/internal/usecase/devices/usecase.go +++ b/internal/usecase/devices/usecase.go @@ -103,6 +103,12 @@ func (uc *UseCase) dtoToEntity(d *dto.Device) (*entity.Device, error) { AllowSelfSigned: d.AllowSelfSigned, } + // Sync the queryable mirror columns from the deviceinfo blob (source of truth). + if d.DeviceInfo != nil { + d1.CurrentMode = d.DeviceInfo.CurrentMode + d1.Discovered = d.DeviceInfo.Discovered + } + d1.Password, err = uc.safeRequirements.Encrypt(d1.Password) if err != nil { return nil, ErrDeviceUseCase.Wrap("dtoToEntity", "failed to encrypt password", err) diff --git a/internal/usecase/nosqldb/mongo/device.go b/internal/usecase/nosqldb/mongo/device.go index c1e5a45f3..78bea0871 100644 --- a/internal/usecase/nosqldb/mongo/device.go +++ b/internal/usecase/nosqldb/mongo/device.go @@ -42,6 +42,8 @@ type deviceUpdateFields struct { UseTLS bool `bson:"usetls"` AllowSelfSigned bool `bson:"allowselfsigned"` CertHash *string `bson:"certhash"` + CurrentMode string `bson:"currentmode"` + Discovered *bool `bson:"discovered"` } type deviceUpdateDocument struct { @@ -247,6 +249,8 @@ func (r *DeviceRepo) Update(ctx context.Context, d *entity.Device) (bool, error) UseTLS: d.UseTLS, AllowSelfSigned: d.AllowSelfSigned, CertHash: d.CertHash, + CurrentMode: d.CurrentMode, + Discovered: d.Discovered, }}, ) if err != nil { diff --git a/internal/usecase/sqldb/device.go b/internal/usecase/sqldb/device.go index 7766d3523..0025ef287 100644 --- a/internal/usecase/sqldb/device.go +++ b/internal/usecase/sqldb/device.go @@ -348,6 +348,8 @@ func (r *DeviceRepo) Update(_ context.Context, d *entity.Device) (bool, error) { Set("useTLS", d.UseTLS). Set("allowSelfSigned", d.AllowSelfSigned). Set("certhash", d.CertHash). + Set("currentmode", d.CurrentMode). + Set("discovered", d.Discovered). Where("guid = ? AND tenantid = ?", d.GUID, d.TenantID). ToSql() if err != nil { @@ -420,8 +422,8 @@ func (r *DeviceRepo) UpdateLastSeen(_ context.Context, guid string) error { func (r *DeviceRepo) Insert(_ context.Context, d *entity.Device) (string, error) { insertBuilder := r.Builder. Insert("devices"). - Columns("guid", "hostname", "tags", "mpsinstance", "connectionstatus", "mpsusername", "tenantid", "friendlyname", "dnssuffix", "deviceinfo", "username", "password", "mpspassword", "mebxpassword", "usetls", "allowselfsigned", "certhash"). - Values(d.GUID, d.Hostname, d.Tags, d.MPSInstance, d.ConnectionStatus, d.MPSUsername, d.TenantID, d.FriendlyName, d.DNSSuffix, d.DeviceInfo, d.Username, d.Password, d.MPSPassword, d.MEBXPassword, d.UseTLS, d.AllowSelfSigned, d.CertHash) + Columns("guid", "hostname", "tags", "mpsinstance", "connectionstatus", "mpsusername", "tenantid", "friendlyname", "dnssuffix", "deviceinfo", "username", "password", "mpspassword", "mebxpassword", "usetls", "allowselfsigned", "certhash", "currentmode", "discovered"). + Values(d.GUID, d.Hostname, d.Tags, d.MPSInstance, d.ConnectionStatus, d.MPSUsername, d.TenantID, d.FriendlyName, d.DNSSuffix, d.DeviceInfo, d.Username, d.Password, d.MPSPassword, d.MEBXPassword, d.UseTLS, d.AllowSelfSigned, d.CertHash, d.CurrentMode, d.Discovered) if !r.IsEmbedded { insertBuilder = insertBuilder.Suffix("RETURNING xmin::text") diff --git a/internal/usecase/sqldb/device_test.go b/internal/usecase/sqldb/device_test.go index 67d7d806e..9b08fc15d 100644 --- a/internal/usecase/sqldb/device_test.go +++ b/internal/usecase/sqldb/device_test.go @@ -49,6 +49,8 @@ func setupDeviceTable(t *testing.T) *sql.DB { usetls BOOLEAN NOT NULL DEFAULT FALSE, allowselfsigned BOOLEAN NOT NULL DEFAULT FALSE, certhash TEXT NOT NULL DEFAULT '', + currentmode TEXT, + discovered BOOLEAN, lastconnected TEXT, lastdisconnected TEXT, lastseen TEXT @@ -815,7 +817,9 @@ func TestDeviceRepo_Update(t *testing.T) { mebxpassword TEXT, usetls BOOLEAN NOT NULL DEFAULT FALSE, allowselfsigned BOOLEAN NOT NULL DEFAULT FALSE, - certhash TEXT NOT NULL DEFAULT '' + certhash TEXT NOT NULL DEFAULT '', + currentmode TEXT, + discovered BOOLEAN ); `) require.NoError(t, err) From 199c73d63aa7de40a2222c7cb653f520b1091368 Mon Sep 17 00:00:00 2001 From: ShradhaGupta31 Date: Thu, 27 Aug 2026 16:00:47 +0530 Subject: [PATCH 2/2] refactor: address review comments - Removed discovered feilds denormalisation Signed-off-by: ShradhaGupta31 --- ....down.sql => 20260820000000_migrate_device_mode.down.sql} | 1 - ...ered.up.sql => 20260820000000_migrate_device_mode.up.sql} | 1 - internal/entity/device.go | 3 +-- internal/usecase/devices/repo_test.go | 1 - internal/usecase/devices/usecase.go | 3 +-- internal/usecase/nosqldb/mongo/device.go | 2 -- internal/usecase/sqldb/device.go | 5 ++--- internal/usecase/sqldb/device_test.go | 4 +--- 8 files changed, 5 insertions(+), 15 deletions(-) rename internal/app/migrations/{20260820000000_migrate_device_mode_discovered.down.sql => 20260820000000_migrate_device_mode.down.sql} (85%) rename internal/app/migrations/{20260820000000_migrate_device_mode_discovered.up.sql => 20260820000000_migrate_device_mode.up.sql} (84%) diff --git a/internal/app/migrations/20260820000000_migrate_device_mode_discovered.down.sql b/internal/app/migrations/20260820000000_migrate_device_mode.down.sql similarity index 85% rename from internal/app/migrations/20260820000000_migrate_device_mode_discovered.down.sql rename to internal/app/migrations/20260820000000_migrate_device_mode.down.sql index 4ffd656e8..0d19079f1 100644 --- a/internal/app/migrations/20260820000000_migrate_device_mode_discovered.down.sql +++ b/internal/app/migrations/20260820000000_migrate_device_mode.down.sql @@ -4,4 +4,3 @@ **********************************************************************/ ALTER TABLE devices DROP COLUMN currentmode; -ALTER TABLE devices DROP COLUMN discovered; diff --git a/internal/app/migrations/20260820000000_migrate_device_mode_discovered.up.sql b/internal/app/migrations/20260820000000_migrate_device_mode.up.sql similarity index 84% rename from internal/app/migrations/20260820000000_migrate_device_mode_discovered.up.sql rename to internal/app/migrations/20260820000000_migrate_device_mode.up.sql index 50c54ca94..17c6fd793 100644 --- a/internal/app/migrations/20260820000000_migrate_device_mode_discovered.up.sql +++ b/internal/app/migrations/20260820000000_migrate_device_mode.up.sql @@ -4,4 +4,3 @@ **********************************************************************/ ALTER TABLE devices ADD COLUMN currentmode TEXT; -ALTER TABLE devices ADD COLUMN discovered BOOLEAN; diff --git a/internal/entity/device.go b/internal/entity/device.go index 3944f317b..17e1e77be 100644 --- a/internal/entity/device.go +++ b/internal/entity/device.go @@ -25,9 +25,8 @@ type Device struct { UseTLS bool `bson:"usetls"` AllowSelfSigned bool `bson:"allowselfsigned"` CertHash *string `bson:"certhash"` - // Queryable mirrors of the matching deviceinfo JSON fields, synced on every insert/update. + // Queryable mirror of the deviceinfo currentMode JSON field, synced on every insert/update. CurrentMode string `bson:"currentmode"` - Discovered *bool `bson:"discovered"` } type Explorer struct { diff --git a/internal/usecase/devices/repo_test.go b/internal/usecase/devices/repo_test.go index ae51b5dfb..c5ff390b5 100644 --- a/internal/usecase/devices/repo_test.go +++ b/internal/usecase/devices/repo_test.go @@ -805,7 +805,6 @@ func TestUpdatePartial(t *testing.T) { Password: "encrypted", MPSPassword: ptr("encrypted"), MEBXPassword: ptr("encrypted"), - Discovered: boolPtr(true), } expectedDTO := &dto.Device{ diff --git a/internal/usecase/devices/usecase.go b/internal/usecase/devices/usecase.go index 87e3c37b9..8a4e90c78 100644 --- a/internal/usecase/devices/usecase.go +++ b/internal/usecase/devices/usecase.go @@ -103,10 +103,9 @@ func (uc *UseCase) dtoToEntity(d *dto.Device) (*entity.Device, error) { AllowSelfSigned: d.AllowSelfSigned, } - // Sync the queryable mirror columns from the deviceinfo blob (source of truth). + // Sync the queryable mirror column from the deviceinfo blob (source of truth). if d.DeviceInfo != nil { d1.CurrentMode = d.DeviceInfo.CurrentMode - d1.Discovered = d.DeviceInfo.Discovered } d1.Password, err = uc.safeRequirements.Encrypt(d1.Password) diff --git a/internal/usecase/nosqldb/mongo/device.go b/internal/usecase/nosqldb/mongo/device.go index 78bea0871..183ea7c6f 100644 --- a/internal/usecase/nosqldb/mongo/device.go +++ b/internal/usecase/nosqldb/mongo/device.go @@ -43,7 +43,6 @@ type deviceUpdateFields struct { AllowSelfSigned bool `bson:"allowselfsigned"` CertHash *string `bson:"certhash"` CurrentMode string `bson:"currentmode"` - Discovered *bool `bson:"discovered"` } type deviceUpdateDocument struct { @@ -250,7 +249,6 @@ func (r *DeviceRepo) Update(ctx context.Context, d *entity.Device) (bool, error) AllowSelfSigned: d.AllowSelfSigned, CertHash: d.CertHash, CurrentMode: d.CurrentMode, - Discovered: d.Discovered, }}, ) if err != nil { diff --git a/internal/usecase/sqldb/device.go b/internal/usecase/sqldb/device.go index 0025ef287..d8fa3d4a2 100644 --- a/internal/usecase/sqldb/device.go +++ b/internal/usecase/sqldb/device.go @@ -349,7 +349,6 @@ func (r *DeviceRepo) Update(_ context.Context, d *entity.Device) (bool, error) { Set("allowSelfSigned", d.AllowSelfSigned). Set("certhash", d.CertHash). Set("currentmode", d.CurrentMode). - Set("discovered", d.Discovered). Where("guid = ? AND tenantid = ?", d.GUID, d.TenantID). ToSql() if err != nil { @@ -422,8 +421,8 @@ func (r *DeviceRepo) UpdateLastSeen(_ context.Context, guid string) error { func (r *DeviceRepo) Insert(_ context.Context, d *entity.Device) (string, error) { insertBuilder := r.Builder. Insert("devices"). - Columns("guid", "hostname", "tags", "mpsinstance", "connectionstatus", "mpsusername", "tenantid", "friendlyname", "dnssuffix", "deviceinfo", "username", "password", "mpspassword", "mebxpassword", "usetls", "allowselfsigned", "certhash", "currentmode", "discovered"). - Values(d.GUID, d.Hostname, d.Tags, d.MPSInstance, d.ConnectionStatus, d.MPSUsername, d.TenantID, d.FriendlyName, d.DNSSuffix, d.DeviceInfo, d.Username, d.Password, d.MPSPassword, d.MEBXPassword, d.UseTLS, d.AllowSelfSigned, d.CertHash, d.CurrentMode, d.Discovered) + Columns("guid", "hostname", "tags", "mpsinstance", "connectionstatus", "mpsusername", "tenantid", "friendlyname", "dnssuffix", "deviceinfo", "username", "password", "mpspassword", "mebxpassword", "usetls", "allowselfsigned", "certhash", "currentmode"). + Values(d.GUID, d.Hostname, d.Tags, d.MPSInstance, d.ConnectionStatus, d.MPSUsername, d.TenantID, d.FriendlyName, d.DNSSuffix, d.DeviceInfo, d.Username, d.Password, d.MPSPassword, d.MEBXPassword, d.UseTLS, d.AllowSelfSigned, d.CertHash, d.CurrentMode) if !r.IsEmbedded { insertBuilder = insertBuilder.Suffix("RETURNING xmin::text") diff --git a/internal/usecase/sqldb/device_test.go b/internal/usecase/sqldb/device_test.go index 9b08fc15d..214907133 100644 --- a/internal/usecase/sqldb/device_test.go +++ b/internal/usecase/sqldb/device_test.go @@ -50,7 +50,6 @@ func setupDeviceTable(t *testing.T) *sql.DB { allowselfsigned BOOLEAN NOT NULL DEFAULT FALSE, certhash TEXT NOT NULL DEFAULT '', currentmode TEXT, - discovered BOOLEAN, lastconnected TEXT, lastdisconnected TEXT, lastseen TEXT @@ -818,8 +817,7 @@ func TestDeviceRepo_Update(t *testing.T) { usetls BOOLEAN NOT NULL DEFAULT FALSE, allowselfsigned BOOLEAN NOT NULL DEFAULT FALSE, certhash TEXT NOT NULL DEFAULT '', - currentmode TEXT, - discovered BOOLEAN + currentmode TEXT ); `) require.NoError(t, err)