@@ -2,18 +2,21 @@ package provider
2
2
3
3
import (
4
4
"context"
5
+ "encoding/json"
5
6
"fmt"
6
7
"strings"
7
8
8
9
"github.com/segmentio/terraform-provider-segment/internal/provider/docs"
9
10
"github.com/segmentio/terraform-provider-segment/internal/provider/models"
10
11
11
12
"github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes"
13
+ "github.com/hashicorp/terraform-plugin-framework/diag"
12
14
"github.com/hashicorp/terraform-plugin-framework/path"
13
15
"github.com/hashicorp/terraform-plugin-framework/resource"
14
16
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
15
17
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
16
18
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
19
+ "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
17
20
18
21
"github.com/segmentio/public-api-sdk-go/api"
19
22
)
@@ -91,12 +94,27 @@ func (r *destinationSubscriptionResource) Schema(_ context.Context, _ resource.S
91
94
Description : `The customer settings for action fields. Only settings included in the configuration will be managed by Terraform.` ,
92
95
CustomType : jsontypes.NormalizedType {},
93
96
},
97
+ "reverse_etl_schedule" : schema.SingleNestedAttribute {
98
+ Optional : true ,
99
+ Description : "(Reverse ETL only) The schedule for the subscription being attached to ReverseETL model." ,
100
+ Attributes : map [string ]schema.Attribute {
101
+ "strategy" : schema.StringAttribute {
102
+ Required : true ,
103
+ Description : "Strategy supports three modes: PERIODIC, SPECIFIC_DAYS, or MANUAL." ,
104
+ },
105
+ "config" : schema.StringAttribute {
106
+ Optional : true ,
107
+ Description : "Configures the schedule for the subscription." ,
108
+ CustomType : jsontypes.NormalizedType {},
109
+ },
110
+ },
111
+ },
94
112
},
95
113
}
96
114
}
97
115
98
116
func (r * destinationSubscriptionResource ) Create (ctx context.Context , req resource.CreateRequest , resp * resource.CreateResponse ) {
99
- var plan models.DestinationSubscriptionState
117
+ var plan models.DestinationSubscriptionPlan
100
118
diags := req .Plan .Get (ctx , & plan )
101
119
resp .Diagnostics .Append (diags ... )
102
120
if resp .Diagnostics .HasError () {
@@ -110,6 +128,15 @@ func (r *destinationSubscriptionResource) Create(ctx context.Context, req resour
110
128
return
111
129
}
112
130
131
+ if ! plan .ModelID .IsNull () && ! plan .ModelID .IsUnknown () && (plan .ReverseETLSchedule .IsNull () || plan .ReverseETLSchedule .IsUnknown ()) {
132
+ resp .Diagnostics .AddError (
133
+ "Reverse ETL model ID provided without reverse ETL schedule" ,
134
+ "Reverse ETL model ID must be provided with a reverse ETL schedule" ,
135
+ )
136
+
137
+ return
138
+ }
139
+
113
140
out , body , err := r .client .DestinationsAPI .CreateDestinationSubscription (r .authContext , plan .DestinationID .ValueString ()).CreateDestinationSubscriptionAlphaInput (api.CreateDestinationSubscriptionAlphaInput {
114
141
Name : plan .Name .ValueString (),
115
142
ActionId : plan .ActionID .ValueString (),
@@ -130,9 +157,39 @@ func (r *destinationSubscriptionResource) Create(ctx context.Context, req resour
130
157
return
131
158
}
132
159
133
- destinationSubscription := out .Data .GetDestinationSubscription ()
160
+ resp .State .SetAttribute (ctx , path .Root ("id" ), out .Data .DestinationSubscription .Id )
161
+ resp .State .SetAttribute (ctx , path .Root ("destination_id" ), out .Data .DestinationSubscription .DestinationId )
162
+
163
+ reverseETLSchedule , diags := getSchedule (ctx , plan .ReverseETLSchedule )
164
+ if diags .HasError () {
165
+ resp .Diagnostics .Append (diags ... )
166
+
167
+ return
168
+ }
169
+
170
+ updateOut , body , err := r .client .DestinationsAPI .UpdateSubscriptionForDestination (r .authContext , plan .DestinationID .ValueString (), out .Data .DestinationSubscription .Id ).UpdateSubscriptionForDestinationAlphaInput (api.UpdateSubscriptionForDestinationAlphaInput {
171
+ Input : api.DestinationSubscriptionUpdateInput {
172
+ Name : plan .Name .ValueStringPointer (),
173
+ Trigger : plan .Trigger .ValueStringPointer (),
174
+ Enabled : plan .Enabled .ValueBoolPointer (),
175
+ Settings : settings ,
176
+ ReverseETLModelId : plan .ModelID .ValueStringPointer (),
177
+ ReverseETLSchedule : reverseETLSchedule ,
178
+ },
179
+ }).Execute ()
180
+ if body != nil {
181
+ defer body .Body .Close ()
182
+ }
183
+ if err != nil {
184
+ resp .Diagnostics .AddError (
185
+ "Unable to update Destination subscription" ,
186
+ getError (err , body ),
187
+ )
188
+
189
+ return
190
+ }
134
191
135
- resp . State . SetAttribute ( ctx , path . Root ( "id" ), destinationSubscription . Id )
192
+ destinationSubscription := updateOut . Data . Subscription
136
193
137
194
var state models.DestinationSubscriptionState
138
195
err = state .Fill (destinationSubscription )
@@ -203,7 +260,7 @@ func (r *destinationSubscriptionResource) Read(ctx context.Context, req resource
203
260
}
204
261
205
262
func (r * destinationSubscriptionResource ) Update (ctx context.Context , req resource.UpdateRequest , resp * resource.UpdateResponse ) {
206
- var plan models.DestinationSubscriptionState
263
+ var plan models.DestinationSubscriptionPlan
207
264
diags := req .Plan .Get (ctx , & plan )
208
265
resp .Diagnostics .Append (diags ... )
209
266
if resp .Diagnostics .HasError () {
@@ -224,12 +281,30 @@ func (r *destinationSubscriptionResource) Update(ctx context.Context, req resour
224
281
return
225
282
}
226
283
284
+ if ! plan .ModelID .IsNull () && ! plan .ModelID .IsUnknown () && (plan .ReverseETLSchedule .IsNull () || plan .ReverseETLSchedule .IsUnknown ()) {
285
+ resp .Diagnostics .AddError (
286
+ "Reverse ETL model ID provided without reverse ETL schedule" ,
287
+ "Reverse ETL model ID must be provided with a reverse ETL schedule" ,
288
+ )
289
+
290
+ return
291
+ }
292
+
293
+ reverseETLSchedule , diags := getSchedule (ctx , plan .ReverseETLSchedule )
294
+ if diags .HasError () {
295
+ resp .Diagnostics .Append (diags ... )
296
+
297
+ return
298
+ }
299
+
227
300
out , body , err := r .client .DestinationsAPI .UpdateSubscriptionForDestination (r .authContext , state .DestinationID .ValueString (), state .ID .ValueString ()).UpdateSubscriptionForDestinationAlphaInput (api.UpdateSubscriptionForDestinationAlphaInput {
228
301
Input : api.DestinationSubscriptionUpdateInput {
229
- Name : plan .Name .ValueStringPointer (),
230
- Trigger : plan .Trigger .ValueStringPointer (),
231
- Enabled : plan .Enabled .ValueBoolPointer (),
232
- Settings : settings ,
302
+ Name : plan .Name .ValueStringPointer (),
303
+ Trigger : plan .Trigger .ValueStringPointer (),
304
+ Enabled : plan .Enabled .ValueBoolPointer (),
305
+ Settings : settings ,
306
+ ReverseETLModelId : plan .ModelID .ValueStringPointer (),
307
+ ReverseETLSchedule : reverseETLSchedule ,
233
308
},
234
309
}).Execute ()
235
310
if body != nil {
@@ -320,3 +395,115 @@ func (r *destinationSubscriptionResource) Configure(_ context.Context, req resou
320
395
r .client = config .client
321
396
r .authContext = config .authContext
322
397
}
398
+
399
+ func getSchedule (ctx context.Context , planSchedule basetypes.ObjectValue ) (* api.ReverseEtlScheduleDefinition , diag.Diagnostics ) {
400
+ var reverseETLSchedule * api.ReverseEtlScheduleDefinition
401
+ var diags diag.Diagnostics
402
+ if ! planSchedule .IsNull () && ! planSchedule .IsUnknown () {
403
+ reverseETLSchedule = & api.ReverseEtlScheduleDefinition {}
404
+
405
+ wrappedReverseETLModelScheduleStrategy , err := planSchedule .Attributes ()["strategy" ].ToTerraformValue (ctx )
406
+ if err != nil {
407
+ diags .AddError (
408
+ "Unable to decode reverse ETL schedule strategy" ,
409
+ err .Error (),
410
+ )
411
+
412
+ return nil , diags
413
+ }
414
+
415
+ var reverseETLModelScheduleStrategy string
416
+ err = wrappedReverseETLModelScheduleStrategy .As (& reverseETLModelScheduleStrategy )
417
+ if err != nil {
418
+ diags .AddError (
419
+ "Unable to decode reverse ETL schedule strategy" ,
420
+ err .Error (),
421
+ )
422
+
423
+ return nil , diags
424
+ }
425
+
426
+ reverseETLSchedule .Strategy = reverseETLModelScheduleStrategy
427
+
428
+ wrappedReverseETLModelScheduleConfig , err := planSchedule .Attributes ()["config" ].ToTerraformValue (ctx )
429
+ if err != nil {
430
+ diags .AddError (
431
+ "Unable to decode reverse ETL schedule config" ,
432
+ err .Error (),
433
+ )
434
+
435
+ return nil , diags
436
+ }
437
+
438
+ if ! wrappedReverseETLModelScheduleConfig .IsNull () && wrappedReverseETLModelScheduleConfig .IsKnown () {
439
+ if reverseETLSchedule .Strategy == "PERIODIC" {
440
+ reverseETLModelScheduleConfig := api.ReverseEtlPeriodicScheduleConfig {}
441
+ var config string
442
+ err = wrappedReverseETLModelScheduleConfig .As (& config )
443
+ if err != nil {
444
+ diags .AddError (
445
+ "Unable to decode reverse ETL schedule config" ,
446
+ err .Error (),
447
+ )
448
+
449
+ return nil , diags
450
+ }
451
+
452
+ err = json .Unmarshal ([]byte (config ), & reverseETLModelScheduleConfig )
453
+ if err != nil {
454
+ diags .AddError (
455
+ "Unable to decode reverse ETL schedule config" ,
456
+ err .Error (),
457
+ )
458
+
459
+ return nil , diags
460
+ }
461
+
462
+ reverseETLSchedule .Config = * api .NewNullableConfig (& api.Config {
463
+ ReverseEtlPeriodicScheduleConfig : & reverseETLModelScheduleConfig ,
464
+ })
465
+ } else if reverseETLSchedule .Strategy == "SPECIFIC_DAYS" {
466
+ reverseETLModelScheduleConfig := api.ReverseEtlSpecificTimeScheduleConfig {}
467
+ var config string
468
+ err = wrappedReverseETLModelScheduleConfig .As (& config )
469
+ if err != nil {
470
+ diags .AddError (
471
+ "Unable to decode reverse ETL schedule config" ,
472
+ err .Error (),
473
+ )
474
+
475
+ return nil , diags
476
+ }
477
+
478
+ err = json .Unmarshal ([]byte (config ), & reverseETLModelScheduleConfig )
479
+ if err != nil {
480
+ diags .AddError (
481
+ "Unable to decode reverse ETL schedule config" ,
482
+ err .Error (),
483
+ )
484
+
485
+ return nil , diags
486
+ }
487
+
488
+ reverseETLSchedule .Config = * api .NewNullableConfig (& api.Config {
489
+ ReverseEtlSpecificTimeScheduleConfig : & reverseETLModelScheduleConfig ,
490
+ })
491
+ } else if reverseETLSchedule .Strategy == "MANUAL" {
492
+ diags .AddError (
493
+ "Manual reverse ETL schedule strategy does not require a config" ,
494
+ "Manual reverse ETL schedule strategy does not require a config" ,
495
+ )
496
+ reverseETLSchedule .Config = * api .NewNullableConfig (nil )
497
+ } else {
498
+ diags .AddError (
499
+ "Unsupported reverse ETL schedule strategy" ,
500
+ fmt .Sprintf ("Strategy %q is not supported" , reverseETLSchedule .Strategy ),
501
+ )
502
+
503
+ return nil , diags
504
+ }
505
+ }
506
+ }
507
+
508
+ return reverseETLSchedule , diags
509
+ }
0 commit comments