@@ -17,87 +17,122 @@ package gcpspanner
1717import (
1818 "context"
1919 "fmt"
20+ "log/slog"
2021
2122 "cloud.google.com/go/spanner"
2223)
2324
2425const browserFeatureAvailabilitiesTable = "BrowserFeatureAvailabilities"
2526
26- // Implements the entityMapper interface for BrowserFeatureAvailability and SpannerBrowserFeatureAvailability.
27- type browserFeatureAvailabilityMapper struct {}
27+ // spannerBrowserFeatureAvailability is a wrapper for the browser availability
28+ // information for a feature stored in spanner.
29+ type spannerBrowserFeatureAvailability struct {
30+ WebFeatureID string `spanner:"WebFeatureID"`
31+ BrowserName string `spanner:"BrowserName"`
32+ BrowserVersion string `spanner:"BrowserVersion"`
33+ }
2834
29- func (m browserFeatureAvailabilityMapper ) Table () string {
30- return browserFeatureAvailabilitiesTable
35+ // BrowserFeatureAvailability contains availability information for a particular
36+ // feature in a browser.
37+ type BrowserFeatureAvailability struct {
38+ BrowserName string
39+ BrowserVersion string
3140}
3241
33- type browserFeatureAvailabilityKey struct {
34- WebFeatureID string
35- BrowserName string
42+ // Implements the syncableEntityMapper interface for BrowserFeatureAvailability and spannerBrowserFeatureAvailability.
43+ type browserFeatureAvailabilitySpannerMapper struct {}
44+
45+ // PreDeleteHook is a no-op for browser feature availabilities.
46+ func (m browserFeatureAvailabilitySpannerMapper ) PreDeleteHook (
47+ _ context.Context ,
48+ _ * Client ,
49+ _ []spannerBrowserFeatureAvailability ,
50+ ) ([]ExtraMutationsGroup , error ) {
51+ return nil , nil
3652}
3753
38- func (m browserFeatureAvailabilityMapper ) SelectOne (key browserFeatureAvailabilityKey ) spanner.Statement {
39- stmt := spanner .NewStatement (fmt .Sprintf (`
54+ // GetChildDeleteKeyMutations returns nil as there are no child delete mutations for browser feature availabilities.
55+ func (m browserFeatureAvailabilitySpannerMapper ) GetChildDeleteKeyMutations (
56+ _ context.Context ,
57+ _ * Client ,
58+ _ []spannerBrowserFeatureAvailability ,
59+ ) ([]ExtraMutationsGroup , error ) {
60+ return nil , nil
61+ }
62+
63+ func (m browserFeatureAvailabilitySpannerMapper ) Table () string {
64+ return browserFeatureAvailabilitiesTable
65+ }
66+
67+ func (m browserFeatureAvailabilitySpannerMapper ) SelectAll () spanner.Statement {
68+ return spanner .NewStatement (fmt .Sprintf (`
4069 SELECT
4170 WebFeatureID, BrowserName, BrowserVersion
42- FROM %s
43- WHERE WebFeatureID = @webFeatureID AND BrowserName = @browserName
44- LIMIT 1` , m .Table ()))
45- parameters := map [string ]interface {}{
46- "webFeatureID" : key .WebFeatureID ,
47- "browserName" : key .BrowserName ,
48- }
49- stmt .Params = parameters
50-
51- return stmt
71+ FROM %s` , m .Table ()))
5272}
5373
54- func (m browserFeatureAvailabilityMapper ) GetKeyFromExternal (
55- in spannerBrowserFeatureAvailability ) browserFeatureAvailabilityKey {
56- return browserFeatureAvailabilityKey {
57- WebFeatureID : in .WebFeatureID ,
58- BrowserName : in .BrowserName ,
59- }
74+ func (m browserFeatureAvailabilitySpannerMapper ) GetKeyFromExternal (in spannerBrowserFeatureAvailability ) string {
75+ return fmt .Sprintf ("%s-%s" , in .WebFeatureID , in .BrowserName )
6076}
6177
62- func (m browserFeatureAvailabilityMapper ) DeleteKey ( key browserFeatureAvailabilityKey ) spanner. Key {
63- return spanner. Key { key .WebFeatureID , key .BrowserName }
78+ func (m browserFeatureAvailabilitySpannerMapper ) GetKeyFromInternal ( in spannerBrowserFeatureAvailability ) string {
79+ return fmt . Sprintf ( "%s-%s" , in .WebFeatureID , in .BrowserName )
6480}
6581
66- // spannerBrowserFeatureAvailability is a wrapper for the browser availability
67- // information for a feature stored in spanner.
68- type spannerBrowserFeatureAvailability struct {
69- WebFeatureID string
70- BrowserFeatureAvailability
82+ func (m browserFeatureAvailabilitySpannerMapper ) MergeAndCheckChanged (
83+ in spannerBrowserFeatureAvailability , existing spannerBrowserFeatureAvailability ) (
84+ spannerBrowserFeatureAvailability , bool ) {
85+ merged := spannerBrowserFeatureAvailability {
86+ WebFeatureID : existing .WebFeatureID ,
87+ BrowserName : existing .BrowserName ,
88+ BrowserVersion : in .BrowserVersion ,
89+ }
90+ hasChanged := merged .BrowserVersion != existing .BrowserVersion
91+
92+ return merged , hasChanged
7193}
7294
73- // BrowserFeatureAvailability contains availability information for a particular
74- // feature in a browser.
75- type BrowserFeatureAvailability struct {
76- BrowserName string
77- BrowserVersion string
95+ func (m browserFeatureAvailabilitySpannerMapper ) DeleteMutation (
96+ in spannerBrowserFeatureAvailability ) * spanner.Mutation {
97+ return spanner .Delete (browserFeatureAvailabilitiesTable , spanner.Key {in .WebFeatureID , in .BrowserName })
7898}
7999
80- // UpsertBrowserFeatureAvailability will upsert the given browser feature availability.
81- func (c * Client ) UpsertBrowserFeatureAvailability (
100+ // SyncBrowserFeatureAvailabilities reconciles the BrowserFeatureAvailabilities table with the provided
101+ // list of availabilities.
102+ func (c * Client ) SyncBrowserFeatureAvailabilities (
82103 ctx context.Context ,
83- webFeatureID string ,
84- input BrowserFeatureAvailability ) error {
85- id , err := c .GetIDFromFeatureKey (ctx , NewFeatureKeyFilter ( webFeatureID ) )
104+ availabilities map [ string ][] BrowserFeatureAvailability ,
105+ ) error {
106+ featureIDandKeys , err := c .FetchAllWebFeatureIDsAndKeys (ctx )
86107 if err != nil {
87108 return err
88109 }
89- if id == nil {
90- return ErrInternalQueryFailure
110+
111+ featureKeyToID := make (map [string ]string , len (featureIDandKeys ))
112+ for _ , item := range featureIDandKeys {
113+ featureKeyToID [item .FeatureKey ] = item .ID
91114 }
92- featureAvailability := spannerBrowserFeatureAvailability {
93- WebFeatureID : * id ,
94- BrowserFeatureAvailability : input ,
115+
116+ var spannerAvailabilities []spannerBrowserFeatureAvailability
117+ for featureKey , featureAvailabilities := range availabilities {
118+ featureID , ok := featureKeyToID [featureKey ]
119+ if ! ok {
120+ slog .WarnContext (ctx , "unable to find feature id for feature key" , "featureKey" , featureKey )
121+
122+ continue
123+ }
124+ for _ , availability := range featureAvailabilities {
125+ spannerAvailabilities = append (spannerAvailabilities , spannerBrowserFeatureAvailability {
126+ WebFeatureID : featureID ,
127+ BrowserName : availability .BrowserName ,
128+ BrowserVersion : availability .BrowserVersion ,
129+ })
130+ }
95131 }
96132
97- return newUniqueEntityWriter [
98- browserFeatureAvailabilityMapper ,
99- spannerBrowserFeatureAvailability ,
100- spannerBrowserFeatureAvailability ](c ).upsertUniqueKey (ctx , featureAvailability )
133+ synchronizer := newEntitySynchronizer [browserFeatureAvailabilitySpannerMapper ](c )
134+
135+ return synchronizer .Sync (ctx , spannerAvailabilities )
101136}
102137
103138func (c * Client ) fetchAllBrowserAvailabilitiesWithTransaction (
0 commit comments