diff --git a/.gitignore b/.gitignore index 563bdc8..7a0d6c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +**/.speakeasy/temp/ +**/.speakeasy/logs/ +.env +.env.local .terraform .terraform* *.tfstate* diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 649720d..0a0efa1 100755 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -1,23 +1,693 @@ lockVersion: 2.0.0 id: 998a101f-1cb6-4c08-9fd1-b3ee7a1cdeb4 management: - docChecksum: 1b26e8c7c1ab65a1ba2183f905b98a1c + docChecksum: 64c6c6e1ba31ff6b601d0063e45b6a48 docVersion: 0.0.1 - speakeasyVersion: 1.477.0 - generationVersion: 2.497.0 - releaseVersion: 0.14.2 - configChecksum: f7903441c23a0a44467352a31adb6dff + speakeasyVersion: 1.680.4 + generationVersion: 2.788.7 + releaseVersion: 0.15.0 + configChecksum: 5289ba7a3c99ab54db06d8d70c750602 repoURL: https://github.com/epilot-dev/terraform-provider-epilot-designbuilder.git +persistentEdits: + generation_id: 715e1cef-86e1-4e23-a145-c5151121c5ae + pristine_commit_hash: c0d107fede8285efaaf22c4f3ac94e1a580ea278 + pristine_tree_hash: 0d45919224918553854f12e238fd6bb01f64b519 features: terraform: additionalDependencies: 0.1.0 - core: 3.29.0 - deprecations: 2.81.1 - envVarSecurityUsage: 0.1.0 - globalSecurity: 2.81.9 - globalServerURLs: 2.82.1 - retries: 2.81.2 + core: 3.46.26 + deprecations: 2.82.0 + globalSecurity: 2.82.1 + globalServerURLs: 2.83.0 + retries: 2.81.4 typeOverrides: 2.81.1 +trackedFiles: + .gitattributes: + id: 24139dae6567 + last_write_checksum: sha1:84b0115789fc3ea52e31df701d8a27f76077e29f + pristine_git_object: e6a994416d0f527912d2d272e2583458f4fc9bcb + USAGE.md: + id: 3aed33ce6e6f + last_write_checksum: sha1:02c32c9430f37507b3eacd41cdc36f080809e92d + pristine_git_object: 8e707bb129af1da185ba30b4c289b0160819c437 + examples/data-sources/epilot-designbuilder_design/data-source.tf: + id: 2f195ac634ee + last_write_checksum: sha1:cea9d1021d445c48d7f7437140a6ecdefd3ce48c + pristine_git_object: 0974cfceab3d4f40c89949bede268a197135d19a + examples/provider/provider.tf: + id: 954e955c0240 + last_write_checksum: sha1:13415405c7e531368e18f2f7c5bcde0df468b0ef + pristine_git_object: ee138537c59bbf3e0ae1543ede3545230fb1c29a + examples/resources/epilot-designbuilder_design/import-by-string-id.tf: + id: "853554071428" + last_write_checksum: sha1:4f9cf2e82ace940fd7f4bcaf8e9b2aa1e63f26f8 + pristine_git_object: 221980d2997ba86daf43f1856ef326e3d3a5ae9f + examples/resources/epilot-designbuilder_design/import.sh: + id: cb31ad3a4a93 + last_write_checksum: sha1:33795f34e1c7d937b181de182cf17c32902e88a7 + pristine_git_object: 916e0d989d2949fa95c4fa727a02bdcd7986b6dc + examples/resources/epilot-designbuilder_design/resource.tf: + id: cff5dadc8901 + last_write_checksum: sha1:06fee91ab468a68247170ad6ab847d1d687fc127 + pristine_git_object: ac822397fcb511a7a1b2c31dace7d51fd8152f9b + go.mod: + id: c47645c391ad + last_write_checksum: sha1:1267d05813181cd52ca621bf23a7200a74cfaa8f + pristine_git_object: 5e2238818b8bdf66fd440a570dd3b94b9222f974 + internal/planmodifiers/boolplanmodifier/suppress_diff.go: + id: 3cf85b98963e + last_write_checksum: sha1:b85207cab140498181910cb8d505aef46d37898a + pristine_git_object: 0789a46559fe0e8e04c37c79f76ce9aeaf36e252 + internal/planmodifiers/boolplanmodifier/use_config_value.go: + id: c0a10558e419 + last_write_checksum: sha1:506e2cac3ec4075a8837403860ef0b07e19bc337 + pristine_git_object: 210846ca24831a6bda811d3e8a42326716d7bf97 + internal/planmodifiers/float32planmodifier/suppress_diff.go: + id: b7f3f671e479 + last_write_checksum: sha1:9549ce0c7a562ab374d7ee988ad34033ecb1fe05 + pristine_git_object: e3d8e448a2485f451922b151f9335e11bbc1501c + internal/planmodifiers/float32planmodifier/use_config_value.go: + id: e75edfe23c08 + last_write_checksum: sha1:2683d9de3605886cb01438a9015c8e8b02b4e069 + pristine_git_object: 0aafffa779b10b01d1e9c831c3a4bda3e6d97789 + internal/planmodifiers/float64planmodifier/suppress_diff.go: + id: 7ae872c2243d + last_write_checksum: sha1:33b0004cb6f9644aa464837384fede0ad70139a6 + pristine_git_object: 9e49bcbf0b247942e9369ea004351f10276336ce + internal/planmodifiers/float64planmodifier/use_config_value.go: + id: 8fd8670f7434 + last_write_checksum: sha1:cc1f1cadfd17a0b9b1e729029dccc03f17d734a5 + pristine_git_object: ecd655b8d658d84aa5cbcc3e1808b69674071325 + internal/planmodifiers/int32planmodifier/suppress_diff.go: + id: 3ee3ede7dc9d + last_write_checksum: sha1:6bd00c0dbeefeaf7b1badc5ad60e62d4abc39922 + pristine_git_object: f3c6dcc93c50590cdae5467c45b8621d881d2b0f + internal/planmodifiers/int32planmodifier/use_config_value.go: + id: 40be4e07e289 + last_write_checksum: sha1:019ba1949b00493bf1a866821f9331d50c8a1f09 + pristine_git_object: ebc98aae308008b2cda39d5f4cfa781982afa44f + internal/planmodifiers/int64planmodifier/suppress_diff.go: + id: fade0cc85582 + last_write_checksum: sha1:f72ec74a83b5ecc6b62d5557b40cb671e1a0b0d9 + pristine_git_object: a5036037d9d8ef6aa8191fa93bb99d51411d108a + internal/planmodifiers/int64planmodifier/use_config_value.go: + id: e38d6f43d093 + last_write_checksum: sha1:b5a63f0c356cd72698e25e1b4f4fc3e29b35d482 + pristine_git_object: 2ec2d53d3ac13f58f64feb32b7fb07ca37b8fe99 + internal/planmodifiers/listplanmodifier/suppress_diff.go: + id: 7b93ed9460b9 + last_write_checksum: sha1:57492d63f8bc4c7c052138f98e1bf713c938e7bf + pristine_git_object: 29283f1725dc9502d3e4bde0da3c6fb41f7cc6ed + internal/planmodifiers/listplanmodifier/use_config_value.go: + id: c9b31b246860 + last_write_checksum: sha1:c56e2d23520ac7023f800328bb7599e7eba2f202 + pristine_git_object: 7e851c7613c71921fd4ccf7ca1f95b8b22ce9745 + internal/planmodifiers/mapplanmodifier/suppress_diff.go: + id: 37bee37da583 + last_write_checksum: sha1:20e28edf7270b7ffdabae148991f84dbc8ceb780 + pristine_git_object: 226a729a134e345800ce48cc2dea16bf529e1dae + internal/planmodifiers/mapplanmodifier/use_config_value.go: + id: 8fef370eccaa + last_write_checksum: sha1:7c2163c8fa4be8e8f7e7499cdb08cc5ed1924b39 + pristine_git_object: 0f2a717f45ca60218f4b8d9e81a6a5cd01494905 + internal/planmodifiers/numberplanmodifier/suppress_diff.go: + id: 0debe6a63221 + last_write_checksum: sha1:273d62fa4621c6692bb860d6676b2fd49af142be + pristine_git_object: e225903921d351ba305368f3f9b4a4f531b04c4e + internal/planmodifiers/numberplanmodifier/use_config_value.go: + id: e6b779d30d26 + last_write_checksum: sha1:9b92d53a4a5f57e211e6f41ebb6c36cb12357ae6 + pristine_git_object: e93c117a0665121b4c43c4a0fd5faec999ad016e + internal/planmodifiers/objectplanmodifier/suppress_diff.go: + id: c5bc1c3980dd + last_write_checksum: sha1:8425144025bb3a423c4f050a317a53cdd70153e1 + pristine_git_object: 148402f9b0a507ddd592197b6bc9dd34ae658321 + internal/planmodifiers/objectplanmodifier/use_config_value.go: + id: 7f103d324869 + last_write_checksum: sha1:1f2b6727605c0b56ff2212ab2e2528046f05b157 + pristine_git_object: eaf24076aeaf233c342886079be38561b94d3856 + internal/planmodifiers/setplanmodifier/suppress_diff.go: + id: 2db9381ea39f + last_write_checksum: sha1:723a8f3aeebc85654dc3b9cc90b9600bbe1dcd5f + pristine_git_object: e40d80004962c3bbc77f853aa51b12da91e7571a + internal/planmodifiers/setplanmodifier/use_config_value.go: + id: 62a591230001 + last_write_checksum: sha1:fe02165f8fd260bbce09f34adfa378376363422f + pristine_git_object: a95de11e54a028586b41352c084de59fdc7af66c + internal/planmodifiers/stringplanmodifier/suppress_diff.go: + id: 05379039a176 + last_write_checksum: sha1:1298a844497e270ee97b66af069a061c4121d074 + pristine_git_object: 5db4b89868a276845148e13da40a7baadf483e60 + internal/planmodifiers/stringplanmodifier/use_config_value.go: + id: a783ed056524 + last_write_checksum: sha1:250673402508661f9d12cfa026dc029d5e7855d9 + pristine_git_object: 8b4457aeb6b22b7f2b581434762e71f3f782897b + internal/planmodifiers/utils/state_check.go: + id: ead742412d0f + last_write_checksum: sha1:acc38ad698bf4fa8c51aa662076cf57b79024bd5 + pristine_git_object: 0ea64fbeb1fd7709d7241a8e06d34bfe9d0323d3 + internal/provider/design_data_source.go: + id: 4a8ebfc3c671 + last_write_checksum: sha1:bb0e99703c308f2f411823f51a4e2f0f3dcf00ff + pristine_git_object: 43d32e94052676e001f44346a2504037a6b5e607 + internal/provider/design_data_source_sdk.go: + id: 33bb40e45a9d + last_write_checksum: sha1:c39002f477df0d38530b1dd93b723711123c6f4c + pristine_git_object: b1ad66a3f77bdea5fecd2eca3e00337f6daf8ce6 + internal/provider/design_resource.go: + id: 877530140ad8 + last_write_checksum: sha1:7f7a9b0356c4f2466f04c0797272c1225f1248df + pristine_git_object: cf27336ebf11b4175a6021338727e7abfbac025e + internal/provider/design_resource_sdk.go: + id: 006033ec6a04 + last_write_checksum: sha1:e498bcb5a2beed699ca4e82fb70946915ac39bf3 + pristine_git_object: e281e4cf844e8cb1a17938575849e719b078d650 + internal/provider/provider.go: + id: 1e7e86841cf3 + last_write_checksum: sha1:6368f272bc2fa7075ad922c75fa7a758a0724012 + pristine_git_object: 249c4333740959e5e2db2e62fbc18993656a0ea2 + internal/provider/reflect/diags.go: + id: 35b6b44972e2 + last_write_checksum: sha1:ace8bc53054bb1d8ee8689acf3e4323de75a6297 + pristine_git_object: 50c50c8c2ee48a2e0bd9f7e01e9de02489c887d8 + internal/provider/reflect/doc.go: + id: cbfb54ee320b + last_write_checksum: sha1:67814656717ff0d0ff38fd9db09872e28666642b + pristine_git_object: e384126d4201af70574ce3a9fb8102edaa3b932e + internal/provider/reflect/generic_attr_value.go: + id: e422f9e35e9e + last_write_checksum: sha1:33300f91738c9b79e41ea4d8f3581d6800ac06ef + pristine_git_object: 48824d543386df6c125ed86da32d85d24659454c + internal/provider/reflect/helpers.go: + id: 3c19b91a8408 + last_write_checksum: sha1:3a2083aa9f84f5a54638803f2225daf86408d360 + pristine_git_object: 8085789a770637a76b1728b0f89b30c564696ca6 + internal/provider/reflect/interfaces.go: + id: d1096171c6f2 + last_write_checksum: sha1:e03017ee98ee8d1bd64fde7a025975638bcfaed7 + pristine_git_object: ff4416e40b7dd139a553979327b0dac70aff37c5 + internal/provider/reflect/into.go: + id: 50e3644442fc + last_write_checksum: sha1:7a29c6e2fd31069faddc441132ff04a92a6198be + pristine_git_object: 29a437fe2bdb30a956b8c7668d11032962962472 + internal/provider/reflect/map.go: + id: 0d8232fb373f + last_write_checksum: sha1:803a218b09d4d9de46d27a5c0227ed3fc6617f62 + pristine_git_object: 91e27a6c1d51441d6091752a0e199c300c1f09dc + internal/provider/reflect/number.go: + id: f7e5eb196c35 + last_write_checksum: sha1:ff756986a30b648c423b9af8996584ffc5983514 + pristine_git_object: 53673b8476a3115f39f7ed03921221243bbe29a3 + internal/provider/reflect/options.go: + id: ae46de5fdb32 + last_write_checksum: sha1:735603671bc13388dca9edeb7fefc0b229196793 + pristine_git_object: 002addd9ab508962b4dc80b0b1f788c738cb8382 + internal/provider/reflect/outof.go: + id: 2b83f83dde82 + last_write_checksum: sha1:46f09acf317888545161fc1cd288113bd3836ead + pristine_git_object: 215406a5867a4b5b6e0978a1664492049cc3738a + internal/provider/reflect/pointer.go: + id: b758e7c3bf1c + last_write_checksum: sha1:92cc23f30396e1a9204f70ac68ebfe7d58cbb967 + pristine_git_object: 215653e7c5d5ba9863ef5053d9084c9d69eba5ca + internal/provider/reflect/primitive.go: + id: c302568a3411 + last_write_checksum: sha1:8b7708414f8be915065952b31986869feaa2fae6 + pristine_git_object: adf648e88b61a8234951db180e4c25bbb7c1b353 + internal/provider/reflect/slice.go: + id: cd2dec5ab676 + last_write_checksum: sha1:70ce36709e204b74e3ded36c4683df7e48df294f + pristine_git_object: 79ad6b80c2a9492522820c3060a89f2de1131e92 + internal/provider/reflect/struct.go: + id: 973d7dbf96c1 + last_write_checksum: sha1:504fa0ca7711df0887f8c265c7acb3774e89afe7 + pristine_git_object: c588f768bd7b39be33962188f97d81e1c4c25f4b + internal/provider/typeconvert/date.go: + id: dfe2bc95ad1b + last_write_checksum: sha1:a5bcbbcc3de1ca3478bf7c5f289a67dad01330a2 + pristine_git_object: 066ba7364bd201cd6026ae2b32c0718d4e14ceb9 + internal/provider/typeconvert/datetime.go: + id: d2fb73d4f01c + last_write_checksum: sha1:a2a20e6785f1e12c3f94c016cbc106e54942e981 + pristine_git_object: 7bfdc553a393a1db69a25574998eb6cc5df79566 + internal/provider/typeconvert/int.go: + id: c44fcd78fccc + last_write_checksum: sha1:c28123f17006dc96a233f916a17c38408e37b71f + pristine_git_object: 54763e7a7555fae6d8bf51c4590220ff610202aa + internal/provider/types/design_tokens.go: + id: a1b10f787597 + last_write_checksum: sha1:3bf91039c9097cd79faec835f4f223bbbb662719 + pristine_git_object: 787b9e806d0b99b15d7d55742cc00673e4e5f4ce + internal/provider/types/user.go: + id: 76bcb6fc77f1 + last_write_checksum: sha1:0a95aa1f4d0125e519bbe79d72c2181c7e5f4dd6 + pristine_git_object: 3e629f2faed3c77cd0aa33507701c812265b8802 + internal/provider/utils.go: + id: 312d50f148af + last_write_checksum: sha1:2852a4804b9077fcfc10b5b48f0a6c4d921a7e40 + pristine_git_object: cee73be6d587b266b58f922d2e61c60548dd7b74 + internal/sdk/.gitattributes: + id: 1ea4c4e0a39d + last_write_checksum: sha1:84b0115789fc3ea52e31df701d8a27f76077e29f + pristine_git_object: e6a994416d0f527912d2d272e2583458f4fc9bcb + internal/sdk/designbuilder.go: + id: 8d14db67a75b + last_write_checksum: sha1:42903e9c7db9c8bf0c07b89c75bc5e6797188ec1 + pristine_git_object: 7ea988488c070a9a4ea344ae83dda355e5fc1a18 + internal/sdk/docs/models/operations/option.md: + id: a35737eb2e35 + last_write_checksum: sha1:08cfee5d266c9d82987e448f6c98a143aa42c5f8 + pristine_git_object: 35d8a1e2ad48a64702c6a654ac8880dabec053b0 + internal/sdk/internal/config/sdkconfiguration.go: + id: 6af0bc8635d9 + last_write_checksum: sha1:a42ebe3f09a88d1076fc0b1293481ec68fc45277 + pristine_git_object: f271f4670d6cbdb0448596946f32882001a9a847 + internal/sdk/internal/hooks/hooks.go: + id: 4e88208e997f + last_write_checksum: sha1:d342ac1eb7bc1dca33241df975bd49bb02f9182d + pristine_git_object: b76f0efcb0b6290e912647ba6987836a9316ad05 + internal/sdk/internal/utils/contenttype.go: + id: b767d5c02609 + last_write_checksum: sha1:ab5cfd860d02c6e6a37f89e2b5649a9859947fb1 + pristine_git_object: f6487e01eb987c0aa49e7aa50b5ff24830314c63 + internal/sdk/internal/utils/env.go: + id: 4b4be1422b75 + last_write_checksum: sha1:1e0bcb2d2caed9f3657f1dbc99b55811bed0298c + pristine_git_object: 110d464eacf2387b347bad1cb903666354a339e9 + internal/sdk/internal/utils/form.go: + id: a29055426367 + last_write_checksum: sha1:fb3cc78ddf5e1fd43fa10b2cd021800322e374ef + pristine_git_object: 526b356922b952ada0bdad2ea50d4fdd4ce2acbf + internal/sdk/internal/utils/headers.go: + id: f035883ac0ff + last_write_checksum: sha1:0e6903d69bbb9dcbc66f110039fcbecd048d03f1 + pristine_git_object: cfdee126d6ccc7b92e80064291ef62adb5cb8e75 + internal/sdk/internal/utils/json.go: + id: 2231afac3add + last_write_checksum: sha1:85dcb102411edc2f9351abcf8a93fc03073e37bb + pristine_git_object: a28fe892cf30003fd26b16e6dc98091149148744 + internal/sdk/internal/utils/pathparams.go: + id: e7fec2afe4a6 + last_write_checksum: sha1:fa8a32fa375b14783e7c3fd677ada181706403a1 + pristine_git_object: a91689f852bd5dabc5f8534ad55d9e75560c2cb3 + internal/sdk/internal/utils/queryparams.go: + id: fb88ad971185 + last_write_checksum: sha1:ee53a56dde311ada796793a621679461f9ed3097 + pristine_git_object: b17ee911565aa1dac0bad9f350cf1efeff9922a4 + internal/sdk/internal/utils/requestbody.go: + id: c971a8b3bbf5 + last_write_checksum: sha1:b1a292ef47871d476390e504070f92e266e7e907 + pristine_git_object: 16010221a84079f623b78f50959fe3ae09b3077a + internal/sdk/internal/utils/retries.go: + id: 6832c2142453 + last_write_checksum: sha1:238277584ebf9a676907bbdd5863dc13e2ffc203 + pristine_git_object: 2723b367fe60eec5625ec40a49630d69c38983e3 + internal/sdk/internal/utils/security.go: + id: 6ebe9eaeb99b + last_write_checksum: sha1:bb9cc1870101f6d2a990766f3eb0ea37292f7507 + pristine_git_object: 19dfa6f4607dea64b1dd61c211e072212e7a3cb2 + internal/sdk/internal/utils/union.go: + id: 183142835cfe + last_write_checksum: sha1:6032e5ca26f768489a5c3649ef13fc121c6d8a57 + pristine_git_object: e8bd72c9f8b81bc6ac8ad2fe5ad1c340e26ada77 + internal/sdk/internal/utils/union_test.go: + id: 4c885192f6f0 + last_write_checksum: sha1:83ac73c1901de4c6db90f65cf5879163f3d47a00 + pristine_git_object: f66814c73ace94d8e71d785fd6161fb405745754 + internal/sdk/internal/utils/utils.go: + id: feefcdf75dbd + last_write_checksum: sha1:d88d96cc244301d137581432095043f27a3e17b0 + pristine_git_object: 0415b536598baa76c5d1a8fc32816ed1b83f9137 + internal/sdk/models/errors/sdkerror.go: + id: 19b5a8d3586b + last_write_checksum: sha1:5d65fce5049df7c5113e11c9ccb1e4c46b91901c + pristine_git_object: c633d568d96b5297c7d2edfc9d22fc717428edf1 + internal/sdk/models/operations/addconsumer.go: + id: 55ee4e369087 + last_write_checksum: sha1:3044fa3a2834e19b17aba5dc7b13f6f1d9979540 + pristine_git_object: ddd873fba11b593115ae62af0239b205f818f71a + internal/sdk/models/operations/adddesign.go: + id: 895f7213bd20 + last_write_checksum: sha1:a6140b03a5dbf93d3372e36f3962de1d47a134e0 + pristine_git_object: 0eb9e3cc122e66f6549c2347b586e2770733a816 + internal/sdk/models/operations/deletedesign.go: + id: 2591f9d6ffa7 + last_write_checksum: sha1:290f773f08343499e4007b8a7267bc3a8f6fa39e + pristine_git_object: 2b2b364e869120fe0c0c35d66f9a289e85419c02 + internal/sdk/models/operations/getalldesigns.go: + id: 8927dc79e7d2 + last_write_checksum: sha1:318b482a62d45bf602e1deaaba9def036467f9cf + pristine_git_object: a01d93a1633e02b365d76725ec35bd966687dfe1 + internal/sdk/models/operations/getbrands.go: + id: 4993fee5d4ea + last_write_checksum: sha1:b79a16599daf57b33578e6ffc45ceef0255cbd01 + pristine_git_object: b57e7bc37a93ac4e72661a95017c899bea294a82 + internal/sdk/models/operations/getconsumerdesign.go: + id: 6c185a1326a8 + last_write_checksum: sha1:e0796f80dcb1d10fe193d7765a4773abeb2a0115 + pristine_git_object: 342bf6489bc1a4b89429dd5c325a7af67cb782ff + internal/sdk/models/operations/getdesign.go: + id: bf185a2564aa + last_write_checksum: sha1:17aa5b0fc49566989f6105765c95f41f338cd720 + pristine_git_object: 2dcb9aed3bbe2fa9fdd02917009780fcf1de138d + internal/sdk/models/operations/getfiles.go: + id: bc11e4667b7d + last_write_checksum: sha1:4949dc17a6290097e2e70a3d8995d7b6ba8a43e2 + pristine_git_object: 58cbaf887cee132cdf1dbfbd280c506657f67c77 + internal/sdk/models/operations/getlimit.go: + id: 04ab7a0b1fdf + last_write_checksum: sha1:59c973420477a69b6fcb0448fd0cb3351ccd3dbc + pristine_git_object: 4b8d1b2bc71d2adbbfbfa953463d0d6477573471 + internal/sdk/models/operations/getthemefromdesign.go: + id: e61094f3348b + last_write_checksum: sha1:212f24cc8a67d006b44b6fc639ddd6a8faa367d8 + pristine_git_object: bf837f43379165312d5bdd539d60c72373e570ce + internal/sdk/models/operations/options.go: + id: 6d0d29414e00 + last_write_checksum: sha1:bc042b6242d0bddde5e196a8cd7ea57c33953ee8 + pristine_git_object: de837a870525d3c3cafeb4f5f40fc4a10e9742b6 + internal/sdk/models/operations/removeconsumer.go: + id: c516828acad4 + last_write_checksum: sha1:60f0bf33f9aebb1dc3e0156fb56f6c6c08397cfb + pristine_git_object: 5b09563e4e2df1ff67f7cdedb1e3305c9827af96 + internal/sdk/models/operations/updatedesign.go: + id: bb2215c2649e + last_write_checksum: sha1:b8d3c0475f099a1feb31d9dcac9ebef79ed4c8a7 + pristine_git_object: 81829578db7e776b7ecd30054a847651eeeab260 + internal/sdk/models/operations/uploadfile.go: + id: 28014f45529f + last_write_checksum: sha1:52d64cf0ef7161b1661c469e0a1c9812d374d0a2 + pristine_git_object: ac47db254221de2a1e7be2d3c66c9ac1fa220c39 + internal/sdk/models/shared/addconsumerreq.go: + id: 55a55ed7cdda + last_write_checksum: sha1:b6ba9a2da4dd058e6ef5b8a55f3b0d4ab3250865 + pristine_git_object: 7aa50bef2490befe9d4d36bb69edf45153abcc4c + internal/sdk/models/shared/adddesignreq.go: + id: 25377e0b9f24 + last_write_checksum: sha1:a52515a41e3c7b9e647c30f335be67e4cf039b51 + pristine_git_object: 0e079e3cdd327e12f642d1b90a1978be2819d81c + internal/sdk/models/shared/adddesignres.go: + id: 1f022e678fef + last_write_checksum: sha1:231abe5c9ff2805b46d45f3d44453a38fe6eb8df + pristine_git_object: 449d0c73c1725b6fb21a1691e9ca7dcac8fe764b + internal/sdk/models/shared/branditem.go: + id: 1f45c71175fa + last_write_checksum: sha1:8019afed0cbc4fc39cf563674b3d73572bca316c + pristine_git_object: 251e54e45cfd8c72de9d66c395e1245e26e526d3 + internal/sdk/models/shared/errorresp.go: + id: 7302a8f1aa24 + last_write_checksum: sha1:f69d6368e8a5c929776b2bfc386e60d4b4bc438b + pristine_git_object: 574d2cec39c320b129d29a008070d03bd24c858d + internal/sdk/models/shared/filedata.go: + id: 50ff698eb421 + last_write_checksum: sha1:8adaa3e4e581d1d10d5968727cf1ce858ee33c44 + pristine_git_object: 124e1da9448d22e063b42ceda0da3c1b20ca3513 + internal/sdk/models/shared/getalldesignsres.go: + id: 4ee6eb215461 + last_write_checksum: sha1:4879e9940086c5c6317c7735b3286dc638c60be8 + pristine_git_object: 447619a9167648b4f2169aa21f996bf2f613c1f9 + internal/sdk/models/shared/getbrandsres.go: + id: b329276d32be + last_write_checksum: sha1:5e8382da6d7bfa933dddf2447f065b6d6ab55b15 + pristine_git_object: e31eb4fa725aa6ae4c4980123b2902cb960891db + internal/sdk/models/shared/getdesignres.go: + id: 1263504d6b89 + last_write_checksum: sha1:fd317072cf0bf1cb74b4561b3a2cd7e227371b82 + pristine_git_object: c78ed6c9e7e2712dc825ebb07ac571040c8ba26a + internal/sdk/models/shared/removeconsumerreq.go: + id: 92a1edcefb24 + last_write_checksum: sha1:981f62d15c5199f5b89f19e590468cee1a41a8b3 + pristine_git_object: 08fd66c61e02368cb7936acda7661e8f64b39f29 + internal/sdk/models/shared/security.go: + id: 9098af98367e + last_write_checksum: sha1:eac47289cd926bc6aad3cc29a2e5645b35d11766 + pristine_git_object: 4c8dd96900dc60ff52eaf34de98fba64094381aa + internal/sdk/models/shared/theme.go: + id: cf8801748beb + last_write_checksum: sha1:55b1ef2b77c6ec05c33a9f2d10c2c511a387fd0c + pristine_git_object: 0db176055f1896d4e4349de3124570d9ff4f8a84 + internal/sdk/models/shared/updatedesignreq.go: + id: c354b0d2da43 + last_write_checksum: sha1:bcd132470caba6bc1f6c39727785a8b8ab118664 + pristine_git_object: fd34568056080824224a807670af2e171eb8172f + internal/sdk/models/shared/uploadfilereq.go: + id: 71b6777944a5 + last_write_checksum: sha1:5b0ffc35b309b8085f06b4c90abedcc65efaf76a + pristine_git_object: 8a60fe47c7d6e78f8a92a541c447578230e50357 + internal/sdk/models/shared/uploadfileres.go: + id: 91755fc5f797 + last_write_checksum: sha1:ce423996915d5e1e0de024d822e713671b785a8b + pristine_git_object: 6423dd2a2e8bf0151095481420b7145142bcca60 + internal/sdk/optionalnullable/optionalnullable.go: + id: 4b83aa3f3df3 + last_write_checksum: sha1:d6aff1a420c31e025ea21d46cf056e305ae76fe8 + pristine_git_object: c6739be0619b6726565e0f11855ffe44b0e5607e + internal/sdk/optionalnullable/optionalnullable_test.go: + id: 3920a41dfc4c + last_write_checksum: sha1:2e9433eff1651ac77d6678ea76880d9a4980cbc2 + pristine_git_object: e6e5a01c6e721e879e24a38a1f97e3e27d4686d4 + internal/sdk/retry/config.go: + id: 7ea5fa9128b6 + last_write_checksum: sha1:f565273be789ffe0e3c160de1ac72a63cfe67fbe + pristine_git_object: aa809fccb3445b1e2530a979dad620512f50e70f + internal/sdk/sdk.go: + id: 02d7190ee502 + last_write_checksum: sha1:46f8b0e6ef0de17997a30b6e7cff1ff3dae8f315 + pristine_git_object: 0ff6996313b784505d02ad4851958a2ecd4b6448 + internal/sdk/types/bigint.go: + id: fc530b70337e + last_write_checksum: sha1:49b004005d0461fb04b846eca062b070b0360b31 + pristine_git_object: 9c6a086d51595888a6ff787ebcb8693559afee95 + internal/sdk/types/date.go: + id: c4bff082c66f + last_write_checksum: sha1:3036a2e1ed15a1d484c093367eba000c38f384d0 + pristine_git_object: 5b2782f219efe6bfbce46fc2dec68998eb759438 + internal/sdk/types/datetime.go: + id: a8109857c712 + last_write_checksum: sha1:196d050af6450669214e9ae4fd28e56263ae2b5d + pristine_git_object: 3eff332daa04e34cec5ffb10add670bafd8ac454 + internal/sdk/types/pointers.go: + id: 2f3f971639f6 + last_write_checksum: sha1:fc2275ea006257ba9ba4ff6f2a2cdb6205371eef + pristine_git_object: 35c439d2661e08fcb6a854096fd7b9a8561b3938 + internal/validators/DateValidator.go: + id: 4fdfa187ab97 + last_write_checksum: sha1:dcde3ee7dbe31661da0d19087e6ae67b7e6510fc + pristine_git_object: 1fecddeac8a318a8216750b2e0faf0c566907e59 + internal/validators/ExactlyOneChild.go: + id: 66e7bd50b47d + last_write_checksum: sha1:ab8e18d1763fbd5b262c3e7d917c81ac40ba839f + pristine_git_object: 1765a3a0b83d38a6cc8f118ea2cfab67ab44c910 + internal/validators/JSONParseValidator.go: + id: ce72f37482f5 + last_write_checksum: sha1:77af551821798350f868410aab90352f7ec7b370 + pristine_git_object: b8bb96b5e0930635eb754f169b3eaf285d48dd1c + internal/validators/RFC3339Validator.go: + id: 0cf126c9a956 + last_write_checksum: sha1:8d9accfc3aa477a74b0f927652f5e2ae3d28061d + pristine_git_object: f5e61466b5c639cb17d0cb2cfe28611957297ce9 + internal/validators/boolvalidators/not_null.go: + id: 865145e65396 + last_write_checksum: sha1:89a7362be9d519ed7c9fb7c4989d273a3aa5f279 + pristine_git_object: 6eca17e0cff87f7682f8baa2cd81cd33bc972f4c + internal/validators/float32validators/not_null.go: + id: 330748f4ff91 + last_write_checksum: sha1:4f0a859aa9d7348056c6559bad9ca336104beaef + pristine_git_object: c9a8973c7dc830b9c5aac546ea7cbe6021f01629 + internal/validators/float64validators/not_null.go: + id: 8f5e6362f0f5 + last_write_checksum: sha1:f2436a4a1323d58ffcff3b153167c4e463325c12 + pristine_git_object: 8f786d278597ffac3c525755e429c9a3caa60b20 + internal/validators/int32validators/not_null.go: + id: ea876d1f8b07 + last_write_checksum: sha1:d08335af46ab809d0076da8543b3455662fb66a0 + pristine_git_object: ec9a3f10adfdd29c3cca40e53dc42db329cf37d7 + internal/validators/int64validators/not_null.go: + id: d3f822eb4c69 + last_write_checksum: sha1:b5bf5b539f2631813ee8771cf00d8ea9744c6dd3 + pristine_git_object: 707ff9573f026b7b7ee3f59462c7a8ba10a1aba9 + internal/validators/listvalidators/not_null.go: + id: b3ee156dafa7 + last_write_checksum: sha1:11f33dfa3cb1b9eadc7e4a8287518135ddae191e + pristine_git_object: 9b88e520b7d58c14c6844d3dbc26ce4f96d39af1 + internal/validators/mapvalidators/not_null.go: + id: 9cff80d0791c + last_write_checksum: sha1:64117afe6cdb1a0e1b57df970da8df0e18d10442 + pristine_git_object: dc6959e9cdadb16e0e1ea90f98b2d27f2d357b64 + internal/validators/numbervalidators/not_null.go: + id: b335c948bcf4 + last_write_checksum: sha1:54d925f13a630f21e14709ce6181e5eaf96bd6e3 + pristine_git_object: 57d4da0ae000f671698384abc550196744884871 + internal/validators/objectvalidators/not_null.go: + id: dd14631b3a38 + last_write_checksum: sha1:5f897f5dcd2686d43c9bd683900572a8d7ef6473 + pristine_git_object: bf0189497acb3b1214f2480e9db071186d85ecad + internal/validators/setvalidators/not_null.go: + id: e612a6618fac + last_write_checksum: sha1:de772bcb14615735a8ebd2a9ffaae06f464a86d5 + pristine_git_object: f859d64810168dd4ec7bfb1ea1c0186c551f8987 + internal/validators/stringvalidators/not_null.go: + id: 80be7ffedf6c + last_write_checksum: sha1:df498b49dd87f9508f3eaec3a63ed0a08ae3c16e + pristine_git_object: 1e40ac1b6ce68540327e01910f0dc91a60b62607 + main.go: + id: 0607f785dfa3 + last_write_checksum: sha1:500038ee48ea03bb24b1a2771baf6e3f1d6b1ea1 + pristine_git_object: 1123d76a0935c3f4471b62d0f4e2aa16cd97f5d8 + terraform-registry-manifest.json: + id: fc3d63fd06e1 + last_write_checksum: sha1:45b609f3f65164bc2f00b6e2b24faf64627e15b8 + pristine_git_object: fec2a5691e493a1941bd79b312b3925403a91aa6 + tools/tools.go: + id: 683390d33800 + last_write_checksum: sha1:8239addbb5e66af0488adc7dc4aba098e4634d88 + pristine_git_object: 36b25801b3a26b57ee042a610a3c35ca65b1376a +examples: + addConsumer: + speakeasy-default-add-consumer: + parameters: + path: + designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" + application: "journey" + requestBody: + application/json: {"consumer_id": "4a062990-a6a3-11eb-9828-4f3da7d4935a", "consumer_name": ""} + responses: + "400": + application/json: {} + "500": + application/json: {} + addDesign: + speakeasy-default-add-design: + requestBody: + application/json: {"design": {"style": "", "style_name": ""}} + responses: + "201": + application/json: {"design": {"created_at": "2021-01-30T08:30:00Z", "edited": true, "style": "", "style_name": ""}} + "400": + application/json: {} + "500": + application/json: {} + deleteDesign: + speakeasy-default-delete-design: + parameters: + path: + designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" + responses: + "400": + application/json: {} + "500": + application/json: {} + getAllDesigns: + speakeasy-default-get-all-designs: + responses: + "200": + application/json: {"designs": [{"created_at": "2021-01-30T08:30:00Z", "edited": true, "style": "", "style_name": ""}]} + "500": + application/json: {} + getBrands: + speakeasy-default-get-brands: + responses: + "200": + application/json: [{}] + "500": + application/json: {} + getConsumerDesign: + speakeasy-default-get-consumer-design: + parameters: + path: + consumerId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" + application: "journey" + responses: + "200": + application/json: {"design": {"created_at": "2021-01-30T08:30:00Z", "edited": false, "style": "", "style_name": ""}} + "400": + application/json: {} + "500": + application/json: {} + getDesign: + speakeasy-default-get-design: + parameters: + path: + designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" + responses: + "200": + application/json: {"design": {"created_at": "2021-01-30T08:30:00Z", "edited": false, "style": "", "style_name": ""}} + "400": + application/json: {} + "500": + application/json: {} + getFiles: + speakeasy-default-get-files: + parameters: + query: + type: "LOGO" + responses: + "200": + application/json: [{"name": "", "s3_object_key": "", "url": "https://colorful-obligation.name"}] + "400": + application/json: {} + "500": + application/json: {} + getLimit: + speakeasy-default-get-limit: + responses: + "200": + application/json: 8443.97 + "500": + application/json: {} + getThemeFromDesign: + speakeasy-default-get-theme-from-design: + parameters: + path: + designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" + query: + theme: "NEW" + responses: + "200": + application/json: {} + "400": + application/json: {} + "500": + application/json: {} + removeConsumer: + speakeasy-default-remove-consumer: + parameters: + path: + designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" + application: "journey" + requestBody: + application/json: {"consumer_id": "4a062990-a6a3-11eb-9828-4f3da7d4935a"} + responses: + "400": + application/json: {} + "500": + application/json: {} + updateDesign: + speakeasy-default-update-design: + parameters: + path: + designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" + requestBody: + application/json: {"design": {"style": "", "style_name": ""}} + responses: + "400": + application/json: {} + "500": + application/json: {} + uploadFile: + speakeasy-default-upload-file: + requestBody: + multipart/form-data: {"file_data": "", "file_name": "example.file", "file_type": "LOGO"} + responses: + "201": + application/json: {"name": "", "s3_object_key": "", "url": "https://boring-roundabout.biz/"} + "400": + application/json: {} + "500": + application/json: {} +examplesVersion: 1.0.2 +generatedTests: {} +releaseNotes: "## Terraform SDK Changes:\n* `SDK.design-builder.getDesign()`: `response` **Changed** **Breaking** :warning:\n* `SDK.design-builder.addDesign()`: \n * `request.design` **Changed** **Breaking** :warning:\n * `response` **Changed** **Breaking** :warning:\n* `SDK.design-builder.getAllDesigns()`: `response` **Changed** **Breaking** :warning:\n* `SDK.design-builder.getConsumerDesign()`: `response` **Changed** **Breaking** :warning:\n* `SDK.design-builder.removeConsumer()`: \n * `request` **Changed** **Breaking** :warning:\n * `response.error` **Added**\n* `SDK.design-builder.updateDesign()`: \n * `request.UpdateDesignReq.design` **Changed** **Breaking** :warning:\n * `response.error` **Added**\n* `SDK.design-builder.deleteDesign()`: `response.error` **Added**\n* `SDK.design-builder.getBrands()`: `response.error` **Added**\n* `SDK.design-builder.addConsumer()`: `response.error` **Added**\n* `SDK.design-builder.getFiles()`: `response.error` **Added**\n* `SDK.design-builder.getLimit()`: `response.error` **Added**\n* `SDK.design-builder.getThemeFromDesign()`: \n * `request.theme` **Changed**\n * `response.error` **Added**\n* `SDK.design-builder.uploadFile()`: `response.error` **Added**\n" generatedFiles: - .gitattributes - USAGE.md @@ -122,104 +792,3 @@ generatedFiles: - main.go - terraform-registry-manifest.json - tools/tools.go -examples: - addConsumer: - "": - parameters: - path: - application: "journey" - designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" - requestBody: - application/json: {"consumer_id": "", "consumer_name": ""} - addDesign: - speakeasy-default-add-design: - requestBody: - application/json: {"design": {"style": {"consumer": {"customer_portals": [{"id": "", "name": ""}], "widgets": [{"id": "", "name": ""}, {"id": "", "name": ""}, {"id": "", "name": ""}]}, "palette": {"background": "", "error": "", "navbar": "", "paper": "", "primary": "", "secondary": ""}, "typography": {"font": {"font_id": "", "font_name": "", "urls": [{}, {}]}, "primary": "", "secondary": ""}}, "style_name": ""}} - responses: - "201": - application/json: {"design": {"created_at": "2021-01-30T08:30:00Z", "edited": true, "style": {"consumer": {"customer_portals": [{"id": "", "name": ""}, {"id": "", "name": ""}, {"id": "", "name": ""}], "widgets": [{"id": "", "name": ""}, {"id": "", "name": ""}]}, "palette": {"background": "", "error": "", "navbar": "", "paper": "", "primary": "", "secondary": ""}, "typography": {"font": {"font_id": "", "font_name": "", "urls": [{}]}, "primary": "", "secondary": ""}}, "style_name": ""}} - "400": - application/json: {} - "500": - application/json: {} - deleteDesign: - "": - parameters: - path: - designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" - getAllDesigns: - speakeasy-default-get-all-designs: - responses: - "200": - application/json: [{"designs": [{"created_at": "2021-01-30T08:30:00Z", "edited": true, "style": {"consumer": {"customer_portals": [{"id": "", "name": ""}], "widgets": []}, "palette": {"background": "", "error": "", "navbar": "", "paper": "", "primary": "", "secondary": ""}, "typography": {"font": {"font_id": "", "font_name": "", "urls": [{}]}, "primary": "", "secondary": ""}}, "style_name": ""}]}] - "500": - application/json: {} - getBrands: - speakeasy-default-get-brands: - responses: - "200": - application/json: [{}] - "500": - application/json: {} - getConsumerDesign: - "": - parameters: - path: - application: "journey" - consumerId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" - responses: - "200": - application/json: {"design": {"created_at": "2021-01-30T08:30:00Z", "edited": false, "style": {"consumer": {"customer_portals": [{"id": "", "name": ""}, {"id": "", "name": ""}], "widgets": [{"id": "", "name": ""}, {"id": "", "name": ""}]}, "palette": {"background": "", "error": "", "navbar": "", "paper": "", "primary": "", "secondary": ""}, "typography": {"font": {"font_id": "", "font_name": "", "urls": []}, "primary": "", "secondary": ""}}, "style_name": ""}} - "400": {} - "500": {} - getDesign: - "": - parameters: - path: - designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" - responses: - "200": - application/json: {"design": {"created_at": "2021-01-30T08:30:00Z", "edited": false, "style": {"consumer": {"customer_portals": [{"id": "", "name": ""}, {"id": "", "name": ""}, {"id": "", "name": ""}], "widgets": [{"id": "", "name": ""}, {"id": "", "name": ""}]}, "palette": {"background": "", "error": "", "navbar": "", "paper": "", "primary": "", "secondary": ""}, "typography": {"font": {"font_id": "", "font_name": "", "urls": []}, "primary": "", "secondary": ""}}, "style_name": ""}} - "400": {} - "500": {} - getFiles: - "": - parameters: - query: - type: "LOGO" - responses: - "200": - application/json: [{"name": "", "s3_object_key": "", "url": "https://nifty-squid.info"}, {"name": "", "s3_object_key": "", "url": "https://next-cinema.name/"}] - "400": {} - "500": {} - getLimit: - speakeasy-default-get-limit: - responses: - "200": - application/json: 8111.85 - "500": - application/json: {} - getThemeFromDesign: - "": - parameters: - path: - designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" - query: - theme: "NEW" - removeConsumer: - "": - parameters: - path: - application: "journey" - designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" - requestBody: - application/json: {"consumer_id": "", "consumer_name": ""} - updateDesign: - "": - parameters: - path: - designId: "4a062990-a6a3-11eb-9828-4f3da7d4935a" - requestBody: - application/json: {"design": {"style": {"consumer": {"customer_portals": [{"id": "", "name": ""}], "widgets": [{"id": "", "name": ""}]}, "palette": {"background": "", "error": "", "navbar": "", "paper": "", "primary": "", "secondary": ""}, "typography": {"font": {"font_id": "", "font_name": "", "urls": []}, "primary": "", "secondary": ""}}, "style_name": ""}} -examplesVersion: 1.0.0 -generatedTests: {} diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index 54c3ce9..1efbeb3 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -1,19 +1,19 @@ -speakeasyVersion: 1.477.2 +speakeasyVersion: 1.680.4 sources: my-source: sourceNamespace: my-source - sourceRevisionDigest: sha256:662a7e163d8a31aef7774a68e86e032c01b94a11e11c5001f7a5cf2b7b1cd53c - sourceBlobDigest: sha256:ec33bbdc357a273611e581125547c2cefe0f3bf75e58500ae01a4a34159ceb20 + sourceRevisionDigest: sha256:1abe06ddd9a3624cbc29cdce348ceede8a5398f297f142bf579ad321a9760720 + sourceBlobDigest: sha256:e3c6fc1ceba5dffe05694fef6570e04f60a7eac0dfbdc8ed6096dd7806076352 tags: - latest - - speakeasy-sdk-regen-1738252747 + - speakeasy-sdk-regen-1758759331 - 0.0.1 targets: terraform: source: my-source sourceNamespace: my-source - sourceRevisionDigest: sha256:662a7e163d8a31aef7774a68e86e032c01b94a11e11c5001f7a5cf2b7b1cd53c - sourceBlobDigest: sha256:ec33bbdc357a273611e581125547c2cefe0f3bf75e58500ae01a4a34159ceb20 + sourceRevisionDigest: sha256:1abe06ddd9a3624cbc29cdce348ceede8a5398f297f142bf579ad321a9760720 + sourceBlobDigest: sha256:e3c6fc1ceba5dffe05694fef6570e04f60a7eac0dfbdc8ed6096dd7806076352 workflow: workflowVersion: 1.0.0 speakeasyVersion: latest diff --git a/README.md b/README.md index 4986fdf..a1b7f74 100755 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ terraform { required_providers { epilot-designbuilder = { source = "epilot-dev/epilot-designbuilder" - version = "0.14.2" + version = "0.15.0" } } } @@ -71,6 +71,18 @@ provider_installation { ``` + +## Authentication + +This provider supports authentication configuration via provider configuration. + +Available configuration: + +| Provider Attribute | Description | +|---|---| +| `custom_authorizer` | HTTP Bearer. | + + ## Available Resources and Data Sources @@ -93,6 +105,7 @@ provider_installation { * [Installation](#installation) * [Testing the provider locally](#testing-the-provider-locally) + * [Authentication](#authentication) * [Available Resources and Data Sources](#available-resources-and-data-sources) diff --git a/RELEASES.md b/RELEASES.md index f89ffc1..e57e7c1 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -60,4 +60,14 @@ Based on: ### Generated - [terraform v0.13.0] . ### Releases -- [Terraform v0.13.0] https://registry.terraform.io/providers/epilot-dev/epilot-designbuilder/0.13.0 - . \ No newline at end of file +- [Terraform v0.13.0] https://registry.terraform.io/providers/epilot-dev/epilot-designbuilder/0.13.0 - . + +## 2025-12-23 00:18:11 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.680.4 (2.788.7) https://github.com/speakeasy-api/speakeasy +### Generated +- [terraform v0.15.0] . +### Releases +- [Terraform v0.15.0] https://registry.terraform.io/providers/epilot-dev/epilot-designbuilder/0.15.0 - . \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 62f3297..12893aa 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,6 @@ --- # generated by https://github.com/hashicorp/terraform-plugin-docs page_title: "epilot-designbuilder Provider" -subcategory: "" description: |- --- @@ -17,7 +16,7 @@ terraform { required_providers { epilot-designbuilder = { source = "epilot-dev/epilot-designbuilder" - version = "0.14.2" + version = "0.15.0" } } } @@ -32,5 +31,5 @@ provider "epilot-designbuilder" { ### Optional -- `custom_authorizer` (String, Sensitive) +- `custom_authorizer` (String, Sensitive) HTTP Bearer. - `server_url` (String) Server URL (defaults to https://design-builder-api.sls.epilot.io) diff --git a/docs/resources/design.md b/docs/resources/design.md index fa85be3..882085c 100644 --- a/docs/resources/design.md +++ b/docs/resources/design.md @@ -85,6 +85,17 @@ Optional: Import is supported using the following syntax: +In Terraform v1.5.0 and later, the [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used with the `id` attribute, for example: + +```terraform +import { + to = epilot-designbuilder_design.my_epilot-designbuilder_design + id = "..." +} +``` + +The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example: + ```shell -terraform import epilot-designbuilder_design.my_epilot-designbuilder_design "" +terraform import epilot-designbuilder_design.my_epilot-designbuilder_design "..." ``` diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf index 1a847d2..ee13853 100644 --- a/examples/provider/provider.tf +++ b/examples/provider/provider.tf @@ -2,7 +2,7 @@ terraform { required_providers { epilot-designbuilder = { source = "epilot-dev/epilot-designbuilder" - version = "0.14.2" + version = "0.15.0" } } } diff --git a/examples/resources/epilot-designbuilder_design/import-by-string-id.tf b/examples/resources/epilot-designbuilder_design/import-by-string-id.tf new file mode 100644 index 0000000..221980d --- /dev/null +++ b/examples/resources/epilot-designbuilder_design/import-by-string-id.tf @@ -0,0 +1,4 @@ +import { + to = epilot-designbuilder_design.my_epilot-designbuilder_design + id = "..." +} diff --git a/examples/resources/epilot-designbuilder_design/import.sh b/examples/resources/epilot-designbuilder_design/import.sh index 7014638..916e0d9 100644 --- a/examples/resources/epilot-designbuilder_design/import.sh +++ b/examples/resources/epilot-designbuilder_design/import.sh @@ -1 +1 @@ -terraform import epilot-designbuilder_design.my_epilot-designbuilder_design "" +terraform import epilot-designbuilder_design.my_epilot-designbuilder_design "..." diff --git a/gen.yaml b/gen.yaml index b9f8785..98771a7 100755 --- a/gen.yaml +++ b/gen.yaml @@ -3,24 +3,46 @@ generation: sdkClassName: SDK usageSnippets: optionalPropertyRendering: withExample + sdkInitStyle: constructor fixes: - nameResolutionDec2023: false + nameResolutionFeb2025: false parameterOrderingFeb2024: false requestResponseComponentNamesFeb2024: false + securityFeb2025: false + sharedErrorComponentsApr2025: false auth: oAuth2ClientCredentialsEnabled: false oAuth2PasswordEnabled: false + hoistGlobalSecurity: true + schemas: + allOfMergeStrategy: shallowMerge + requestBodyFieldName: "" + persistentEdits: {} + tests: + generateTests: true + generateNewTests: false + skipResponseBodyAssertions: false telemetryEnabled: false terraform: - version: 0.14.2 + version: 0.15.0 additionalDataSources: [] additionalDependencies: {} + additionalEphemeralResources: [] + additionalProviderAttributes: + httpHeaders: "" + tlsSkipVerify: "" additionalResources: [] allowUnknownFieldsInWeakUnions: false author: epilot-dev + baseErrorName: SDKBaseError + debugLogging: {} defaultErrorName: SDKError + enableCustomCodeRegions: false + enableOperationSecurity: false + enableOperationServers: false enableTypeDeduplication: true environmentVariables: [] + excludeEmptyObjectSchemas: false imports: option: openapi paths: @@ -29,6 +51,10 @@ terraform: operations: operations shared: shared webhooks: webhooks + includeEmptyObjects: false + inferUnionDiscriminators: false inputModelSuffix: input outputModelSuffix: output packageName: epilot-designbuilder + respectRequiredFields: false + unionStrategy: populated-fields diff --git a/go.mod b/go.mod index 1e7c3f5..5e22388 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,17 @@ module github.com/epilot-dev/terraform-provider-epilot-designbuilder -go 1.22.0 +go 1.23.7 require ( - github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 + github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 github.com/hashicorp/go-uuid v1.0.3 - github.com/hashicorp/terraform-plugin-docs v0.19.4 - github.com/hashicorp/terraform-plugin-framework v1.12.0 - github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 - github.com/hashicorp/terraform-plugin-go v0.24.0 + github.com/hashicorp/terraform-plugin-docs v0.22.0 + github.com/hashicorp/terraform-plugin-framework v1.15.1 + github.com/hashicorp/terraform-plugin-framework-jsontypes v0.2.0 + github.com/hashicorp/terraform-plugin-framework-validators v0.18.0 + github.com/hashicorp/terraform-plugin-go v0.28.0 github.com/hashicorp/terraform-plugin-log v0.9.0 + github.com/stretchr/testify v1.8.3 ) require ( @@ -18,56 +20,59 @@ require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect - github.com/ProtonMail/go-crypto v1.1.0-alpha.2 // indirect + github.com/ProtonMail/go-crypto v1.1.6 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect - github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect - github.com/cloudflare/circl v1.3.7 // indirect + github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect + github.com/cloudflare/circl v1.6.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.16.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/hashicorp/cli v1.1.6 // indirect + github.com/hashicorp/cli v1.1.7 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.6.1 // indirect + github.com/hashicorp/go-plugin v1.6.3 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-version v1.7.0 // indirect - github.com/hashicorp/hc-install v0.7.0 // indirect - github.com/hashicorp/terraform-exec v0.21.0 // indirect - github.com/hashicorp/terraform-json v0.22.1 // indirect - github.com/hashicorp/terraform-registry-address v0.2.3 // indirect + github.com/hashicorp/hc-install v0.9.2 // indirect + github.com/hashicorp/terraform-exec v0.23.0 // indirect + github.com/hashicorp/terraform-json v0.25.0 // indirect + github.com/hashicorp/terraform-registry-address v0.2.5 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.15 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/run v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/posener/complete v1.2.3 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/yuin/goldmark v1.7.1 // indirect + github.com/yuin/goldmark v1.7.7 // indirect github.com/yuin/goldmark-meta v1.1.0 // indirect - github.com/zclconf/go-cty v1.14.4 // indirect + github.com/zclconf/go-cty v1.16.3 // indirect go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect - golang.org/x/crypto v0.24.0 // indirect + golang.org/x/crypto v0.38.0 // indirect golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect - google.golang.org/grpc v1.66.2 // indirect - google.golang.org/protobuf v1.34.2 // indirect + golang.org/x/mod v0.25.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect + google.golang.org/grpc v1.72.1 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 762ad5a..77529c9 100644 --- a/go.sum +++ b/go.sum @@ -10,31 +10,31 @@ github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7Y github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg= -github.com/ProtonMail/go-crypto v1.1.0-alpha.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= +github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= -github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38= +github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= +github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 h1:S92OBrGuLLZsyM5ybUzgc/mPjIYk2AZqufieooe98uw= -github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ= +github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 h1:R/ZjJpjQKsZ6L/+Gf9WHbt31GG8NMVcpRqUE+1mMIyo= +github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= @@ -42,21 +42,25 @@ github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3 github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= -github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= -github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= +github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= +github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= +github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/cli v1.1.6 h1:CMOV+/LJfL1tXCOKrgAX0uRKnzjj/mpmqNXloRSy2K8= -github.com/hashicorp/cli v1.1.6/go.mod h1:MPon5QYlgjjo0BSoAiN0ESeT5fRzDjVRp+uioJ0piz4= +github.com/hashicorp/cli v1.1.7 h1:/fZJ+hNdwfTSfsxMBa9WWMlfjUZbX8/LnUxgAd7lCVU= +github.com/hashicorp/cli v1.1.7/go.mod h1:e6Mfpga9OCT1vqzFuoGZiiF/KaG9CbUfO5s3ghU3YgU= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -65,36 +69,40 @@ github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuD github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI= -github.com/hashicorp/go-plugin v1.6.1/go.mod h1:XPHFku2tFo3o3QKFgSYo+cghcUhw1NA1hZyMK0PWAw0= +github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= +github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/hc-install v0.7.0 h1:Uu9edVqjKQxxuD28mR5TikkKDd/p55S8vzPC1659aBk= -github.com/hashicorp/hc-install v0.7.0/go.mod h1:ELmmzZlGnEcqoUMKUuykHaPCIR1sYLYX+KSggWSKZuA= -github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ= -github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg= -github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec= -github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A= -github.com/hashicorp/terraform-plugin-docs v0.19.4 h1:G3Bgo7J22OMtegIgn8Cd/CaSeyEljqjH3G39w28JK4c= -github.com/hashicorp/terraform-plugin-docs v0.19.4/go.mod h1:4pLASsatTmRynVzsjEhbXZ6s7xBlUw/2Kt0zfrq8HxA= -github.com/hashicorp/terraform-plugin-framework v1.12.0 h1:7HKaueHPaikX5/7cbC1r9d1m12iYHY+FlNZEGxQ42CQ= -github.com/hashicorp/terraform-plugin-framework v1.12.0/go.mod h1:N/IOQ2uYjW60Jp39Cp3mw7I/OpC/GfZ0385R0YibmkE= -github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 h1:bxZfGo9DIUoLLtHMElsu+zwqI4IsMZQBRRy4iLzZJ8E= -github.com/hashicorp/terraform-plugin-framework-validators v0.13.0/go.mod h1:wGeI02gEhj9nPANU62F2jCaHjXulejm/X+af4PdZaNo= -github.com/hashicorp/terraform-plugin-go v0.24.0 h1:2WpHhginCdVhFIrWHxDEg6RBn3YaWzR2o6qUeIEat2U= -github.com/hashicorp/terraform-plugin-go v0.24.0/go.mod h1:tUQ53lAsOyYSckFGEefGC5C8BAaO0ENqzFd3bQeuYQg= +github.com/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24= +github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I= +github.com/hashicorp/terraform-exec v0.23.0 h1:MUiBM1s0CNlRFsCLJuM5wXZrzA3MnPYEsiXmzATMW/I= +github.com/hashicorp/terraform-exec v0.23.0/go.mod h1:mA+qnx1R8eePycfwKkCRk3Wy65mwInvlpAeOwmA7vlY= +github.com/hashicorp/terraform-json v0.25.0 h1:rmNqc/CIfcWawGiwXmRuiXJKEiJu1ntGoxseG1hLhoQ= +github.com/hashicorp/terraform-json v0.25.0/go.mod h1:sMKS8fiRDX4rVlR6EJUMudg1WcanxCMoWwTLkgZP/vc= +github.com/hashicorp/terraform-plugin-docs v0.22.0 h1:fwIDStbFel1PPNkM+mDPnpB4efHZBdGoMz/zt5FbTDw= +github.com/hashicorp/terraform-plugin-docs v0.22.0/go.mod h1:55DJVyZ7BNK4t/lANcQ1YpemRuS6KsvIO1BbGA+xzGE= +github.com/hashicorp/terraform-plugin-framework v1.15.1 h1:2mKDkwb8rlx/tvJTlIcpw0ykcmvdWv+4gY3SIgk8Pq8= +github.com/hashicorp/terraform-plugin-framework v1.15.1/go.mod h1:hxrNI/GY32KPISpWqlCoTLM9JZsGH3CyYlir09bD/fI= +github.com/hashicorp/terraform-plugin-framework-jsontypes v0.2.0 h1:SJXL5FfJJm17554Kpt9jFXngdM6fXbnUnZ6iT2IeiYA= +github.com/hashicorp/terraform-plugin-framework-jsontypes v0.2.0/go.mod h1:p0phD0IYhsu9bR4+6OetVvvH59I6LwjXGnTVEr8ox6E= +github.com/hashicorp/terraform-plugin-framework-validators v0.18.0 h1:OQnlOt98ua//rCw+QhBbSqfW3QbwtVrcdWeQN5gI3Hw= +github.com/hashicorp/terraform-plugin-framework-validators v0.18.0/go.mod h1:lZvZvagw5hsJwuY7mAY6KUz45/U6fiDR0CzQAwWD0CA= +github.com/hashicorp/terraform-plugin-go v0.28.0 h1:zJmu2UDwhVN0J+J20RE5huiF3XXlTYVIleaevHZgKPA= +github.com/hashicorp/terraform-plugin-go v0.28.0/go.mod h1:FDa2Bb3uumkTGSkTFpWSOwWJDwA7bf3vdP3ltLDTH6o= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= -github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI= -github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM= +github.com/hashicorp/terraform-registry-address v0.2.5 h1:2GTftHqmUhVOeuu9CW3kwDkRe4pcBDq0uuK5VJngU1M= +github.com/hashicorp/terraform-registry-address v0.2.5/go.mod h1:PpzXWINwB5kuVS5CA7m1+eO2f1jKb5ZDIxrOPfpnGkg= github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ= github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= @@ -116,11 +124,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= @@ -135,21 +142,21 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= -github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= +github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= +github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= -github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= +github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= @@ -158,8 +165,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -167,34 +174,44 @@ github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U= -github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark v1.7.7 h1:5m9rrB1sW3JUMToKFQfb+FGt1U7r57IHu5GrYrG2nqU= +github.com/yuin/goldmark v1.7.7/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= -github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= -github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty v1.16.3 h1:osr++gw2T61A8KVYHoQiFbFd1Lh3JOCXc/jFLJXKTxk= +github.com/zclconf/go-cty v1.16.3/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= go.abhg.dev/goldmark/frontmatter v0.2.0 h1:P8kPG0YkL12+aYk2yU3xHv4tcXzeVnN+gU0tJ5JnxRw= go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -205,11 +222,10 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -217,20 +233,20 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= -google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= diff --git a/internal/planmodifiers/boolplanmodifier/use_config_value.go b/internal/planmodifiers/boolplanmodifier/use_config_value.go new file mode 100644 index 0000000..210846c --- /dev/null +++ b/internal/planmodifiers/boolplanmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package boolplanmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.Bool { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifyBool(ctx context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.BoolNull() + } +} diff --git a/internal/planmodifiers/float32planmodifier/suppress_diff.go b/internal/planmodifiers/float32planmodifier/suppress_diff.go new file mode 100644 index 0000000..e3d8e44 --- /dev/null +++ b/internal/planmodifiers/float32planmodifier/suppress_diff.go @@ -0,0 +1,56 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package float32planmodifier + +import ( + "context" + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/planmodifiers/utils" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" +) + +const ( + // ExplicitSuppress strategy suppresses "(known after changes)" messages unless we're in the initial creation + ExplicitSuppress = iota +) + +// SuppressDiff returns a plan modifier that propagates a state value into the planned value, when it is Known, and the Plan Value is Unknown +func SuppressDiff(strategy int) planmodifier.Float32 { + return suppressDiff{ + strategy: strategy, + } +} + +// suppressDiff implements the plan modifier. +type suppressDiff struct { + strategy int +} + +// Description returns a human-readable description of the plan modifier. +func (m suppressDiff) Description(_ context.Context) string { + return "Once set, the value of this attribute in state will not change." +} + +// MarkdownDescription returns a markdown description of the plan modifier. +func (m suppressDiff) MarkdownDescription(_ context.Context) string { + return "Once set, the value of this attribute in state will not change." +} + +// PlanModifyFloat32 implements the plan modification logic. +func (m suppressDiff) PlanModifyFloat32(ctx context.Context, req planmodifier.Float32Request, resp *planmodifier.Float32Response) { + // Do nothing if there is a known planned value. + if !req.PlanValue.IsUnknown() { + return + } + + // Do nothing if there is an unknown configuration value + if req.ConfigValue.IsUnknown() { + return + } + + if utils.IsAllStateUnknown(ctx, req.State) { + return + } + + resp.PlanValue = req.StateValue +} diff --git a/internal/planmodifiers/float32planmodifier/use_config_value.go b/internal/planmodifiers/float32planmodifier/use_config_value.go new file mode 100644 index 0000000..0aafffa --- /dev/null +++ b/internal/planmodifiers/float32planmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package float32planmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.Float32 { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifyFloat32(ctx context.Context, req planmodifier.Float32Request, resp *planmodifier.Float32Response) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.Float32Null() + } +} diff --git a/internal/planmodifiers/float64planmodifier/use_config_value.go b/internal/planmodifiers/float64planmodifier/use_config_value.go new file mode 100644 index 0000000..ecd655b --- /dev/null +++ b/internal/planmodifiers/float64planmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package float64planmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.Float64 { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifyFloat64(ctx context.Context, req planmodifier.Float64Request, resp *planmodifier.Float64Response) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.Float64Null() + } +} diff --git a/internal/planmodifiers/int32planmodifier/suppress_diff.go b/internal/planmodifiers/int32planmodifier/suppress_diff.go new file mode 100644 index 0000000..f3c6dcc --- /dev/null +++ b/internal/planmodifiers/int32planmodifier/suppress_diff.go @@ -0,0 +1,56 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package int32planmodifier + +import ( + "context" + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/planmodifiers/utils" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" +) + +const ( + // ExplicitSuppress strategy suppresses "(known after changes)" messages unless we're in the initial creation + ExplicitSuppress = iota +) + +// SuppressDiff returns a plan modifier that propagates a state value into the planned value, when it is Known, and the Plan Value is Unknown +func SuppressDiff(strategy int) planmodifier.Int32 { + return suppressDiff{ + strategy: strategy, + } +} + +// suppressDiff implements the plan modifier. +type suppressDiff struct { + strategy int +} + +// Description returns a human-readable description of the plan modifier. +func (m suppressDiff) Description(_ context.Context) string { + return "Once set, the value of this attribute in state will not change." +} + +// MarkdownDescription returns a markdown description of the plan modifier. +func (m suppressDiff) MarkdownDescription(_ context.Context) string { + return "Once set, the value of this attribute in state will not change." +} + +// PlanModifyInt32 implements the plan modification logic. +func (m suppressDiff) PlanModifyInt32(ctx context.Context, req planmodifier.Int32Request, resp *planmodifier.Int32Response) { + // Do nothing if there is a known planned value. + if !req.PlanValue.IsUnknown() { + return + } + + // Do nothing if there is an unknown configuration value + if req.ConfigValue.IsUnknown() { + return + } + + if utils.IsAllStateUnknown(ctx, req.State) { + return + } + + resp.PlanValue = req.StateValue +} diff --git a/internal/planmodifiers/int32planmodifier/use_config_value.go b/internal/planmodifiers/int32planmodifier/use_config_value.go new file mode 100644 index 0000000..ebc98aa --- /dev/null +++ b/internal/planmodifiers/int32planmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package int32planmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.Int32 { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifyInt32(ctx context.Context, req planmodifier.Int32Request, resp *planmodifier.Int32Response) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.Int32Null() + } +} diff --git a/internal/planmodifiers/int64planmodifier/use_config_value.go b/internal/planmodifiers/int64planmodifier/use_config_value.go new file mode 100644 index 0000000..2ec2d53 --- /dev/null +++ b/internal/planmodifiers/int64planmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package int64planmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.Int64 { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifyInt64(ctx context.Context, req planmodifier.Int64Request, resp *planmodifier.Int64Response) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.Int64Null() + } +} diff --git a/internal/planmodifiers/listplanmodifier/use_config_value.go b/internal/planmodifiers/listplanmodifier/use_config_value.go new file mode 100644 index 0000000..7e851c7 --- /dev/null +++ b/internal/planmodifiers/listplanmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package listplanmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.List { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifyList(ctx context.Context, req planmodifier.ListRequest, resp *planmodifier.ListResponse) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.ListNull(req.PlanValue.ElementType(ctx)) + } +} diff --git a/internal/planmodifiers/mapplanmodifier/use_config_value.go b/internal/planmodifiers/mapplanmodifier/use_config_value.go new file mode 100644 index 0000000..0f2a717 --- /dev/null +++ b/internal/planmodifiers/mapplanmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package mapplanmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.Map { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifyMap(ctx context.Context, req planmodifier.MapRequest, resp *planmodifier.MapResponse) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.MapNull(req.PlanValue.ElementType(ctx)) + } +} diff --git a/internal/planmodifiers/numberplanmodifier/use_config_value.go b/internal/planmodifiers/numberplanmodifier/use_config_value.go new file mode 100644 index 0000000..e93c117 --- /dev/null +++ b/internal/planmodifiers/numberplanmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package numberplanmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.Number { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifyNumber(ctx context.Context, req planmodifier.NumberRequest, resp *planmodifier.NumberResponse) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.NumberNull() + } +} diff --git a/internal/planmodifiers/objectplanmodifier/use_config_value.go b/internal/planmodifiers/objectplanmodifier/use_config_value.go new file mode 100644 index 0000000..eaf2407 --- /dev/null +++ b/internal/planmodifiers/objectplanmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package objectplanmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.Object { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifyObject(ctx context.Context, req planmodifier.ObjectRequest, resp *planmodifier.ObjectResponse) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.ObjectNull(req.PlanValue.AttributeTypes(ctx)) + } +} diff --git a/internal/planmodifiers/setplanmodifier/use_config_value.go b/internal/planmodifiers/setplanmodifier/use_config_value.go new file mode 100644 index 0000000..a95de11 --- /dev/null +++ b/internal/planmodifiers/setplanmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package setplanmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.Set { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifySet(ctx context.Context, req planmodifier.SetRequest, resp *planmodifier.SetResponse) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.SetNull(req.PlanValue.ElementType(ctx)) + } +} diff --git a/internal/planmodifiers/stringplanmodifier/use_config_value.go b/internal/planmodifiers/stringplanmodifier/use_config_value.go new file mode 100644 index 0000000..8b4457a --- /dev/null +++ b/internal/planmodifiers/stringplanmodifier/use_config_value.go @@ -0,0 +1,60 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package stringplanmodifier + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// UseConfigValue returns a plan modifier that ensures the configuration value +// is always used for plan-only attributes, preventing Terraform core from +// copying prior state into the plan when configuration is null. +func UseConfigValue() planmodifier.String { + return useConfigValue{} +} + +type useConfigValue struct{} + +func (m useConfigValue) Description(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) MarkdownDescription(_ context.Context) string { + return "Uses the configuration value for this attribute, ensuring prior state " + + "is not automatically copied into the plan when configuration is null." +} + +func (m useConfigValue) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) { + // If configuration is unknown, don't modify + if req.ConfigValue.IsUnknown() { + return + } + + // If configuration is explicitly set (not null), always use it + if !req.ConfigValue.IsNull() { + resp.PlanValue = req.ConfigValue + return + } + + // Configuration is null - check if we should override the plan + // At this point, the plan value could be: + // 1. A default value (if one was defined) - we want to keep this + // 2. The state value (if Terraform copied it) - we want to override with null + // 3. Unknown (for new computed fields) - we want to keep this + // 4. Null - already correct + + if req.PlanValue.IsNull() || req.PlanValue.IsUnknown() { + return + } + + // Plan has a value and config is null + // If plan equals state, Terraform copied state into plan - override with null + // If plan differs from state, a default was likely applied - keep it + if !req.StateValue.IsNull() && req.PlanValue.Equal(req.StateValue) { + resp.PlanValue = types.StringNull() + } +} diff --git a/internal/planmodifiers/utils/state_check.go b/internal/planmodifiers/utils/state_check.go index 51d5362..0ea64fb 100644 --- a/internal/planmodifiers/utils/state_check.go +++ b/internal/planmodifiers/utils/state_check.go @@ -4,6 +4,7 @@ package utils import ( "context" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/tfsdk" @@ -12,7 +13,7 @@ import ( func IsAllStateUnknown(ctx context.Context, state tfsdk.State) bool { attrs := state.Schema.GetAttributes() anyFound := false - for k, _ := range attrs { + for k := range attrs { attrValue := new(attr.Value) state.GetAttribute(ctx, path.Root(k), attrValue) if attrValue != nil && !(*attrValue).IsUnknown() && !(*attrValue).IsNull() { diff --git a/internal/provider/design_data_source.go b/internal/provider/design_data_source.go index edfbf8d..43d32e9 100644 --- a/internal/provider/design_data_source.go +++ b/internal/provider/design_data_source.go @@ -7,7 +7,7 @@ import ( "fmt" tfTypes "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/provider/types" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk" - "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/operations" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" @@ -24,22 +24,23 @@ func NewDesignDataSource() datasource.DataSource { // DesignDataSource is the data source implementation. type DesignDataSource struct { + // Provider configured SDK client. client *sdk.SDK } // DesignDataSourceModel describes the data model. type DesignDataSourceModel struct { - BrandID types.String `tfsdk:"brand_id"` + BrandID jsontypes.Normalized `tfsdk:"brand_id"` BrandName types.String `tfsdk:"brand_name"` CreatedAt types.String `tfsdk:"created_at"` CreatedBy types.String `tfsdk:"created_by"` - CustomTheme types.String `tfsdk:"custom_theme"` + CustomTheme jsontypes.Normalized `tfsdk:"custom_theme"` DesignTokens *tfTypes.DesignTokens `tfsdk:"design_tokens"` Edited types.Bool `tfsdk:"edited"` ID types.String `tfsdk:"id"` IsDefault types.Bool `tfsdk:"is_default"` LastModifiedAt types.String `tfsdk:"last_modified_at"` - Style types.String `tfsdk:"style"` + Style jsontypes.Normalized `tfsdk:"style"` StyleName types.String `tfsdk:"style_name"` UseCustomTheme types.Bool `tfsdk:"use_custom_theme"` User *tfTypes.User `tfsdk:"user"` @@ -57,6 +58,7 @@ func (r *DesignDataSource) Schema(ctx context.Context, req datasource.SchemaRequ Attributes: map[string]schema.Attribute{ "brand_id": schema.StringAttribute{ + CustomType: jsontypes.NormalizedType{}, Computed: true, Description: `Parsed as JSON.`, }, @@ -71,6 +73,7 @@ func (r *DesignDataSource) Schema(ctx context.Context, req datasource.SchemaRequ Computed: true, }, "custom_theme": schema.StringAttribute{ + CustomType: jsontypes.NormalizedType{}, Computed: true, Description: `Parsed as JSON.`, }, @@ -101,6 +104,7 @@ func (r *DesignDataSource) Schema(ctx context.Context, req datasource.SchemaRequ Computed: true, }, "style": schema.StringAttribute{ + CustomType: jsontypes.NormalizedType{}, Computed: true, Description: `Parsed as JSON.`, }, @@ -169,13 +173,13 @@ func (r *DesignDataSource) Read(ctx context.Context, req datasource.ReadRequest, return } - var designID string - designID = data.ID.ValueString() + request, requestDiags := data.ToOperationsGetDesignRequest(ctx) + resp.Diagnostics.Append(requestDiags...) - request := operations.GetDesignRequest{ - DesignID: designID, + if resp.Diagnostics.HasError() { + return } - res, err := r.client.DesignBuilder.GetDesign(ctx, request) + res, err := r.client.DesignBuilder.GetDesign(ctx, *request) if err != nil { resp.Diagnostics.AddError("failure to invoke API", err.Error()) if res != nil && res.RawResponse != nil { @@ -187,19 +191,19 @@ func (r *DesignDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp.Diagnostics.AddError("unexpected response from API", fmt.Sprintf("%v", res)) return } - if res.StatusCode == 404 { - resp.State.RemoveResource(ctx) - return - } if res.StatusCode != 200 { resp.Diagnostics.AddError(fmt.Sprintf("unexpected response from API. Got an unexpected response code %v", res.StatusCode), debugResponse(res.RawResponse)) return } - if !(res.GetDesignRes != nil && res.GetDesignRes.Design != nil) { + if !(res.GetDesignRes != nil) { resp.Diagnostics.AddError("unexpected response from API. Got an unexpected response body", debugResponse(res.RawResponse)) return } - data.RefreshFromSharedGetDesignResDesign(res.GetDesignRes.Design) + resp.Diagnostics.Append(data.RefreshFromSharedGetDesignRes(ctx, res.GetDesignRes)...) + + if resp.Diagnostics.HasError() { + return + } // Save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) diff --git a/internal/provider/design_data_source_sdk.go b/internal/provider/design_data_source_sdk.go index 8f9ca31..b1ad66a 100644 --- a/internal/provider/design_data_source_sdk.go +++ b/internal/provider/design_data_source_sdk.go @@ -3,28 +3,49 @@ package provider import ( + "context" "encoding/json" tfTypes "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/provider/types" + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/operations" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/shared" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) -func (r *DesignDataSourceModel) RefreshFromSharedGetDesignResDesign(resp *shared.GetDesignResDesign) { +func (r *DesignDataSourceModel) RefreshFromSharedGetDesignRes(ctx context.Context, resp *shared.GetDesignRes) diag.Diagnostics { + var diags diag.Diagnostics + + if resp != nil { + diags.Append(r.RefreshFromSharedGetDesignResDesign(ctx, resp.Design)...) + + if diags.HasError() { + return diags + } + + } + + return diags +} + +func (r *DesignDataSourceModel) RefreshFromSharedGetDesignResDesign(ctx context.Context, resp *shared.GetDesignResDesign) diag.Diagnostics { + var diags diag.Diagnostics + if resp != nil { if resp.BrandID == nil { - r.BrandID = types.StringNull() + r.BrandID = jsontypes.NewNormalizedNull() } else { brandIDResult, _ := json.Marshal(resp.BrandID) - r.BrandID = types.StringValue(string(brandIDResult)) + r.BrandID = jsontypes.NewNormalizedValue(string(brandIDResult)) } r.BrandName = types.StringPointerValue(resp.BrandName) r.CreatedAt = types.StringPointerValue(resp.CreatedAt) r.CreatedBy = types.StringPointerValue(resp.CreatedBy) if resp.CustomTheme == nil { - r.CustomTheme = types.StringNull() + r.CustomTheme = jsontypes.NewNormalizedNull() } else { customThemeResult, _ := json.Marshal(resp.CustomTheme) - r.CustomTheme = types.StringValue(string(customThemeResult)) + r.CustomTheme = jsontypes.NewNormalizedValue(string(customThemeResult)) } if resp.DesignTokens == nil { r.DesignTokens = nil @@ -39,7 +60,7 @@ func (r *DesignDataSourceModel) RefreshFromSharedGetDesignResDesign(resp *shared r.IsDefault = types.BoolPointerValue(resp.IsDefault) r.LastModifiedAt = types.StringPointerValue(resp.LastModifiedAt) styleResult, _ := json.Marshal(resp.Style) - r.Style = types.StringValue(string(styleResult)) + r.Style = jsontypes.NewNormalizedValue(string(styleResult)) r.StyleName = types.StringValue(resp.StyleName) r.UseCustomTheme = types.BoolPointerValue(resp.UseCustomTheme) if resp.User == nil { @@ -52,4 +73,19 @@ func (r *DesignDataSourceModel) RefreshFromSharedGetDesignResDesign(resp *shared r.User.Userid = types.StringPointerValue(resp.User.Userid) } } + + return diags +} + +func (r *DesignDataSourceModel) ToOperationsGetDesignRequest(ctx context.Context) (*operations.GetDesignRequest, diag.Diagnostics) { + var diags diag.Diagnostics + + var designID string + designID = r.ID.ValueString() + + out := operations.GetDesignRequest{ + DesignID: designID, + } + + return &out, diags } diff --git a/internal/provider/design_resource.go b/internal/provider/design_resource.go index 2d78b72..cf27336 100644 --- a/internal/provider/design_resource.go +++ b/internal/provider/design_resource.go @@ -7,13 +7,10 @@ import ( "fmt" tfTypes "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/provider/types" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk" - "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/operations" - "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/shared" - "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/validators" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" - "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -28,22 +25,23 @@ func NewDesignResource() resource.Resource { // DesignResource defines the resource implementation. type DesignResource struct { + // Provider configured SDK client. client *sdk.SDK } // DesignResourceModel describes the resource data model. type DesignResourceModel struct { - BrandID types.String `tfsdk:"brand_id"` + BrandID jsontypes.Normalized `tfsdk:"brand_id"` BrandName types.String `tfsdk:"brand_name"` CreatedAt types.String `tfsdk:"created_at"` CreatedBy types.String `tfsdk:"created_by"` - CustomTheme types.String `tfsdk:"custom_theme"` + CustomTheme jsontypes.Normalized `tfsdk:"custom_theme"` DesignTokens *tfTypes.DesignTokens `tfsdk:"design_tokens"` Edited types.Bool `tfsdk:"edited"` ID types.String `tfsdk:"id"` IsDefault types.Bool `tfsdk:"is_default"` LastModifiedAt types.String `tfsdk:"last_modified_at"` - Style types.String `tfsdk:"style"` + Style jsontypes.Normalized `tfsdk:"style"` StyleName types.String `tfsdk:"style_name"` UseCustomTheme types.Bool `tfsdk:"use_custom_theme"` User *tfTypes.User `tfsdk:"user"` @@ -58,12 +56,10 @@ func (r *DesignResource) Schema(ctx context.Context, req resource.SchemaRequest, MarkdownDescription: "Design Resource", Attributes: map[string]schema.Attribute{ "brand_id": schema.StringAttribute{ + CustomType: jsontypes.NormalizedType{}, Computed: true, Optional: true, Description: `Parsed as JSON.`, - Validators: []validator.String{ - validators.IsValidJSON(), - }, }, "brand_name": schema.StringAttribute{ Computed: true, @@ -77,12 +73,10 @@ func (r *DesignResource) Schema(ctx context.Context, req resource.SchemaRequest, Computed: true, }, "custom_theme": schema.StringAttribute{ + CustomType: jsontypes.NormalizedType{}, Computed: true, Optional: true, Description: `Parsed as JSON.`, - Validators: []validator.String{ - validators.IsValidJSON(), - }, }, "design_tokens": schema.SingleNestedAttribute{ Computed: true, @@ -116,11 +110,9 @@ func (r *DesignResource) Schema(ctx context.Context, req resource.SchemaRequest, Computed: true, }, "style": schema.StringAttribute{ + CustomType: jsontypes.NormalizedType{}, Required: true, Description: `Parsed as JSON.`, - Validators: []validator.String{ - validators.IsValidJSON(), - }, }, "style_name": schema.StringAttribute{ Required: true, @@ -193,11 +185,13 @@ func (r *DesignResource) Create(ctx context.Context, req resource.CreateRequest, return } - design := *data.ToSharedDesign() - request := shared.AddDesignReq{ - Design: design, + request, requestDiags := data.ToSharedAddDesignReq(ctx) + resp.Diagnostics.Append(requestDiags...) + + if resp.Diagnostics.HasError() { + return } - res, err := r.client.DesignBuilder.AddDesign(ctx, request) + res, err := r.client.DesignBuilder.AddDesign(ctx, *request) if err != nil { resp.Diagnostics.AddError("failure to invoke API", err.Error()) if res != nil && res.RawResponse != nil { @@ -213,12 +207,21 @@ func (r *DesignResource) Create(ctx context.Context, req resource.CreateRequest, resp.Diagnostics.AddError(fmt.Sprintf("unexpected response from API. Got an unexpected response code %v", res.StatusCode), debugResponse(res.RawResponse)) return } - if !(res.AddDesignRes != nil && res.AddDesignRes.Design != nil) { + if !(res.AddDesignRes != nil) { resp.Diagnostics.AddError("unexpected response from API. Got an unexpected response body", debugResponse(res.RawResponse)) return } - data.RefreshFromSharedAddDesignResDesign(res.AddDesignRes.Design) - refreshPlan(ctx, plan, &data, resp.Diagnostics) + resp.Diagnostics.Append(data.RefreshFromSharedAddDesignRes(ctx, res.AddDesignRes)...) + + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(refreshPlan(ctx, plan, &data)...) + + if resp.Diagnostics.HasError() { + return + } // Save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -242,13 +245,13 @@ func (r *DesignResource) Read(ctx context.Context, req resource.ReadRequest, res return } - var designID string - designID = data.ID.ValueString() + request, requestDiags := data.ToOperationsGetDesignRequest(ctx) + resp.Diagnostics.Append(requestDiags...) - request := operations.GetDesignRequest{ - DesignID: designID, + if resp.Diagnostics.HasError() { + return } - res, err := r.client.DesignBuilder.GetDesign(ctx, request) + res, err := r.client.DesignBuilder.GetDesign(ctx, *request) if err != nil { resp.Diagnostics.AddError("failure to invoke API", err.Error()) if res != nil && res.RawResponse != nil { @@ -268,11 +271,15 @@ func (r *DesignResource) Read(ctx context.Context, req resource.ReadRequest, res resp.Diagnostics.AddError(fmt.Sprintf("unexpected response from API. Got an unexpected response code %v", res.StatusCode), debugResponse(res.RawResponse)) return } - if !(res.GetDesignRes != nil && res.GetDesignRes.Design != nil) { + if !(res.GetDesignRes != nil) { resp.Diagnostics.AddError("unexpected response from API. Got an unexpected response body", debugResponse(res.RawResponse)) return } - data.RefreshFromSharedGetDesignResDesign(res.GetDesignRes.Design) + resp.Diagnostics.Append(data.RefreshFromSharedGetDesignRes(ctx, res.GetDesignRes)...) + + if resp.Diagnostics.HasError() { + return + } // Save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -292,18 +299,13 @@ func (r *DesignResource) Update(ctx context.Context, req resource.UpdateRequest, return } - design := *data.ToSharedUpdateDesignReqDesign() - updateDesignReq := shared.UpdateDesignReq{ - Design: design, - } - var designID string - designID = data.ID.ValueString() + request, requestDiags := data.ToOperationsUpdateDesignRequest(ctx) + resp.Diagnostics.Append(requestDiags...) - request := operations.UpdateDesignRequest{ - UpdateDesignReq: updateDesignReq, - DesignID: designID, + if resp.Diagnostics.HasError() { + return } - res, err := r.client.DesignBuilder.UpdateDesign(ctx, request) + res, err := r.client.DesignBuilder.UpdateDesign(ctx, *request) if err != nil { resp.Diagnostics.AddError("failure to invoke API", err.Error()) if res != nil && res.RawResponse != nil { @@ -319,7 +321,12 @@ func (r *DesignResource) Update(ctx context.Context, req resource.UpdateRequest, resp.Diagnostics.AddError(fmt.Sprintf("unexpected response from API. Got an unexpected response code %v", res.StatusCode), debugResponse(res.RawResponse)) return } - refreshPlan(ctx, plan, &data, resp.Diagnostics) + + resp.Diagnostics.Append(refreshPlan(ctx, plan, &data)...) + + if resp.Diagnostics.HasError() { + return + } // Save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -343,13 +350,13 @@ func (r *DesignResource) Delete(ctx context.Context, req resource.DeleteRequest, return } - var designID string - designID = data.ID.ValueString() + request, requestDiags := data.ToOperationsDeleteDesignRequest(ctx) + resp.Diagnostics.Append(requestDiags...) - request := operations.DeleteDesignRequest{ - DesignID: designID, + if resp.Diagnostics.HasError() { + return } - res, err := r.client.DesignBuilder.DeleteDesign(ctx, request) + res, err := r.client.DesignBuilder.DeleteDesign(ctx, *request) if err != nil { resp.Diagnostics.AddError("failure to invoke API", err.Error()) if res != nil && res.RawResponse != nil { @@ -361,7 +368,10 @@ func (r *DesignResource) Delete(ctx context.Context, req resource.DeleteRequest, resp.Diagnostics.AddError("unexpected response from API", fmt.Sprintf("%v", res)) return } - if res.StatusCode != 204 { + switch res.StatusCode { + case 204, 404: + break + default: resp.Diagnostics.AddError(fmt.Sprintf("unexpected response from API. Got an unexpected response code %v", res.StatusCode), debugResponse(res.RawResponse)) return } diff --git a/internal/provider/design_resource_sdk.go b/internal/provider/design_resource_sdk.go index 72709a8..e281e4c 100644 --- a/internal/provider/design_resource_sdk.go +++ b/internal/provider/design_resource_sdk.go @@ -3,13 +3,211 @@ package provider import ( + "context" "encoding/json" tfTypes "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/provider/types" + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/operations" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/shared" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) -func (r *DesignResourceModel) ToSharedDesign() *shared.Design { +func (r *DesignResourceModel) RefreshFromSharedAddDesignRes(ctx context.Context, resp *shared.AddDesignRes) diag.Diagnostics { + var diags diag.Diagnostics + + if resp != nil { + diags.Append(r.RefreshFromSharedAddDesignResDesign(ctx, resp.Design)...) + + if diags.HasError() { + return diags + } + + } + + return diags +} + +func (r *DesignResourceModel) RefreshFromSharedAddDesignResDesign(ctx context.Context, resp *shared.AddDesignResDesign) diag.Diagnostics { + var diags diag.Diagnostics + + if resp != nil { + if resp.BrandID == nil { + r.BrandID = jsontypes.NewNormalizedNull() + } else { + brandIDResult, _ := json.Marshal(resp.BrandID) + r.BrandID = jsontypes.NewNormalizedValue(string(brandIDResult)) + } + r.BrandName = types.StringPointerValue(resp.BrandName) + r.CreatedAt = types.StringPointerValue(resp.CreatedAt) + r.CreatedBy = types.StringPointerValue(resp.CreatedBy) + if resp.CustomTheme == nil { + r.CustomTheme = jsontypes.NewNormalizedNull() + } else { + customThemeResult, _ := json.Marshal(resp.CustomTheme) + r.CustomTheme = jsontypes.NewNormalizedValue(string(customThemeResult)) + } + if resp.DesignTokens == nil { + r.DesignTokens = nil + } else { + r.DesignTokens = &tfTypes.DesignTokens{} + r.DesignTokens.Cashback = types.StringPointerValue(resp.DesignTokens.Cashback) + r.DesignTokens.Coupon = types.StringPointerValue(resp.DesignTokens.Coupon) + r.DesignTokens.CustomCSS = types.StringPointerValue(resp.DesignTokens.CustomCSS) + } + r.Edited = types.BoolValue(resp.Edited) + r.ID = types.StringPointerValue(resp.ID) + r.IsDefault = types.BoolPointerValue(resp.IsDefault) + r.LastModifiedAt = types.StringPointerValue(resp.LastModifiedAt) + styleResult, _ := json.Marshal(resp.Style) + r.Style = jsontypes.NewNormalizedValue(string(styleResult)) + r.StyleName = types.StringValue(resp.StyleName) + r.UseCustomTheme = types.BoolPointerValue(resp.UseCustomTheme) + if resp.User == nil { + r.User = nil + } else { + r.User = &tfTypes.User{} + r.User.Emailaddress = types.StringPointerValue(resp.User.Emailaddress) + r.User.Fullname = types.StringPointerValue(resp.User.Fullname) + r.User.Name = types.StringPointerValue(resp.User.Name) + r.User.Userid = types.StringPointerValue(resp.User.Userid) + } + } + + return diags +} + +func (r *DesignResourceModel) RefreshFromSharedGetDesignRes(ctx context.Context, resp *shared.GetDesignRes) diag.Diagnostics { + var diags diag.Diagnostics + + if resp != nil { + diags.Append(r.RefreshFromSharedGetDesignResDesign(ctx, resp.Design)...) + + if diags.HasError() { + return diags + } + + } + + return diags +} + +func (r *DesignResourceModel) RefreshFromSharedGetDesignResDesign(ctx context.Context, resp *shared.GetDesignResDesign) diag.Diagnostics { + var diags diag.Diagnostics + + if resp != nil { + if resp.BrandID == nil { + r.BrandID = jsontypes.NewNormalizedNull() + } else { + brandIDResult, _ := json.Marshal(resp.BrandID) + r.BrandID = jsontypes.NewNormalizedValue(string(brandIDResult)) + } + r.BrandName = types.StringPointerValue(resp.BrandName) + r.CreatedAt = types.StringPointerValue(resp.CreatedAt) + r.CreatedBy = types.StringPointerValue(resp.CreatedBy) + if resp.CustomTheme == nil { + r.CustomTheme = jsontypes.NewNormalizedNull() + } else { + customThemeResult, _ := json.Marshal(resp.CustomTheme) + r.CustomTheme = jsontypes.NewNormalizedValue(string(customThemeResult)) + } + if resp.DesignTokens == nil { + r.DesignTokens = nil + } else { + r.DesignTokens = &tfTypes.DesignTokens{} + r.DesignTokens.Cashback = types.StringPointerValue(resp.DesignTokens.Cashback) + r.DesignTokens.Coupon = types.StringPointerValue(resp.DesignTokens.Coupon) + r.DesignTokens.CustomCSS = types.StringPointerValue(resp.DesignTokens.CustomCSS) + } + r.Edited = types.BoolValue(resp.Edited) + r.ID = types.StringPointerValue(resp.ID) + r.IsDefault = types.BoolPointerValue(resp.IsDefault) + r.LastModifiedAt = types.StringPointerValue(resp.LastModifiedAt) + styleResult, _ := json.Marshal(resp.Style) + r.Style = jsontypes.NewNormalizedValue(string(styleResult)) + r.StyleName = types.StringValue(resp.StyleName) + r.UseCustomTheme = types.BoolPointerValue(resp.UseCustomTheme) + if resp.User == nil { + r.User = nil + } else { + r.User = &tfTypes.User{} + r.User.Emailaddress = types.StringPointerValue(resp.User.Emailaddress) + r.User.Fullname = types.StringPointerValue(resp.User.Fullname) + r.User.Name = types.StringPointerValue(resp.User.Name) + r.User.Userid = types.StringPointerValue(resp.User.Userid) + } + } + + return diags +} + +func (r *DesignResourceModel) ToOperationsDeleteDesignRequest(ctx context.Context) (*operations.DeleteDesignRequest, diag.Diagnostics) { + var diags diag.Diagnostics + + var designID string + designID = r.ID.ValueString() + + out := operations.DeleteDesignRequest{ + DesignID: designID, + } + + return &out, diags +} + +func (r *DesignResourceModel) ToOperationsGetDesignRequest(ctx context.Context) (*operations.GetDesignRequest, diag.Diagnostics) { + var diags diag.Diagnostics + + var designID string + designID = r.ID.ValueString() + + out := operations.GetDesignRequest{ + DesignID: designID, + } + + return &out, diags +} + +func (r *DesignResourceModel) ToOperationsUpdateDesignRequest(ctx context.Context) (*operations.UpdateDesignRequest, diag.Diagnostics) { + var diags diag.Diagnostics + + updateDesignReq, updateDesignReqDiags := r.ToSharedUpdateDesignReq(ctx) + diags.Append(updateDesignReqDiags...) + + if diags.HasError() { + return nil, diags + } + + var designID string + designID = r.ID.ValueString() + + out := operations.UpdateDesignRequest{ + UpdateDesignReq: *updateDesignReq, + DesignID: designID, + } + + return &out, diags +} + +func (r *DesignResourceModel) ToSharedAddDesignReq(ctx context.Context) (*shared.AddDesignReq, diag.Diagnostics) { + var diags diag.Diagnostics + + design, designDiags := r.ToSharedDesign(ctx) + diags.Append(designDiags...) + + if diags.HasError() { + return nil, diags + } + + out := shared.AddDesignReq{ + Design: *design, + } + + return &out, diags +} + +func (r *DesignResourceModel) ToSharedDesign(ctx context.Context) (*shared.Design, diag.Diagnostics) { + var diags diag.Diagnostics + var brandID interface{} if !r.BrandID.IsUnknown() && !r.BrandID.IsNull() { _ = json.Unmarshal([]byte(r.BrandID.ValueString()), &brandID) @@ -111,100 +309,30 @@ func (r *DesignResourceModel) ToSharedDesign() *shared.Design { UseCustomTheme: useCustomTheme, User: user, } - return &out + + return &out, diags } -func (r *DesignResourceModel) RefreshFromSharedAddDesignResDesign(resp *shared.AddDesignResDesign) { - if resp != nil { - if resp.BrandID == nil { - r.BrandID = types.StringNull() - } else { - brandIDResult, _ := json.Marshal(resp.BrandID) - r.BrandID = types.StringValue(string(brandIDResult)) - } - r.BrandName = types.StringPointerValue(resp.BrandName) - r.CreatedAt = types.StringPointerValue(resp.CreatedAt) - r.CreatedBy = types.StringPointerValue(resp.CreatedBy) - if resp.CustomTheme == nil { - r.CustomTheme = types.StringNull() - } else { - customThemeResult, _ := json.Marshal(resp.CustomTheme) - r.CustomTheme = types.StringValue(string(customThemeResult)) - } - if resp.DesignTokens == nil { - r.DesignTokens = nil - } else { - r.DesignTokens = &tfTypes.DesignTokens{} - r.DesignTokens.Cashback = types.StringPointerValue(resp.DesignTokens.Cashback) - r.DesignTokens.Coupon = types.StringPointerValue(resp.DesignTokens.Coupon) - r.DesignTokens.CustomCSS = types.StringPointerValue(resp.DesignTokens.CustomCSS) - } - r.Edited = types.BoolValue(resp.Edited) - r.ID = types.StringPointerValue(resp.ID) - r.IsDefault = types.BoolPointerValue(resp.IsDefault) - r.LastModifiedAt = types.StringPointerValue(resp.LastModifiedAt) - styleResult, _ := json.Marshal(resp.Style) - r.Style = types.StringValue(string(styleResult)) - r.StyleName = types.StringValue(resp.StyleName) - r.UseCustomTheme = types.BoolPointerValue(resp.UseCustomTheme) - if resp.User == nil { - r.User = nil - } else { - r.User = &tfTypes.User{} - r.User.Emailaddress = types.StringPointerValue(resp.User.Emailaddress) - r.User.Fullname = types.StringPointerValue(resp.User.Fullname) - r.User.Name = types.StringPointerValue(resp.User.Name) - r.User.Userid = types.StringPointerValue(resp.User.Userid) - } +func (r *DesignResourceModel) ToSharedUpdateDesignReq(ctx context.Context) (*shared.UpdateDesignReq, diag.Diagnostics) { + var diags diag.Diagnostics + + design, designDiags := r.ToSharedUpdateDesignReqDesign(ctx) + diags.Append(designDiags...) + + if diags.HasError() { + return nil, diags } -} -func (r *DesignResourceModel) RefreshFromSharedGetDesignResDesign(resp *shared.GetDesignResDesign) { - if resp != nil { - if resp.BrandID == nil { - r.BrandID = types.StringNull() - } else { - brandIDResult, _ := json.Marshal(resp.BrandID) - r.BrandID = types.StringValue(string(brandIDResult)) - } - r.BrandName = types.StringPointerValue(resp.BrandName) - r.CreatedAt = types.StringPointerValue(resp.CreatedAt) - r.CreatedBy = types.StringPointerValue(resp.CreatedBy) - if resp.CustomTheme == nil { - r.CustomTheme = types.StringNull() - } else { - customThemeResult, _ := json.Marshal(resp.CustomTheme) - r.CustomTheme = types.StringValue(string(customThemeResult)) - } - if resp.DesignTokens == nil { - r.DesignTokens = nil - } else { - r.DesignTokens = &tfTypes.DesignTokens{} - r.DesignTokens.Cashback = types.StringPointerValue(resp.DesignTokens.Cashback) - r.DesignTokens.Coupon = types.StringPointerValue(resp.DesignTokens.Coupon) - r.DesignTokens.CustomCSS = types.StringPointerValue(resp.DesignTokens.CustomCSS) - } - r.Edited = types.BoolValue(resp.Edited) - r.ID = types.StringPointerValue(resp.ID) - r.IsDefault = types.BoolPointerValue(resp.IsDefault) - r.LastModifiedAt = types.StringPointerValue(resp.LastModifiedAt) - styleResult, _ := json.Marshal(resp.Style) - r.Style = types.StringValue(string(styleResult)) - r.StyleName = types.StringValue(resp.StyleName) - r.UseCustomTheme = types.BoolPointerValue(resp.UseCustomTheme) - if resp.User == nil { - r.User = nil - } else { - r.User = &tfTypes.User{} - r.User.Emailaddress = types.StringPointerValue(resp.User.Emailaddress) - r.User.Fullname = types.StringPointerValue(resp.User.Fullname) - r.User.Name = types.StringPointerValue(resp.User.Name) - r.User.Userid = types.StringPointerValue(resp.User.Userid) - } + out := shared.UpdateDesignReq{ + Design: *design, } + + return &out, diags } -func (r *DesignResourceModel) ToSharedUpdateDesignReqDesign() *shared.UpdateDesignReqDesign { +func (r *DesignResourceModel) ToSharedUpdateDesignReqDesign(ctx context.Context) (*shared.UpdateDesignReqDesign, diag.Diagnostics) { + var diags diag.Diagnostics + var brandID interface{} if !r.BrandID.IsUnknown() && !r.BrandID.IsNull() { _ = json.Unmarshal([]byte(r.BrandID.ValueString()), &brandID) @@ -306,5 +434,6 @@ func (r *DesignResourceModel) ToSharedUpdateDesignReqDesign() *shared.UpdateDesi UseCustomTheme: useCustomTheme, User: user, } - return &out + + return &out, diags } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 68e0936..249c433 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -7,6 +7,7 @@ import ( "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/shared" "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/ephemeral" "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -14,7 +15,8 @@ import ( "net/http" ) -var _ provider.Provider = &EpilotDesignbuilderProvider{} +var _ provider.Provider = (*EpilotDesignbuilderProvider)(nil) +var _ provider.ProviderWithEphemeralResources = (*EpilotDesignbuilderProvider)(nil) type EpilotDesignbuilderProvider struct { // version is set to the provider version on release, "dev" when the @@ -25,8 +27,8 @@ type EpilotDesignbuilderProvider struct { // EpilotDesignbuilderProviderModel describes the provider data model. type EpilotDesignbuilderProviderModel struct { - ServerURL types.String `tfsdk:"server_url"` CustomAuthorizer types.String `tfsdk:"custom_authorizer"` + ServerURL types.String `tfsdk:"server_url"` } func (p *EpilotDesignbuilderProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { @@ -37,14 +39,14 @@ func (p *EpilotDesignbuilderProvider) Metadata(ctx context.Context, req provider func (p *EpilotDesignbuilderProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - "server_url": schema.StringAttribute{ - MarkdownDescription: "Server URL (defaults to https://design-builder-api.sls.epilot.io)", + "custom_authorizer": schema.StringAttribute{ + MarkdownDescription: `HTTP Bearer.`, Optional: true, - Required: false, + Sensitive: true, }, - "custom_authorizer": schema.StringAttribute{ - Sensitive: true, - Optional: true, + "server_url": schema.StringAttribute{ + Description: `Server URL (defaults to https://design-builder-api.sls.epilot.io)`, + Optional: true, }, }, } @@ -59,33 +61,35 @@ func (p *EpilotDesignbuilderProvider) Configure(ctx context.Context, req provide return } - ServerURL := data.ServerURL.ValueString() + serverUrl := data.ServerURL.ValueString() - if ServerURL == "" { - ServerURL = "https://design-builder-api.sls.epilot.io" + if serverUrl == "" { + serverUrl = "https://design-builder-api.sls.epilot.io" } - customAuthorizer := new(string) - if !data.CustomAuthorizer.IsUnknown() && !data.CustomAuthorizer.IsNull() { - *customAuthorizer = data.CustomAuthorizer.ValueString() - } else { - customAuthorizer = nil + security := shared.Security{} + + if !data.CustomAuthorizer.IsUnknown() { + security.CustomAuthorizer = data.CustomAuthorizer.ValueStringPointer() } - security := shared.Security{ - CustomAuthorizer: customAuthorizer, + + providerHTTPTransportOpts := ProviderHTTPTransportOpts{ + SetHeaders: make(map[string]string), + Transport: http.DefaultTransport, } httpClient := http.DefaultClient - httpClient.Transport = NewLoggingHTTPTransport(http.DefaultTransport) + httpClient.Transport = NewProviderHTTPTransport(providerHTTPTransportOpts) opts := []sdk.SDKOption{ - sdk.WithServerURL(ServerURL), + sdk.WithServerURL(serverUrl), sdk.WithSecurity(security), sdk.WithClient(httpClient), } - client := sdk.New(opts...) + client := sdk.New(opts...) resp.DataSourceData = client + resp.EphemeralResourceData = client resp.ResourceData = client } @@ -101,6 +105,10 @@ func (p *EpilotDesignbuilderProvider) DataSources(ctx context.Context) []func() } } +func (p *EpilotDesignbuilderProvider) EphemeralResources(ctx context.Context) []func() ephemeral.EphemeralResource { + return []func() ephemeral.EphemeralResource{} +} + func New(version string) func() provider.Provider { return func() provider.Provider { return &EpilotDesignbuilderProvider{ diff --git a/internal/provider/reflect/options.go b/internal/provider/reflect/options.go index 063353f..002addd 100644 --- a/internal/provider/reflect/options.go +++ b/internal/provider/reflect/options.go @@ -2,11 +2,6 @@ package reflect -const ( - SourceTypeState = iota - SourceTypePlan -) - // Options provides configuration settings for how the reflection behavior // works, letting callers tweak different behaviors based on their needs. type Options struct { @@ -19,9 +14,4 @@ type Options struct { // translated into empty values without provider interaction, or if // they must be explicitly handled. UnhandledUnknownAsEmpty bool - - // SourceType informs the reflection system what the source is - // such that it can make decisions based on the tfPlanOnly annotation - // The default is SourceTypeState - SourceType int } diff --git a/internal/provider/reflect/struct.go b/internal/provider/reflect/struct.go index 68ea994..c588f76 100644 --- a/internal/provider/reflect/struct.go +++ b/internal/provider/reflect/struct.go @@ -125,7 +125,6 @@ func Struct(ctx context.Context, typ attr.Type, object tftypes.Value, target ref } else { result = reflect.New(target.Type()).Elem() } - structType := trueReflectValue(target).Type() for field, structFieldPos := range targetFields { attrType, ok := attrTypes[field] @@ -138,12 +137,6 @@ func Struct(ctx context.Context, typ attr.Type, object tftypes.Value, target ref return target, diags } - fieldReflected := structType.Field(structFieldPos) - if opts.SourceType == SourceTypeState && fieldReflected.Tag.Get(`tfPlanOnly`) == "true" { - // skip explicitly excluded fields - continue - } - // Fork End structField := result.Field(structFieldPos) fieldVal, fieldValDiags := BuildValue(ctx, attrType, objectFields[field], structField, opts, path.AtName(field)) diags.Append(fieldValDiags...) diff --git a/internal/provider/typeconvert/date.go b/internal/provider/typeconvert/date.go new file mode 100644 index 0000000..066ba73 --- /dev/null +++ b/internal/provider/typeconvert/date.go @@ -0,0 +1,23 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package typeconvert + +import ( + sdkTypes "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/types" +) + +// Converts a date types.Date to string. +func DateToString(value sdkTypes.Date) string { + return value.String() +} + +// Converts a date *types.Date to *string. +func DatePointerToStringPointer(value *sdkTypes.Date) *string { + if value == nil { + return nil + } + + stringValue := DateToString(*value) + + return &stringValue +} diff --git a/internal/provider/typeconvert/datetime.go b/internal/provider/typeconvert/datetime.go new file mode 100644 index 0000000..7bfdc55 --- /dev/null +++ b/internal/provider/typeconvert/datetime.go @@ -0,0 +1,23 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package typeconvert + +import ( + "time" +) + +// Converts a date-time time.Time to string. +func TimeToString(value time.Time) string { + return value.Format(time.RFC3339Nano) +} + +// Converts a date-time *time.Time to *string. +func TimePointerToStringPointer(value *time.Time) *string { + if value == nil { + return nil + } + + stringValue := TimeToString(*value) + + return &stringValue +} diff --git a/internal/provider/typeconvert/int.go b/internal/provider/typeconvert/int.go new file mode 100644 index 0000000..54763e7 --- /dev/null +++ b/internal/provider/typeconvert/int.go @@ -0,0 +1,50 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package typeconvert + +// Converts an *int to *int32. +func IntPointerToInt32Pointer(value *int) *int32 { + if value == nil { + return nil + } + + int32Value := int32(*value) + + return &int32Value +} + +// Converts an *int to *int64. +func IntPointerToInt64Pointer(value *int) *int64 { + if value == nil { + return nil + } + + int64Value := int64(*value) + + return &int64Value +} + +// Converts an *int32 to *int. +func Int32PointerToIntPointer(value *int32) *int { + if value == nil { + return nil + } + + intValue := int(*value) + + return &intValue +} + +// Converts an *int64 to *int32. +func Int64PointerToInt32Pointer(value *int64) *int32 { + if value == nil { + return nil + } + + // This may panic and if it does, represents a schema mismatch between + // response and response types. Request and response types should always + // be consistent with the highest integer size necessary. + int32Value := int32(*value) + + return &int32Value +} diff --git a/internal/provider/types/design_tokens.go b/internal/provider/types/design_tokens.go index c380835..787b9e8 100644 --- a/internal/provider/types/design_tokens.go +++ b/internal/provider/types/design_tokens.go @@ -2,7 +2,9 @@ package types -import "github.com/hashicorp/terraform-plugin-framework/types" +import ( + "github.com/hashicorp/terraform-plugin-framework/types" +) type DesignTokens struct { Cashback types.String `tfsdk:"cashback"` diff --git a/internal/provider/types/user.go b/internal/provider/types/user.go index cd573ec..3e629f2 100644 --- a/internal/provider/types/user.go +++ b/internal/provider/types/user.go @@ -2,7 +2,9 @@ package types -import "github.com/hashicorp/terraform-plugin-framework/types" +import ( + "github.com/hashicorp/terraform-plugin-framework/types" +) type User struct { Emailaddress types.String `tfsdk:"emailaddress"` diff --git a/internal/provider/utils.go b/internal/provider/utils.go index 6bbd190..cee73be 100644 --- a/internal/provider/utils.go +++ b/internal/provider/utils.go @@ -6,22 +6,22 @@ import ( "bufio" "bytes" "context" - "encoding/json" "errors" "fmt" - tfReflect "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/provider/reflect" + "io" + "net/http" + "net/http/httputil" + "net/textproto" + "strings" + "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" - "io" - "net/http" - "net/http/httputil" - "net/textproto" - "reflect" - "strings" + + tfReflect "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/provider/reflect" ) func debugResponse(response *http.Response) string { @@ -45,19 +45,6 @@ func debugResponse(response *http.Response) string { return fmt.Sprintf("**Request**:\n%s\n**Response**:\n%s", string(dumpReq), string(dumpRes)) } -func reflectJSONKey(data any, key string) reflect.Value { - jsonIfied, err := json.Marshal(data) - if err != nil { - panic(fmt.Errorf("failed to marshal data: %w", err)) - } - var jsonMap map[string]interface{} - err = json.Unmarshal(jsonIfied, &jsonMap) - if err != nil { - panic(fmt.Errorf("failed to unmarshal data: %w", err)) - } - return reflect.ValueOf(jsonMap[key]) -} - func merge(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse, target interface{}) { var plan types.Object var state types.Object @@ -83,26 +70,45 @@ func merge(ctx context.Context, req resource.UpdateRequest, resp *resource.Updat return } - refreshPlan(ctx, plan, target, resp.Diagnostics) + resp.Diagnostics.Append(refreshPlan(ctx, plan, target)...) } -func refreshPlan(ctx context.Context, plan types.Object, target interface{}, diagnostics diag.Diagnostics) { +func refreshPlan(ctx context.Context, plan types.Object, target any) diag.Diagnostics { + var diags diag.Diagnostics + obj := types.ObjectType{AttrTypes: plan.AttributeTypes(ctx)} val, err := plan.ToTerraformValue(ctx) if err != nil { - diagnostics.Append(diag.NewErrorDiagnostic("Object Conversion Error", "An unexpected error was encountered trying to convert object. This is always an error in the provider. Please report the following to the provider developer:\n\n"+err.Error())) - return + diags.AddError( + "Object Conversion Error", + "An unexpected error was encountered trying to convert object. This is always an error in the provider. Please report the following to the provider developer:\n\n"+err.Error(), + ) + return diags } - diagnostics.Append(tfReflect.Into(ctx, obj, val, target, tfReflect.Options{ + + diags.Append(tfReflect.Into(ctx, obj, val, target, tfReflect.Options{ UnhandledNullAsEmpty: true, UnhandledUnknownAsEmpty: true, - SourceType: tfReflect.SourceTypePlan, }, path.Empty())...) + + return diags +} + +// Configurable options for the provider HTTP transport. +type ProviderHTTPTransportOpts struct { + // HTTP headers to set on all requests. + SetHeaders map[string]string + + // Underlying HTTP transport. + Transport http.RoundTripper } // Note: this is taken as a more minimal/specific version of https://github.com/hashicorp/terraform-plugin-sdk/blob/main/helper/logging/logging_http_transport.go -func NewLoggingHTTPTransport(t http.RoundTripper) *loggingHttpTransport { - return &loggingHttpTransport{t} +func NewProviderHTTPTransport(opts ProviderHTTPTransportOpts) *providerHttpTransport { + return &providerHttpTransport{ + setHeaders: opts.SetHeaders, + transport: opts.Transport, + } } const ( @@ -120,14 +126,18 @@ const ( FieldHttpTransactionId = "tf_http_trans_id" ) -type loggingHttpTransport struct { - transport http.RoundTripper +type providerHttpTransport struct { + setHeaders map[string]string + transport http.RoundTripper } -func (t *loggingHttpTransport) RoundTrip(req *http.Request) (*http.Response, error) { +func (t *providerHttpTransport) RoundTrip(req *http.Request) (*http.Response, error) { ctx := req.Context() ctx = t.addTransactionIdField(ctx) + // Set globally defined HTTP headers in the request + t.setRequestHeaders(req) + // Decompose the request bytes in a message (HTTP body) and fields (HTTP headers), then log it fields, err := decomposeRequestForLogging(req) if err != nil { @@ -157,7 +167,8 @@ func (t *loggingHttpTransport) RoundTrip(req *http.Request) (*http.Response, err return res, nil } -func (t *loggingHttpTransport) addTransactionIdField(ctx context.Context) context.Context { +// Generates UUID and sets it into the tf_http_trans_id logging field. +func (t *providerHttpTransport) addTransactionIdField(ctx context.Context) context.Context { tId, err := uuid.GenerateUUID() if err != nil { @@ -167,6 +178,13 @@ func (t *loggingHttpTransport) addTransactionIdField(ctx context.Context) contex return tflog.SetField(ctx, FieldHttpTransactionId, tId) } +// Sets globally defined HTTP headers in the request. +func (t *providerHttpTransport) setRequestHeaders(req *http.Request) { + for name, value := range t.setHeaders { + req.Header.Set(name, value) + } +} + func decomposeRequestForLogging(req *http.Request) (map[string]interface{}, error) { fields := make(map[string]interface{}, len(req.Header)+4) fields[FieldHttpOperationType] = OperationHttpRequest diff --git a/internal/sdk/.gitignore b/internal/sdk/.gitignore index 96942a4..46a743b 100644 --- a/internal/sdk/.gitignore +++ b/internal/sdk/.gitignore @@ -1,2 +1,7 @@ +.DS_Store +**/.speakeasy/temp/ +**/.speakeasy/logs/ +.env +.env.local .speakeasy/reports # .gitignore diff --git a/internal/sdk/designbuilder.go b/internal/sdk/designbuilder.go index d40d154..7ea9884 100644 --- a/internal/sdk/designbuilder.go +++ b/internal/sdk/designbuilder.go @@ -6,6 +6,7 @@ import ( "bytes" "context" "fmt" + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/internal/config" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/internal/hooks" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/internal/utils" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/errors" @@ -18,25 +19,22 @@ import ( // DesignBuilder - Available design-builder over designs provided by Design Builder v2 type DesignBuilder struct { - sdkConfiguration sdkConfiguration + rootSDK *SDK + sdkConfiguration config.SDKConfiguration + hooks *hooks.Hooks } -func newDesignBuilder(sdkConfig sdkConfiguration) *DesignBuilder { +func newDesignBuilder(rootSDK *SDK, sdkConfig config.SDKConfiguration, hooks *hooks.Hooks) *DesignBuilder { return &DesignBuilder{ + rootSDK: rootSDK, sdkConfiguration: sdkConfig, + hooks: hooks, } } // AddConsumer - addConsumer // Add a consumer that uses a specific design func (s *DesignBuilder) AddConsumer(ctx context.Context, request operations.AddConsumerRequest, opts ...operations.Option) (*operations.AddConsumerResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "addConsumer", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -60,6 +58,15 @@ func (s *DesignBuilder) AddConsumer(ctx context.Context, request operations.AddC return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "addConsumer", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } bodyReader, reqContentType, err := utils.SerializeRequestBody(ctx, request, false, false, "AddConsumerReq", "json", `request:"mediaType=application/json"`) if err != nil { return nil, err @@ -120,15 +127,17 @@ func (s *DesignBuilder) AddConsumer(ctx context.Context, request operations.AddC "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -145,7 +154,7 @@ func (s *DesignBuilder) AddConsumer(ctx context.Context, request operations.AddC err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -153,13 +162,13 @@ func (s *DesignBuilder) AddConsumer(ctx context.Context, request operations.AddC if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -172,17 +181,17 @@ func (s *DesignBuilder) AddConsumer(ctx context.Context, request operations.AddC err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -257,13 +266,6 @@ func (s *DesignBuilder) AddConsumer(ctx context.Context, request operations.AddC // AddDesign - addDesign // Create a brand new design linked to a organization, based in orgId attribute from JWT auth token func (s *DesignBuilder) AddDesign(ctx context.Context, request shared.AddDesignReq, opts ...operations.Option) (*operations.AddDesignResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "addDesign", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -287,6 +289,15 @@ func (s *DesignBuilder) AddDesign(ctx context.Context, request shared.AddDesignR return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "addDesign", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } bodyReader, reqContentType, err := utils.SerializeRequestBody(ctx, request, false, false, "Request", "json", `request:"mediaType=application/json"`) if err != nil { return nil, err @@ -347,15 +358,17 @@ func (s *DesignBuilder) AddDesign(ctx context.Context, request shared.AddDesignR "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -372,7 +385,7 @@ func (s *DesignBuilder) AddDesign(ctx context.Context, request shared.AddDesignR err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -380,13 +393,13 @@ func (s *DesignBuilder) AddDesign(ctx context.Context, request shared.AddDesignR if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -399,17 +412,17 @@ func (s *DesignBuilder) AddDesign(ctx context.Context, request shared.AddDesignR err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -503,13 +516,6 @@ func (s *DesignBuilder) AddDesign(ctx context.Context, request shared.AddDesignR // DeleteDesign - deleteDesign // Search and delete for a especific design owned by user organization func (s *DesignBuilder) DeleteDesign(ctx context.Context, request operations.DeleteDesignRequest, opts ...operations.Option) (*operations.DeleteDesignResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "deleteDesign", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -533,6 +539,16 @@ func (s *DesignBuilder) DeleteDesign(ctx context.Context, request operations.Del return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "deleteDesign", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } + timeout := o.Timeout if timeout == nil { timeout = s.sdkConfiguration.Timeout @@ -585,15 +601,17 @@ func (s *DesignBuilder) DeleteDesign(ctx context.Context, request operations.Del "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -610,7 +628,7 @@ func (s *DesignBuilder) DeleteDesign(ctx context.Context, request operations.Del err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -618,13 +636,13 @@ func (s *DesignBuilder) DeleteDesign(ctx context.Context, request operations.Del if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -637,17 +655,17 @@ func (s *DesignBuilder) DeleteDesign(ctx context.Context, request operations.Del err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -722,13 +740,6 @@ func (s *DesignBuilder) DeleteDesign(ctx context.Context, request operations.Del // GetAllDesigns - getAllDesigns // Scan all designs linked to a organization, based in orgId attribute from JWT auth token func (s *DesignBuilder) GetAllDesigns(ctx context.Context, opts ...operations.Option) (*operations.GetAllDesignsResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "getAllDesigns", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -752,6 +763,16 @@ func (s *DesignBuilder) GetAllDesigns(ctx context.Context, opts ...operations.Op return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "getAllDesigns", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } + timeout := o.Timeout if timeout == nil { timeout = s.sdkConfiguration.Timeout @@ -804,15 +825,17 @@ func (s *DesignBuilder) GetAllDesigns(ctx context.Context, opts ...operations.Op "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -829,7 +852,7 @@ func (s *DesignBuilder) GetAllDesigns(ctx context.Context, opts ...operations.Op err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -837,13 +860,13 @@ func (s *DesignBuilder) GetAllDesigns(ctx context.Context, opts ...operations.Op if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -856,17 +879,17 @@ func (s *DesignBuilder) GetAllDesigns(ctx context.Context, opts ...operations.Op err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -888,12 +911,12 @@ func (s *DesignBuilder) GetAllDesigns(ctx context.Context, opts ...operations.Op return nil, err } - var out []shared.GetAllDesignsRes + var out shared.GetAllDesignsRes if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil { return nil, err } - res.Classes = out + res.GetAllDesignsRes = &out default: rawBody, err := utils.ConsumeRawBody(httpRes) if err != nil { @@ -939,13 +962,6 @@ func (s *DesignBuilder) GetAllDesigns(ctx context.Context, opts ...operations.Op // // Deprecated: This will be removed in a future release, please migrate away from it as soon as possible. func (s *DesignBuilder) GetBrands(ctx context.Context, opts ...operations.Option) (*operations.GetBrandsResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "getBrands", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -969,6 +985,16 @@ func (s *DesignBuilder) GetBrands(ctx context.Context, opts ...operations.Option return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "getBrands", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } + timeout := o.Timeout if timeout == nil { timeout = s.sdkConfiguration.Timeout @@ -1021,15 +1047,17 @@ func (s *DesignBuilder) GetBrands(ctx context.Context, opts ...operations.Option "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -1046,7 +1074,7 @@ func (s *DesignBuilder) GetBrands(ctx context.Context, opts ...operations.Option err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -1054,13 +1082,13 @@ func (s *DesignBuilder) GetBrands(ctx context.Context, opts ...operations.Option if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -1073,17 +1101,17 @@ func (s *DesignBuilder) GetBrands(ctx context.Context, opts ...operations.Option err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -1154,13 +1182,6 @@ func (s *DesignBuilder) GetBrands(ctx context.Context, opts ...operations.Option // GetConsumerDesign - getConsumerDesign // Search for a especific design owned by user organization func (s *DesignBuilder) GetConsumerDesign(ctx context.Context, request operations.GetConsumerDesignRequest, opts ...operations.Option) (*operations.GetConsumerDesignResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "getConsumerDesign", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -1184,6 +1205,16 @@ func (s *DesignBuilder) GetConsumerDesign(ctx context.Context, request operation return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "getConsumerDesign", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } + timeout := o.Timeout if timeout == nil { timeout = s.sdkConfiguration.Timeout @@ -1236,15 +1267,17 @@ func (s *DesignBuilder) GetConsumerDesign(ctx context.Context, request operation "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -1261,7 +1294,7 @@ func (s *DesignBuilder) GetConsumerDesign(ctx context.Context, request operation err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -1269,13 +1302,13 @@ func (s *DesignBuilder) GetConsumerDesign(ctx context.Context, request operation if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -1288,17 +1321,17 @@ func (s *DesignBuilder) GetConsumerDesign(ctx context.Context, request operation err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -1393,13 +1426,6 @@ func (s *DesignBuilder) GetConsumerDesign(ctx context.Context, request operation // GetDesign - getDesign // Search for a especific design owned by user organization func (s *DesignBuilder) GetDesign(ctx context.Context, request operations.GetDesignRequest, opts ...operations.Option) (*operations.GetDesignResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "getDesign", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -1423,6 +1449,16 @@ func (s *DesignBuilder) GetDesign(ctx context.Context, request operations.GetDes return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "getDesign", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } + timeout := o.Timeout if timeout == nil { timeout = s.sdkConfiguration.Timeout @@ -1475,15 +1511,17 @@ func (s *DesignBuilder) GetDesign(ctx context.Context, request operations.GetDes "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -1500,7 +1538,7 @@ func (s *DesignBuilder) GetDesign(ctx context.Context, request operations.GetDes err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -1508,13 +1546,13 @@ func (s *DesignBuilder) GetDesign(ctx context.Context, request operations.GetDes if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -1527,17 +1565,17 @@ func (s *DesignBuilder) GetDesign(ctx context.Context, request operations.GetDes err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -1632,13 +1670,6 @@ func (s *DesignBuilder) GetDesign(ctx context.Context, request operations.GetDes // GetFiles - getFiles // List all files for the user organization bucket func (s *DesignBuilder) GetFiles(ctx context.Context, request operations.GetFilesRequest, opts ...operations.Option) (*operations.GetFilesResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "getFiles", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -1662,6 +1693,16 @@ func (s *DesignBuilder) GetFiles(ctx context.Context, request operations.GetFile return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "getFiles", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } + timeout := o.Timeout if timeout == nil { timeout = s.sdkConfiguration.Timeout @@ -1680,7 +1721,7 @@ func (s *DesignBuilder) GetFiles(ctx context.Context, request operations.GetFile req.Header.Set("Accept", "application/json") req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent) - if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { + if err := utils.PopulateQueryParams(ctx, req, request, nil, nil); err != nil { return nil, fmt.Errorf("error populating query params: %w", err) } @@ -1718,15 +1759,17 @@ func (s *DesignBuilder) GetFiles(ctx context.Context, request operations.GetFile "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -1743,7 +1786,7 @@ func (s *DesignBuilder) GetFiles(ctx context.Context, request operations.GetFile err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -1751,13 +1794,13 @@ func (s *DesignBuilder) GetFiles(ctx context.Context, request operations.GetFile if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -1770,17 +1813,17 @@ func (s *DesignBuilder) GetFiles(ctx context.Context, request operations.GetFile err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -1876,13 +1919,6 @@ func (s *DesignBuilder) GetFiles(ctx context.Context, request operations.GetFile // // Deprecated: This will be removed in a future release, please migrate away from it as soon as possible. func (s *DesignBuilder) GetLimit(ctx context.Context, opts ...operations.Option) (*operations.GetLimitResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "getLimit", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -1906,6 +1942,16 @@ func (s *DesignBuilder) GetLimit(ctx context.Context, opts ...operations.Option) return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "getLimit", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } + timeout := o.Timeout if timeout == nil { timeout = s.sdkConfiguration.Timeout @@ -1958,15 +2004,17 @@ func (s *DesignBuilder) GetLimit(ctx context.Context, opts ...operations.Option) "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -1983,7 +2031,7 @@ func (s *DesignBuilder) GetLimit(ctx context.Context, opts ...operations.Option) err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -1991,13 +2039,13 @@ func (s *DesignBuilder) GetLimit(ctx context.Context, opts ...operations.Option) if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -2010,17 +2058,17 @@ func (s *DesignBuilder) GetLimit(ctx context.Context, opts ...operations.Option) err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -2091,13 +2139,6 @@ func (s *DesignBuilder) GetLimit(ctx context.Context, opts ...operations.Option) // GetThemeFromDesign - getThemeFromDesign // Search for a especific design owned by user organization and parse them to a new or old theme func (s *DesignBuilder) GetThemeFromDesign(ctx context.Context, request operations.GetThemeFromDesignRequest, opts ...operations.Option) (*operations.GetThemeFromDesignResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "getThemeFromDesign", - OAuth2Scopes: []string{}, - SecuritySource: nil, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -2121,6 +2162,16 @@ func (s *DesignBuilder) GetThemeFromDesign(ctx context.Context, request operatio return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "getThemeFromDesign", + OAuth2Scopes: nil, + SecuritySource: nil, + } + timeout := o.Timeout if timeout == nil { timeout = s.sdkConfiguration.Timeout @@ -2139,7 +2190,7 @@ func (s *DesignBuilder) GetThemeFromDesign(ctx context.Context, request operatio req.Header.Set("Accept", "application/json") req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent) - if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { + if err := utils.PopulateQueryParams(ctx, req, request, nil, nil); err != nil { return nil, fmt.Errorf("error populating query params: %w", err) } @@ -2173,15 +2224,17 @@ func (s *DesignBuilder) GetThemeFromDesign(ctx context.Context, request operatio "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -2198,7 +2251,7 @@ func (s *DesignBuilder) GetThemeFromDesign(ctx context.Context, request operatio err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -2206,13 +2259,13 @@ func (s *DesignBuilder) GetThemeFromDesign(ctx context.Context, request operatio if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -2225,17 +2278,17 @@ func (s *DesignBuilder) GetThemeFromDesign(ctx context.Context, request operatio err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -2330,13 +2383,6 @@ func (s *DesignBuilder) GetThemeFromDesign(ctx context.Context, request operatio // RemoveConsumer - removeConsumer // Remove a consumer that uses a specific design func (s *DesignBuilder) RemoveConsumer(ctx context.Context, request operations.RemoveConsumerRequest, opts ...operations.Option) (*operations.RemoveConsumerResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "removeConsumer", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -2360,7 +2406,16 @@ func (s *DesignBuilder) RemoveConsumer(ctx context.Context, request operations.R return nil, fmt.Errorf("error generating URL: %w", err) } - bodyReader, reqContentType, err := utils.SerializeRequestBody(ctx, request, false, false, "AddConsumerReq", "json", `request:"mediaType=application/json"`) + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "removeConsumer", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } + bodyReader, reqContentType, err := utils.SerializeRequestBody(ctx, request, false, false, "RemoveConsumerReq", "json", `request:"mediaType=application/json"`) if err != nil { return nil, err } @@ -2420,15 +2475,17 @@ func (s *DesignBuilder) RemoveConsumer(ctx context.Context, request operations.R "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -2445,7 +2502,7 @@ func (s *DesignBuilder) RemoveConsumer(ctx context.Context, request operations.R err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -2453,13 +2510,13 @@ func (s *DesignBuilder) RemoveConsumer(ctx context.Context, request operations.R if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -2472,17 +2529,17 @@ func (s *DesignBuilder) RemoveConsumer(ctx context.Context, request operations.R err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -2557,13 +2614,6 @@ func (s *DesignBuilder) RemoveConsumer(ctx context.Context, request operations.R // UpdateDesign - updateDesign // Update a especific design owned by user organization func (s *DesignBuilder) UpdateDesign(ctx context.Context, request operations.UpdateDesignRequest, opts ...operations.Option) (*operations.UpdateDesignResponse, error) { - hookCtx := hooks.HookContext{ - Context: ctx, - OperationID: "updateDesign", - OAuth2Scopes: []string{}, - SecuritySource: s.sdkConfiguration.Security, - } - o := operations.Options{} supportedOptions := []string{ operations.SupportedOptionRetries, @@ -2587,6 +2637,15 @@ func (s *DesignBuilder) UpdateDesign(ctx context.Context, request operations.Upd return nil, fmt.Errorf("error generating URL: %w", err) } + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "updateDesign", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } bodyReader, reqContentType, err := utils.SerializeRequestBody(ctx, request, false, false, "UpdateDesignReq", "json", `request:"mediaType=application/json"`) if err != nil { return nil, err @@ -2647,15 +2706,17 @@ func (s *DesignBuilder) UpdateDesign(ctx context.Context, request operations.Upd "5XX", }, }, func() (*http.Response, error) { - if req.Body != nil { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { copyBody, err := req.GetBody() + if err != nil { return nil, err } + req.Body = copyBody } - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { return nil, err @@ -2672,7 +2733,7 @@ func (s *DesignBuilder) UpdateDesign(ctx context.Context, request operations.Upd err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) } return httpRes, err }) @@ -2680,13 +2741,13 @@ func (s *DesignBuilder) UpdateDesign(ctx context.Context, request operations.Upd if err != nil { return nil, err } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } } } else { - req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) if err != nil { return nil, err } @@ -2699,17 +2760,17 @@ func (s *DesignBuilder) UpdateDesign(ctx context.Context, request operations.Upd err = fmt.Errorf("error sending request: no response") } - _, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) return nil, err } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { - _httpRes, err := s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) if err != nil { return nil, err } else if _httpRes != nil { httpRes = _httpRes } } else { - httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) if err != nil { return nil, err } @@ -2780,3 +2841,253 @@ func (s *DesignBuilder) UpdateDesign(ctx context.Context, request operations.Upd return res, nil } + +// UploadFile - uploadFile +// Upload a new file for the user organization bucket +func (s *DesignBuilder) UploadFile(ctx context.Context, request shared.UploadFileReq, opts ...operations.Option) (*operations.UploadFileResponse, error) { + o := operations.Options{} + supportedOptions := []string{ + operations.SupportedOptionRetries, + operations.SupportedOptionTimeout, + } + + for _, opt := range opts { + if err := opt(&o, supportedOptions...); err != nil { + return nil, fmt.Errorf("error applying option: %w", err) + } + } + + var baseURL string + if o.ServerURL == nil { + baseURL = utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) + } else { + baseURL = *o.ServerURL + } + opURL, err := url.JoinPath(baseURL, "/v1/designs/files") + if err != nil { + return nil, fmt.Errorf("error generating URL: %w", err) + } + + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "uploadFile", + OAuth2Scopes: nil, + SecuritySource: s.sdkConfiguration.Security, + } + bodyReader, reqContentType, err := utils.SerializeRequestBody(ctx, request, false, false, "Request", "multipart", `request:"mediaType=multipart/form-data"`) + if err != nil { + return nil, err + } + + timeout := o.Timeout + if timeout == nil { + timeout = s.sdkConfiguration.Timeout + } + + if timeout != nil { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, *timeout) + defer cancel() + } + + req, err := http.NewRequestWithContext(ctx, "POST", opURL, bodyReader) + if err != nil { + return nil, fmt.Errorf("error creating request: %w", err) + } + req.Header.Set("Accept", "application/json") + req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent) + if reqContentType != "" { + req.Header.Set("Content-Type", reqContentType) + } + + if err := utils.PopulateSecurity(ctx, req, s.sdkConfiguration.Security); err != nil { + return nil, err + } + + for k, v := range o.SetHeaders { + req.Header.Set(k, v) + } + + globalRetryConfig := s.sdkConfiguration.RetryConfig + retryConfig := o.Retries + if retryConfig == nil { + if globalRetryConfig != nil { + retryConfig = globalRetryConfig + } else { + retryConfig = &retry.Config{ + Strategy: "backoff", Backoff: &retry.BackoffStrategy{ + InitialInterval: 5000, + MaxInterval: 60000, + Exponent: 1.5, + MaxElapsedTime: 3600000, + }, + RetryConnectionErrors: true, + } + } + } + + var httpRes *http.Response + if retryConfig != nil { + httpRes, err = utils.Retry(ctx, utils.Retries{ + Config: retryConfig, + StatusCodes: []string{ + "5XX", + }, + }, func() (*http.Response, error) { + if req.Body != nil && req.Body != http.NoBody && req.GetBody != nil { + copyBody, err := req.GetBody() + + if err != nil { + return nil, err + } + + req.Body = copyBody + } + + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + if err != nil { + if retry.IsPermanentError(err) || retry.IsTemporaryError(err) { + return nil, err + } + + return nil, retry.Permanent(err) + } + + httpRes, err := s.sdkConfiguration.Client.Do(req) + if err != nil || httpRes == nil { + if err != nil { + err = fmt.Errorf("error sending request: %w", err) + } else { + err = fmt.Errorf("error sending request: no response") + } + + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + } + return httpRes, err + }) + + if err != nil { + return nil, err + } else { + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + if err != nil { + return nil, err + } + } + } else { + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + if err != nil { + return nil, err + } + + httpRes, err = s.sdkConfiguration.Client.Do(req) + if err != nil || httpRes == nil { + if err != nil { + err = fmt.Errorf("error sending request: %w", err) + } else { + err = fmt.Errorf("error sending request: no response") + } + + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + return nil, err + } else if utils.MatchStatusCodes([]string{}, httpRes.StatusCode) { + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + if err != nil { + return nil, err + } else if _httpRes != nil { + httpRes = _httpRes + } + } else { + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + if err != nil { + return nil, err + } + } + } + + res := &operations.UploadFileResponse{ + StatusCode: httpRes.StatusCode, + ContentType: httpRes.Header.Get("Content-Type"), + RawResponse: httpRes, + } + + switch { + case httpRes.StatusCode == 201: + switch { + case utils.MatchContentType(httpRes.Header.Get("Content-Type"), `application/json`): + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + + var out shared.UploadFileRes + if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil { + return nil, err + } + + res.UploadFileRes = &out + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, errors.NewSDKError(fmt.Sprintf("unknown content-type received: %s", httpRes.Header.Get("Content-Type")), httpRes.StatusCode, string(rawBody), httpRes) + } + case httpRes.StatusCode == 400: + fallthrough + case httpRes.StatusCode == 401: + switch { + case utils.MatchContentType(httpRes.Header.Get("Content-Type"), `application/json`): + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + + var out shared.ErrorResp + if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil { + return nil, err + } + + res.ErrorResp = &out + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, errors.NewSDKError(fmt.Sprintf("unknown content-type received: %s", httpRes.Header.Get("Content-Type")), httpRes.StatusCode, string(rawBody), httpRes) + } + case httpRes.StatusCode == 500: + switch { + case utils.MatchContentType(httpRes.Header.Get("Content-Type"), `application/json`): + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + + var out shared.ErrorResp + if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil { + return nil, err + } + + res.ErrorResp = &out + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, errors.NewSDKError(fmt.Sprintf("unknown content-type received: %s", httpRes.Header.Get("Content-Type")), httpRes.StatusCode, string(rawBody), httpRes) + } + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, errors.NewSDKError("unknown status code returned", httpRes.StatusCode, string(rawBody), httpRes) + } + + return res, nil + +} diff --git a/internal/sdk/docs/models/operations/option.md b/internal/sdk/docs/models/operations/option.md new file mode 100644 index 0000000..35d8a1e --- /dev/null +++ b/internal/sdk/docs/models/operations/option.md @@ -0,0 +1,37 @@ +## Options + +### WithServerURL + +WithServerURL allows providing an alternative server URL. + +```go +operations.WithServerURL("http://api.example.com") +``` + +## WithTemplatedServerURL + +WithTemplatedServerURL allows providing an alternative server URL with templated parameters. + +```go +operations.WithTemplatedServerURL("http://{host}:{port}", map[string]string{ + "host": "api.example.com", + "port": "8080", +}) +``` + +### WithRetries + +WithRetries allows customizing the default retry configuration. Only usable with methods that mention they support retries. + +```go +operations.WithRetries(retry.Config{ + Strategy: "backoff", + Backoff: retry.BackoffStrategy{ + InitialInterval: 500 * time.Millisecond, + MaxInterval: 60 * time.Second, + Exponent: 1.5, + MaxElapsedTime: 5 * time.Minute, + }, + RetryConnectionErrors: true, +}) +``` \ No newline at end of file diff --git a/internal/sdk/internal/config/sdkconfiguration.go b/internal/sdk/internal/config/sdkconfiguration.go new file mode 100644 index 0000000..f271f46 --- /dev/null +++ b/internal/sdk/internal/config/sdkconfiguration.go @@ -0,0 +1,33 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package config + +import ( + "context" + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/retry" + "net/http" + "time" +) + +type HTTPClient interface { + Do(req *http.Request) (*http.Response, error) +} + +type SDKConfiguration struct { + Client HTTPClient + Security func(context.Context) (interface{}, error) + ServerURL string + ServerIndex int + ServerList []string + UserAgent string + RetryConfig *retry.Config + Timeout *time.Duration +} + +func (c *SDKConfiguration) GetServerDetails() (string, map[string]string) { + if c.ServerURL != "" { + return c.ServerURL, nil + } + + return c.ServerList[c.ServerIndex], nil +} diff --git a/internal/sdk/internal/hooks/hooks.go b/internal/sdk/internal/hooks/hooks.go index 8ea491a..b76f0ef 100644 --- a/internal/sdk/internal/hooks/hooks.go +++ b/internal/sdk/internal/hooks/hooks.go @@ -5,6 +5,7 @@ package hooks import ( "context" "errors" + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/internal/config" "net/http" ) @@ -24,10 +25,13 @@ type HTTPClient interface { } type HookContext struct { - Context context.Context - OperationID string - OAuth2Scopes []string - SecuritySource func(context.Context) (interface{}, error) + SDK any + SDKConfiguration config.SDKConfiguration + BaseURL string + Context context.Context + OperationID string + OAuth2Scopes []string + SecuritySource func(context.Context) (interface{}, error) } type BeforeRequestContext struct { @@ -70,6 +74,11 @@ type Hooks struct { afterErrorHook []afterErrorHook } +var _ sdkInitHook = (*Hooks)(nil) +var _ beforeRequestHook = (*Hooks)(nil) +var _ afterSuccessHook = (*Hooks)(nil) +var _ afterErrorHook = (*Hooks)(nil) + func New() *Hooks { h := &Hooks{ sdkInitHooks: []sdkInitHook{}, diff --git a/internal/sdk/internal/utils/form.go b/internal/sdk/internal/utils/form.go index b4a06a9..526b356 100644 --- a/internal/sdk/internal/utils/form.go +++ b/internal/sdk/internal/utils/form.go @@ -10,16 +10,21 @@ import ( "strings" "time" - "github.com/ericlagergren/decimal" - + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/optionalnullable" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/types" ) -func populateForm(paramName string, explode bool, objType reflect.Type, objValue reflect.Value, delimiter string, getFieldName func(reflect.StructField) string) url.Values { +func populateForm(paramName string, explode bool, objType reflect.Type, objValue reflect.Value, delimiter string, defaultValue *string, allowEmptyValue map[string]struct{}, getFieldName func(reflect.StructField) string) url.Values { formValues := url.Values{} if isNil(objType, objValue) { + if defaultValue != nil { + formValues.Add(paramName, *defaultValue) + } else if _, ok := allowEmptyValue[paramName]; ok { + formValues.Add(paramName, "") + } + return formValues } @@ -37,8 +42,6 @@ func populateForm(paramName string, explode bool, objType reflect.Type, objValue formValues.Add(paramName, valToString(objValue.Interface())) case big.Int: formValues.Add(paramName, valToString(objValue.Interface())) - case decimal.Big: - formValues.Add(paramName, valToString(objValue.Interface())) default: var items []string @@ -60,7 +63,13 @@ func populateForm(paramName string, explode bool, objType reflect.Type, objValue } if explode { - formValues.Add(fieldName, valToString(valType.Interface())) + if valType.Kind() == reflect.Slice || valType.Kind() == reflect.Array { + for i := 0; i < valType.Len(); i++ { + formValues.Add(fieldName, valToString(valType.Index(i).Interface())) + } + } else { + formValues.Add(fieldName, valToString(valType.Interface())) + } } else { items = append(items, fmt.Sprintf("%s%s%s", fieldName, delimiter, valToString(valType.Interface()))) } @@ -71,6 +80,16 @@ func populateForm(paramName string, explode bool, objType reflect.Type, objValue } } case reflect.Map: + // check if optionalnullable.OptionalNullable[T] + if nullableValue, ok := optionalnullable.AsOptionalNullable(objValue); ok { + // Handle optionalnullable.OptionalNullable[T] using GetUntyped method + if value, isSet := nullableValue.GetUntyped(); isSet && value != nil { + formValues.Add(paramName, valToString(value)) + } + // If not set or explicitly null, skip adding to form + return formValues + } + items := []string{} iter := objValue.MapRange() @@ -86,12 +105,31 @@ func populateForm(paramName string, explode bool, objType reflect.Type, objValue formValues.Add(paramName, strings.Join(items, delimiter)) } case reflect.Slice, reflect.Array: - values := parseDelimitedArray(explode, objValue, delimiter) - for _, v := range values { - formValues.Add(paramName, v) + if objValue.Len() == 0 { + if _, ok := allowEmptyValue[paramName]; ok { + formValues.Add(paramName, "") + } + } else { + values := parseDelimitedArray(explode, objValue, delimiter) + for _, v := range values { + formValues.Add(paramName, v) + } } default: - formValues.Add(paramName, valToString(objValue.Interface())) + // For string types, use the value directly without conversion + if objType.Kind() == reflect.String { + stringValue := objValue.String() + formValues.Add(paramName, stringValue) + } else { + stringValue := valToString(objValue.Interface()) + if stringValue == "" { + if _, ok := allowEmptyValue[paramName]; ok { + formValues.Add(paramName, "") + } + } else if stringValue != "" { + formValues.Add(paramName, stringValue) + } + } } return formValues diff --git a/internal/sdk/internal/utils/headers.go b/internal/sdk/internal/utils/headers.go index a07608b..cfdee12 100644 --- a/internal/sdk/internal/utils/headers.go +++ b/internal/sdk/internal/utils/headers.go @@ -8,6 +8,8 @@ import ( "net/http" "reflect" "strings" + + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/optionalnullable" ) func PopulateHeaders(_ context.Context, req *http.Request, headers interface{}, globals interface{}) { @@ -98,6 +100,16 @@ func serializeHeader(objType reflect.Type, objValue reflect.Value, explode bool) return strings.Join(items, ",") case reflect.Map: + // check if optionalnullable.OptionalNullable[T] + if nullableValue, ok := optionalnullable.AsOptionalNullable(objValue); ok { + // Handle optionalnullable.OptionalNullable[T] using GetUntyped method + if value, isSet := nullableValue.GetUntyped(); isSet && value != nil { + return valToString(value) + } + // If not set or explicitly null, return empty string + return "" + } + items := []string{} iter := objValue.MapRange() diff --git a/internal/sdk/internal/utils/json.go b/internal/sdk/internal/utils/json.go index eaadc41..a28fe89 100644 --- a/internal/sdk/internal/utils/json.go +++ b/internal/sdk/internal/utils/json.go @@ -5,6 +5,7 @@ package utils import ( "bytes" "encoding/json" + "errors" "fmt" "math/big" "reflect" @@ -14,8 +15,6 @@ import ( "unsafe" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/types" - - "github.com/ericlagergren/decimal" ) func MarshalJSON(v interface{}, tag reflect.StructTag, topLevel bool) ([]byte, error) { @@ -40,21 +39,30 @@ func MarshalJSON(v interface{}, tag reflect.StructTag, topLevel bool) ([]byte, e fieldName := field.Name omitEmpty := false + omitZero := false jsonTag := field.Tag.Get("json") if jsonTag != "" { for _, tag := range strings.Split(jsonTag, ",") { if tag == "omitempty" { omitEmpty = true + } else if tag == "omitzero" { + omitZero = true } else { fieldName = tag } } } - if isNil(field.Type, fieldVal) && field.Tag.Get("const") == "" { - if omitEmpty { + if (omitEmpty || omitZero) && field.Tag.Get("const") == "" { + // Both omitempty and omitzero skip zero values (including nil) + if isNil(field.Type, fieldVal) { + continue + } + + if omitZero && fieldVal.IsZero() { continue } + } if !field.IsExported() && field.Tag.Get("const") == "" { @@ -114,9 +122,9 @@ func MarshalJSON(v interface{}, tag reflect.StructTag, topLevel bool) ([]byte, e } } -func UnmarshalJSON(b []byte, v interface{}, tag reflect.StructTag, topLevel bool, disallowUnknownFields bool) error { +func UnmarshalJSON(b []byte, v interface{}, tag reflect.StructTag, topLevel bool, requiredFields []string) error { if reflect.TypeOf(v).Kind() != reflect.Ptr { - return fmt.Errorf("v must be a pointer") + return errors.New("v must be a pointer") } typ, val := dereferencePointers(reflect.TypeOf(v), reflect.ValueOf(v)) @@ -124,19 +132,25 @@ func UnmarshalJSON(b []byte, v interface{}, tag reflect.StructTag, topLevel bool switch { case isModelType(typ): if topLevel || bytes.Equal(b, []byte("null")) { - d := json.NewDecoder(bytes.NewReader(b)) - if disallowUnknownFields { - d.DisallowUnknownFields() - } - return d.Decode(v) + return json.Unmarshal(b, v) } - var unmarhsaled map[string]json.RawMessage + var unmarshaled map[string]json.RawMessage - if err := json.Unmarshal(b, &unmarhsaled); err != nil { + if err := json.Unmarshal(b, &unmarshaled); err != nil { return err } + missingFields := []string{} + for _, requiredField := range requiredFields { + if _, ok := unmarshaled[requiredField]; !ok { + missingFields = append(missingFields, requiredField) + } + } + if len(missingFields) > 0 { + return fmt.Errorf("missing required fields: %s", strings.Join(missingFields, ", ")) + } + var additionalPropertiesField *reflect.StructField var additionalPropertiesValue *reflect.Value @@ -149,7 +163,7 @@ func UnmarshalJSON(b []byte, v interface{}, tag reflect.StructTag, topLevel bool jsonTag := field.Tag.Get("json") if jsonTag != "" { for _, tag := range strings.Split(jsonTag, ",") { - if tag != "omitempty" { + if tag != "omitempty" && tag != "omitzero" { fieldName = tag } } @@ -163,7 +177,7 @@ func UnmarshalJSON(b []byte, v interface{}, tag reflect.StructTag, topLevel bool // If we receive a value for a const field ignore it but mark it as unmarshaled if field.Tag.Get("const") != "" { - if r, ok := unmarhsaled[fieldName]; ok { + if r, ok := unmarshaled[fieldName]; ok { val := string(r) if strings.HasPrefix(val, `"`) && strings.HasSuffix(val, `"`) { @@ -178,40 +192,36 @@ func UnmarshalJSON(b []byte, v interface{}, tag reflect.StructTag, topLevel bool return fmt.Errorf("const field `%s` does not match expected value `%s` got `%s`", fieldName, constValue, val) } - delete(unmarhsaled, fieldName) + delete(unmarshaled, fieldName) } } else if !field.IsExported() { continue } - value, ok := unmarhsaled[fieldName] + value, ok := unmarshaled[fieldName] if !ok { - defaultTag := field.Tag.Get("default") - if defaultTag != "" { + defaultTag, defaultOk := field.Tag.Lookup("default") + if defaultOk { value = handleDefaultConstValue(defaultTag, fieldVal.Interface(), field.Tag) ok = true } } else { - delete(unmarhsaled, fieldName) + delete(unmarshaled, fieldName) } if ok { - if err := unmarshalValue(value, fieldVal, field.Tag, disallowUnknownFields); err != nil { + if err := unmarshalValue(value, fieldVal, field.Tag); err != nil { return err } } } - keys := make([]string, 0, len(unmarhsaled)) - for k := range unmarhsaled { + keys := make([]string, 0, len(unmarshaled)) + for k := range unmarshaled { keys = append(keys, k) } if len(keys) > 0 { - if disallowUnknownFields && (additionalPropertiesField == nil || additionalPropertiesValue == nil) { - return fmt.Errorf("unknown fields: %v", keys) - } - if additionalPropertiesField != nil && additionalPropertiesValue != nil { typeOfMap := additionalPropertiesField.Type if additionalPropertiesValue.Type().Kind() == reflect.Interface { @@ -222,10 +232,10 @@ func UnmarshalJSON(b []byte, v interface{}, tag reflect.StructTag, topLevel bool mapValue := reflect.MakeMap(typeOfMap) - for key, value := range unmarhsaled { + for key, value := range unmarshaled { val := reflect.New(typeOfMap.Elem()) - if err := unmarshalValue(value, val, additionalPropertiesField.Tag, disallowUnknownFields); err != nil { + if err := unmarshalValue(value, val, additionalPropertiesField.Tag); err != nil { return err } @@ -244,7 +254,7 @@ func UnmarshalJSON(b []byte, v interface{}, tag reflect.StructTag, topLevel bool } } default: - return unmarshalValue(b, reflect.ValueOf(v), tag, disallowUnknownFields) + return unmarshalValue(b, reflect.ValueOf(v), tag) } return nil @@ -257,8 +267,8 @@ func marshalValue(v interface{}, tag reflect.StructTag) (json.RawMessage, error) } if isNil(reflect.TypeOf(v), reflect.ValueOf(v)) { - defaultTag := tag.Get("default") - if defaultTag != "" { + defaultTag, ok := tag.Lookup("default") + if ok { return handleDefaultConstValue(defaultTag, v, tag), nil } @@ -284,6 +294,11 @@ func marshalValue(v interface{}, tag reflect.StructTag) (json.RawMessage, error) return []byte("null"), nil } + // Check if the map implements json.Marshaler (like optionalnullable.OptionalNullable[T]) + if marshaler, ok := val.Interface().(json.Marshaler); ok { + return marshaler.MarshalJSON() + } + out := map[string]json.RawMessage{} for _, key := range val.MapKeys() { @@ -337,17 +352,6 @@ func marshalValue(v interface{}, tag reflect.StructTag) (json.RawMessage, error) b := val.Interface().(big.Int) return []byte(fmt.Sprintf(`"%s"`, (&b).String())), nil } - case reflect.TypeOf(decimal.Big{}): - format := tag.Get("decimal") - if format == "number" { - b := val.Interface().(decimal.Big) - f, ok := (&b).Float64() - if ok { - return []byte(b.String()), nil - } - - return []byte(fmt.Sprintf(`%f`, f)), nil - } } } @@ -378,11 +382,6 @@ func handleDefaultConstValue(tagValue string, val interface{}, tag reflect.Struc if format == "string" { return []byte(fmt.Sprintf(`"%s"`, tagValue)) } - case reflect.TypeOf(decimal.Big{}): - decimalTag := tag.Get("decimal") - if decimalTag != "number" { - return []byte(fmt.Sprintf(`"%s"`, tagValue)) - } case reflect.TypeOf(types.Date{}): return []byte(fmt.Sprintf(`"%s"`, tagValue)) default: @@ -394,7 +393,7 @@ func handleDefaultConstValue(tagValue string, val interface{}, tag reflect.Struc return []byte(tagValue) } -func unmarshalValue(value json.RawMessage, v reflect.Value, tag reflect.StructTag, disallowUnknownFields bool) error { +func unmarshalValue(value json.RawMessage, v reflect.Value, tag reflect.StructTag) error { if bytes.Equal(value, []byte("null")) { if v.CanAddr() { return json.Unmarshal(value, v.Addr().Interface()) @@ -466,18 +465,18 @@ func unmarshalValue(value json.RawMessage, v reflect.Value, tag reflect.StructTa } } - var unmarhsaled map[string]json.RawMessage + var unmarshaled map[string]json.RawMessage - if err := json.Unmarshal(value, &unmarhsaled); err != nil { + if err := json.Unmarshal(value, &unmarshaled); err != nil { return err } m := reflect.MakeMap(typ) - for k, value := range unmarhsaled { + for k, value := range unmarshaled { itemVal := reflect.New(typ.Elem()) - if err := unmarshalValue(value, itemVal, tag, disallowUnknownFields); err != nil { + if err := unmarshalValue(value, itemVal, tag); err != nil { return err } @@ -498,7 +497,7 @@ func unmarshalValue(value json.RawMessage, v reflect.Value, tag reflect.StructTa for index, value := range unmarshaled { itemVal := reflect.New(typ.Elem()) - if err := unmarshalValue(value, itemVal, tag, disallowUnknownFields); err != nil { + if err := unmarshalValue(value, itemVal, tag); err != nil { return err } @@ -563,27 +562,6 @@ func unmarshalValue(value json.RawMessage, v reflect.Value, tag reflect.StructTa v.Set(reflect.ValueOf(b)) return nil - case reflect.TypeOf(decimal.Big{}): - var d *decimal.Big - format := tag.Get("decimal") - if format == "number" { - var ok bool - d, ok = new(decimal.Big).SetString(string(value)) - if !ok { - return fmt.Errorf("failed to parse number as decimal.Big") - } - } else { - if err := json.Unmarshal(value, &d); err != nil { - return err - } - } - - if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Ptr { - v = v.Elem() - } - - v.Set(reflect.ValueOf(d)) - return nil case reflect.TypeOf(types.Date{}): var s string @@ -616,11 +594,7 @@ func unmarshalValue(value json.RawMessage, v reflect.Value, tag reflect.StructTa val = v.Interface() } - d := json.NewDecoder(bytes.NewReader(value)) - if disallowUnknownFields { - d.DisallowUnknownFields() - } - return d.Decode(val) + return json.Unmarshal(value, val) } func dereferencePointers(typ reflect.Type, val reflect.Value) (reflect.Type, reflect.Value) { @@ -652,8 +626,6 @@ func isComplexValueType(typ reflect.Type) bool { fallthrough case reflect.TypeOf(big.Int{}): fallthrough - case reflect.TypeOf(decimal.Big{}): - fallthrough case reflect.TypeOf(types.Date{}): return true } diff --git a/internal/sdk/internal/utils/pathparams.go b/internal/sdk/internal/utils/pathparams.go index 7dca519..a91689f 100644 --- a/internal/sdk/internal/utils/pathparams.go +++ b/internal/sdk/internal/utils/pathparams.go @@ -11,8 +11,7 @@ import ( "strings" "time" - "github.com/ericlagergren/decimal" - + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/optionalnullable" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/types" ) @@ -114,6 +113,16 @@ func getSimplePathParams(parentName string, objType reflect.Type, objValue refle } pathParams[parentName] = strings.Join(ppVals, ",") case reflect.Map: + // check if optionalnullable.OptionalNullable[T] + if nullableValue, ok := optionalnullable.AsOptionalNullable(objValue); ok { + // Handle optionalnullable.OptionalNullable[T] using GetUntyped method + if value, isSet := nullableValue.GetUntyped(); isSet && value != nil { + pathParams[parentName] = valToString(value) + } + // If not set or explicitly null, return nil (skip parameter) + return pathParams + } + if objValue.Len() == 0 { return nil } @@ -135,8 +144,6 @@ func getSimplePathParams(parentName string, objType reflect.Type, objValue refle pathParams[parentName] = valToString(objValue.Interface()) case big.Int: pathParams[parentName] = valToString(objValue.Interface()) - case decimal.Big: - pathParams[parentName] = valToString(objValue.Interface()) default: var ppVals []string for i := 0; i < objType.NumField(); i++ { diff --git a/internal/sdk/internal/utils/queryparams.go b/internal/sdk/internal/utils/queryparams.go index 78d41a7..b17ee91 100644 --- a/internal/sdk/internal/utils/queryparams.go +++ b/internal/sdk/internal/utils/queryparams.go @@ -12,12 +12,11 @@ import ( "reflect" "time" - "github.com/ericlagergren/decimal" - + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/optionalnullable" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/types" ) -func PopulateQueryParams(_ context.Context, req *http.Request, queryParams interface{}, globals interface{}) error { +func PopulateQueryParams(_ context.Context, req *http.Request, queryParams interface{}, globals interface{}, allowEmptyValue map[string]struct{}) error { // Query parameters may already be present from overriding URL if req.URL.RawQuery != "" { return nil @@ -25,13 +24,13 @@ func PopulateQueryParams(_ context.Context, req *http.Request, queryParams inter values := url.Values{} - globalsAlreadyPopulated, err := populateQueryParams(queryParams, globals, values, []string{}) + globalsAlreadyPopulated, err := populateQueryParams(queryParams, globals, values, []string{}, allowEmptyValue) if err != nil { return err } if globals != nil { - _, err = populateQueryParams(globals, nil, values, globalsAlreadyPopulated) + _, err = populateQueryParams(globals, nil, values, globalsAlreadyPopulated, allowEmptyValue) if err != nil { return err } @@ -42,11 +41,14 @@ func PopulateQueryParams(_ context.Context, req *http.Request, queryParams inter return nil } -func populateQueryParams(queryParams interface{}, globals interface{}, values url.Values, skipFields []string) ([]string, error) { - queryParamsStructType, queryParamsValType := dereferencePointers(reflect.TypeOf(queryParams), reflect.ValueOf(queryParams)) +func populateQueryParams(queryParams interface{}, globals interface{}, values url.Values, skipFields []string, allowEmptyValue map[string]struct{}) ([]string, error) { + queryParamsVal := reflect.ValueOf(queryParams) + if queryParamsVal.Kind() == reflect.Pointer && queryParamsVal.IsNil() { + return nil, nil + } + queryParamsStructType, queryParamsValType := dereferencePointers(reflect.TypeOf(queryParams), queryParamsVal) globalsAlreadyPopulated := []string{} - for i := 0; i < queryParamsStructType.NumField(); i++ { fieldType := queryParamsStructType.Field(i) valType := queryParamsValType.Field(i) @@ -65,6 +67,14 @@ func populateQueryParams(queryParams interface{}, globals interface{}, values ur continue } + constValue := parseConstTag(fieldType) + if constValue != nil { + values.Add(qpTag.ParamName, *constValue) + continue + } + + defaultValue := parseDefaultTag(fieldType) + if globals != nil { var globalFound bool fieldType, valType, globalFound = populateFromGlobals(fieldType, valType, queryParamTagKey, globals) @@ -91,14 +101,14 @@ func populateQueryParams(queryParams interface{}, globals interface{}, values ur } } case "form": - vals := populateFormParams(qpTag, fieldType.Type, valType, ",") + vals := populateFormParams(qpTag, fieldType.Type, valType, ",", defaultValue, allowEmptyValue) for k, v := range vals { for _, vv := range v { values.Add(k, vv) } } case "pipeDelimited": - vals := populateFormParams(qpTag, fieldType.Type, valType, "|") + vals := populateFormParams(qpTag, fieldType.Type, valType, "|", defaultValue, allowEmptyValue) for k, v := range vals { for _, vv := range v { values.Add(k, vv) @@ -149,6 +159,16 @@ func populateDeepObjectParams(tag *paramTag, objType reflect.Type, objValue refl switch objValue.Kind() { case reflect.Map: + // check if optionalnullable.OptionalNullable[T] + if nullableValue, ok := optionalnullable.AsOptionalNullable(objValue); ok { + // Handle optionalnullable.OptionalNullable[T] using GetUntyped method + if value, isSet := nullableValue.GetUntyped(); isSet && value != nil { + values.Add(tag.ParamName, valToString(value)) + } + // If not set or explicitly null, skip adding to values + return values + } + populateDeepObjectParamsMap(values, tag.ParamName, objValue) case reflect.Struct: populateDeepObjectParamsStruct(values, tag.ParamName, objValue) @@ -227,7 +247,7 @@ func populateDeepObjectParamsStruct(qsValues url.Values, priorScope string, stru populateDeepObjectParamsMap(qsValues, scope, fieldValue) case reflect.Struct: switch fieldValue.Type() { - case reflect.TypeOf(big.Int{}), reflect.TypeOf(decimal.Big{}), reflect.TypeOf(time.Time{}), reflect.TypeOf(types.Date{}): + case reflect.TypeOf(big.Int{}), reflect.TypeOf(time.Time{}), reflect.TypeOf(types.Date{}): qsValues.Add(scope, valToString(fieldValue.Interface())) continue @@ -240,8 +260,8 @@ func populateDeepObjectParamsStruct(qsValues url.Values, priorScope string, stru } } -func populateFormParams(tag *paramTag, objType reflect.Type, objValue reflect.Value, delimiter string) url.Values { - return populateForm(tag.ParamName, tag.Explode, objType, objValue, delimiter, func(fieldType reflect.StructField) string { +func populateFormParams(tag *paramTag, objType reflect.Type, objValue reflect.Value, delimiter string, defaultValue *string, allowEmptyValue map[string]struct{}) url.Values { + return populateForm(tag.ParamName, tag.Explode, objType, objValue, delimiter, defaultValue, allowEmptyValue, func(fieldType reflect.StructField) string { qpTag := parseQueryParamTag(fieldType) if qpTag == nil { return "" diff --git a/internal/sdk/internal/utils/requestbody.go b/internal/sdk/internal/utils/requestbody.go index 78479c6..1601022 100644 --- a/internal/sdk/internal/utils/requestbody.go +++ b/internal/sdk/internal/utils/requestbody.go @@ -7,10 +7,15 @@ import ( "context" "fmt" "io" + "mime" "mime/multipart" + "net/textproto" "net/url" + "path/filepath" "reflect" "regexp" + + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/optionalnullable" ) const ( @@ -166,9 +171,21 @@ func encodeMultipartFormData(w io.Writer, data interface{}) (string, error) { tag := parseMultipartFormTag(field) if tag.File { - if err := encodeMultipartFormDataFile(writer, tag.Name, fieldType, valType); err != nil { - writer.Close() - return "", err + switch fieldType.Kind() { + case reflect.Slice, reflect.Array: + for i := 0; i < valType.Len(); i++ { + arrayVal := valType.Index(i) + + if err := encodeMultipartFormDataFile(writer, tag.Name, arrayVal.Type(), arrayVal); err != nil { + writer.Close() + return "", err + } + } + default: + if err := encodeMultipartFormDataFile(writer, tag.Name, fieldType, valType); err != nil { + writer.Close() + return "", err + } } } else if tag.JSON { jw, err := writer.CreateFormField(tag.Name) @@ -190,7 +207,7 @@ func encodeMultipartFormData(w io.Writer, data interface{}) (string, error) { case reflect.Slice, reflect.Array: values := parseDelimitedArray(true, valType, ",") for _, v := range values { - if err := writer.WriteField(tag.Name+"[]", v); err != nil { + if err := writer.WriteField(tag.Name, v); err != nil { writer.Close() return "", err } @@ -243,7 +260,18 @@ func encodeMultipartFormDataFile(w *multipart.Writer, fieldName string, fieldTyp return fmt.Errorf("invalid multipart/form-data file") } - fw, err := w.CreateFormFile(fieldName, fileName) + // Detect content type based on file extension + contentType := mime.TypeByExtension(filepath.Ext(fileName)) + if contentType == "" { + contentType = "application/octet-stream" + } + + // Create multipart header with proper content type + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`, fieldName, fileName)) + h.Set("Content-Type", contentType) + + fw, err := w.CreatePart(h) if err != nil { return err } @@ -251,6 +279,11 @@ func encodeMultipartFormDataFile(w *multipart.Writer, fieldName string, fieldTyp return err } + // Reset seek position to 0 if the reader supports seeking + if seeker, ok := reader.(io.Seeker); ok { + _, _ = seeker.Seek(0, io.SeekStart) + } + return nil } @@ -292,7 +325,7 @@ func encodeFormData(fieldName string, w io.Writer, data interface{}) error { switch tag.Style { // TODO: support other styles case "form": - values := populateForm(tag.Name, tag.Explode, fieldType, valType, ",", func(sf reflect.StructField) string { + values := populateForm(tag.Name, tag.Explode, fieldType, valType, ",", nil, nil, func(sf reflect.StructField) string { tag := parseFormTag(field) if tag == nil { return "" @@ -309,6 +342,17 @@ func encodeFormData(fieldName string, w io.Writer, data interface{}) error { } } case reflect.Map: + // check if optionalnullable.OptionalNullable[T] + if nullableValue, ok := optionalnullable.AsOptionalNullable(requestValType); ok { + // Handle optionalnullable.OptionalNullable[T] using GetUntyped method + if value, isSet := nullableValue.GetUntyped(); isSet && value != nil { + dataValues.Set(fieldName, valToString(value)) + } + // If not set or explicitly null, skip adding to form + break + } + + // Handle regular map for _, k := range requestValType.MapKeys() { v := requestValType.MapIndex(k) dataValues.Set(fmt.Sprintf("%v", k.Interface()), valToString(v.Interface())) diff --git a/internal/sdk/internal/utils/retries.go b/internal/sdk/internal/utils/retries.go index 3f35f90..2723b36 100644 --- a/internal/sdk/internal/utils/retries.go +++ b/internal/sdk/internal/utils/retries.go @@ -7,10 +7,12 @@ import ( "errors" "fmt" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/retry" + "io" "math" "math/rand" "net/http" "net/url" + "slices" "strconv" "strings" "time" @@ -27,6 +29,17 @@ type Retries struct { StatusCodes []string } +var ( + // IETF RFC 7231 4.2 safe and idempotent HTTP methods for connection retries + idempotentHTTPMethods = []string{ + http.MethodDelete, + http.MethodGet, + http.MethodHead, + http.MethodOptions, + http.MethodPut, + } +) + func Retry(ctx context.Context, r Retries, operation func() (*http.Response, error)) (*http.Response, error) { switch r.Config.Strategy { case "backoff": @@ -49,11 +62,48 @@ func Retry(ctx context.Context, r Retries, operation func() (*http.Response, err res, err := operation() if err != nil { + if !r.Config.RetryConnectionErrors { + return retry.Permanent(err) + } + + var httpMethod string + + // Use http.Request method if available + if res != nil && res.Request != nil { + httpMethod = res.Request.Method + } + + isIdempotentHTTPMethod := slices.Contains(idempotentHTTPMethods, httpMethod) urlError := new(url.Error) + if errors.As(err, &urlError) { - if (urlError.Temporary() || urlError.Timeout()) && r.Config.RetryConnectionErrors { + if urlError.Temporary() || urlError.Timeout() { return err } + + // In certain error cases, the http.Request may not have + // been populated, so use url.Error.Op which only has its + // first character capitalized from the original request + // HTTP method. + if httpMethod == "" { + httpMethod = strings.ToUpper(urlError.Op) + } + + isIdempotentHTTPMethod = slices.Contains(idempotentHTTPMethods, httpMethod) + + // Connection closed + if errors.Is(urlError.Err, io.EOF) && isIdempotentHTTPMethod { + return err + } + } + + // syscall detection is not available on every platform, so + // fallback to best effort string detection. + isBrokenPipeError := strings.Contains(err.Error(), "broken pipe") + isConnectionResetError := strings.Contains(err.Error(), "connection reset") + + if (isBrokenPipeError || isConnectionResetError) && isIdempotentHTTPMethod { + return err } return retry.Permanent(err) diff --git a/internal/sdk/internal/utils/union.go b/internal/sdk/internal/utils/union.go new file mode 100644 index 0000000..e8bd72c --- /dev/null +++ b/internal/sdk/internal/utils/union.go @@ -0,0 +1,289 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package utils + +import ( + "encoding/json" + "math/big" + "reflect" + "strings" + "time" + + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/types" +) + +// UnionCandidate represents a candidate type during union deserialization +type UnionCandidate struct { + Matched int // Count of matched fields (includes inexact) + Inexact int // Count of fields with unknown/unrecognized enum values + Unmatched int // Count of struct fields not found in raw JSON + AdditionalProperties int // Count of fields captured by additionalProperties + Type any // The union type enum value + Value any // The unmarshaled value +} + +// PickBestUnionCandidate selects the best union type candidate according to `betterCandidate` +func PickBestUnionCandidate(candidates []UnionCandidate, rawJSON []byte) *UnionCandidate { + if len(candidates) == 0 { + return nil + } + + if len(candidates) == 1 { + return &candidates[0] + } + + var raw any + _ = json.Unmarshal(rawJSON, &raw) + + var best *UnionCandidate + for i := range candidates { + countFields(&candidates[i], raw) + best = betterCandidate(best, &candidates[i]) + } + return best +} + +// betterCandidate returns the better of two candidates based on: +// 1. Matched count (higher is better) +// 2. Inexact count (lower is better) +// 3. Unmatched count (lower is better - fewer zero defaulted values) +// 4. AdditionalProperties count (higher is better - captures more extra fields) +// Returns a if tied (preserving spec order). +func betterCandidate(a, b *UnionCandidate) *UnionCandidate { + if a == nil { + return b + } + if b == nil { + return a + } + if a.Matched != b.Matched { + if a.Matched > b.Matched { + return a + } + return b + } + if a.Inexact != b.Inexact { + if a.Inexact > b.Inexact { + return b + } + return a + } + if a.Unmatched != b.Unmatched { + if a.Unmatched > b.Unmatched { + return b + } + return a + } + if a.AdditionalProperties != b.AdditionalProperties { + if a.AdditionalProperties > b.AdditionalProperties { + return a + } + return b + } + return a +} + +// countFields populates UnionCandidate.Matched, UnionCandidate.Inexact, and UnionCandidate.Unmatched fields +func countFields(candidate *UnionCandidate, raw any) { + typ := reflect.TypeOf(candidate.Value) + val := reflect.ValueOf(candidate.Value) + countFieldsRecursive(candidate, typ, val, raw) +} + +func countFieldsRecursive(candidate *UnionCandidate, typ reflect.Type, val reflect.Value, raw any) { + kind := typ.Kind() + + // Handle interface{}/any types - can hold any JSON value + if kind == reflect.Interface { + candidate.Matched++ + return + } + + if typ.Kind() == reflect.Ptr { + if raw == nil { + // Handle null JSON value match + candidate.Matched++ + return + } + typ, val = dereferencePointers(typ, val) + kind = typ.Kind() + } + + // Handle primitives + if kind == reflect.String || + kind == reflect.Bool || + kind == reflect.Int || kind == reflect.Int8 || kind == reflect.Int16 || kind == reflect.Int32 || kind == reflect.Int64 || + kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 || kind == reflect.Uint64 || + kind == reflect.Float32 || kind == reflect.Float64 || + typ == reflect.TypeOf(time.Time{}) || + typ == reflect.TypeOf(big.Int{}) || + typ == reflect.TypeOf(types.Date{}) || + typ == reflect.TypeOf([]byte{}) { + candidate.Matched++ + if !isExact(val) || raw == nil { + candidate.Inexact++ + } + return + } + + // Handle unions + if isUnion, activeVariant, variantVal := findActiveUnionVariant(typ, val); isUnion { + if activeVariant != nil && !variantVal.IsNil() { + countFieldsRecursive(candidate, activeVariant.Type.Elem(), variantVal.Elem(), raw) + } + return + } + + // Handle regular structs + if kind == reflect.Struct { + rawObj, ok := raw.(map[string]any) + if !ok { + return + } + + for i := 0; i < typ.NumField(); i++ { + field := typ.Field(i) + fieldVal := val.Field(i) + + if field.Tag.Get("additionalProperties") == "true" { + if field.Type.Kind() == reflect.Map && !fieldVal.IsNil() { + candidate.AdditionalProperties += fieldVal.Len() + } + continue + } + + jsonName, ok := jsonFieldName(field) + if !ok { + continue + } + + rawField, exists := rawObj[jsonName] + if !exists { + candidate.Unmatched++ + continue + } + + countFieldsRecursive(candidate, field.Type, fieldVal, rawField) + } + return + } + + // Handle slices and arrays + if kind == reflect.Slice || kind == reflect.Array { + if val.IsNil() || val.Len() == 0 { + return + } + + rawArr, ok := raw.([]any) + if !ok { + return + } + + // Count each array/slice element + for i := 0; i < val.Len() && i < len(rawArr); i++ { + itemVal := val.Index(i) + countFieldsRecursive(candidate, itemVal.Type(), itemVal, rawArr[i]) + } + return + } + + // Handle maps + if kind == reflect.Map { + if val.IsNil() || val.Len() == 0 { + return + } + + rawObj, ok := raw.(map[string]any) + if !ok { + return + } + + for _, key := range val.MapKeys() { + keyStr := key.String() + rawVal, exists := rawObj[keyStr] + if exists { + mapVal := val.MapIndex(key) + countFieldsRecursive(candidate, mapVal.Type(), mapVal, rawVal) + } + } + return + } + // Anything else + candidate.Matched++ + return +} + +// jsonFieldName returns the JSON field name for a struct field. +// Returns ("", false) if the field should be skipped (json:"-"). +func jsonFieldName(field reflect.StructField) (string, bool) { + jsonTag := field.Tag.Get("json") + if jsonTag == "-" { + return "", false + } + if jsonTag != "" { + parts := strings.Split(jsonTag, ",") + if parts[0] != "" { + return parts[0], true + } + } + return field.Name, true +} + +// findActiveUnionVariant detects if a struct is a union type and returns the active variant. +// A union type is detected by having fields with the `union:"member"` tag. +// Returns (false, nil, invalid) if not a union type. +// Returns (true, nil, invalid) if union type but no active variant found (all nil). +// Returns (true, field, value) if union type with an active variant. +func findActiveUnionVariant(typ reflect.Type, val reflect.Value) (bool, *reflect.StructField, reflect.Value) { + if typ.Kind() != reflect.Struct { + return false, nil, reflect.Value{} + } + + var activeVariant *reflect.StructField + var activeValue reflect.Value + isUnion := false + + for i := 0; i < typ.NumField(); i++ { + field := typ.Field(i) + + // Look for fields tagged as union members + if field.Tag.Get("union") != "member" { + continue + } + + isUnion = true + + // All union variants are pointers - only set active if non-nil + fieldVal := val.Field(i) + if !fieldVal.IsNil() { + activeVariant = &field + activeValue = fieldVal + } + } + + return isUnion, activeVariant, activeValue +} + +func isExact(val reflect.Value) bool { + if !val.IsValid() { + return true + } + + // If not addressable, make an addressable copy + if !val.CanAddr() && val.CanInterface() { + ptr := reflect.New(val.Type()) + ptr.Elem().Set(val) + val = ptr.Elem() + } + + if val.CanInterface() && val.CanAddr() { + ptrVal := val.Addr() + if method := ptrVal.MethodByName("IsExact"); method.IsValid() { + results := method.Call(nil) + if len(results) == 1 && results[0].Kind() == reflect.Bool { + return results[0].Bool() + } + } + } + return true +} diff --git a/internal/sdk/internal/utils/union_test.go b/internal/sdk/internal/utils/union_test.go new file mode 100644 index 0000000..f66814c --- /dev/null +++ b/internal/sdk/internal/utils/union_test.go @@ -0,0 +1,587 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package utils + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// makeCandidates unmarshals payload into each type and returns candidates +func makeCandidates(t *testing.T, payload string, types ...any) []UnionCandidate { + t.Helper() + candidates := make([]UnionCandidate, len(types)) + for i, typ := range types { + val := reflect.New(reflect.TypeOf(typ)).Interface() + require.NoError(t, UnmarshalJSON([]byte(payload), val, "", false, nil)) + candidates[i] = UnionCandidate{Type: typ, Value: reflect.ValueOf(val).Elem().Interface()} + } + return candidates +} + +func TestPickBestUnionCandidate_SelectsTypeWithMoreMatchedFields(t *testing.T) { + type A struct { + Foo string `json:"foo"` + } + type B struct { + Foo string `json:"foo"` + Bar string `json:"bar"` + } + + payload := `{"foo": "", "bar": ""}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_EmptyCandidates(t *testing.T) { + result := PickBestUnionCandidate([]UnionCandidate{}, []byte(`{"foo": "test"}`)) + assert.Nil(t, result) +} + +func TestPickBestUnionCandidate_PrefersFewerUnmatchedFields(t *testing.T) { + type A struct { + Foo string `json:"foo"` + Bar string `json:"bar"` // not in payload + } + type B struct { + Foo string `json:"foo"` + } + + payload := `{"foo": "test"}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) // fewer unmatched fields +} + +func TestPickBestUnionCandidate_NestedStructs(t *testing.T) { + type InnerA struct { + Value string `json:"value"` + } + type InnerB struct { + Value string `json:"value"` + Extra string `json:"extra"` + } + type A struct { + Nested InnerA `json:"nested"` + } + type B struct { + Nested InnerB `json:"nested"` + } + + payload := `{"nested": {"value": "test", "extra": "data"}}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_ArrayFields(t *testing.T) { + type ItemA struct { + Name string `json:"name"` + } + type ItemB struct { + Name string `json:"name"` + Value string `json:"value"` + } + type A = []ItemA + type B = []ItemB + + payload := `[{"name": "a", "value": "1"}, {"name": "b", "value": "2"}]` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_PreservesOrderOnTie(t *testing.T) { + type A struct { + Foo string `json:"foo"` + } + type B struct { + Foo string `json:"foo"` + } + + payload := `{"foo": "test"}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, A{}, result.Type) // first wins on tie +} + +func TestPickBestUnionCandidate_OptionalPointerFields(t *testing.T) { + type A struct { + Foo *string `json:"foo"` + } + type B struct { + Foo *string `json:"foo"` + Bar *string `json:"bar"` + } + + payload := `{"foo": "test", "bar": "value"}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_OptionalPointerStructs(t *testing.T) { + type InnerA struct { + Name string `json:"name"` + } + type InnerB struct { + Name string `json:"name"` + Value string `json:"value"` + } + type A struct { + Nested *InnerA `json:"nested"` + } + type B struct { + Nested *InnerB `json:"nested"` + } + + payload := `{"nested": {"name": "test", "value": "data"}}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_NullPointerField(t *testing.T) { + type A struct { + Bar *string `json:"bar"` + } + type B struct { + Foo *string `json:"foo"` + } + + payload := `{"foo": null}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_NullNestedPointerField(t *testing.T) { + type InnerA struct { + Bar *string `json:"bar"` + } + type InnerB struct { + Bar *bool `json:"bar"` + } + type A struct { + Foo InnerA `json:"foo"` + } + type B struct { + Foo InnerB `json:"foo"` + } + + payload := `{"foo": {"bar": null}}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, A{}, result.Type) // first wins on tie +} + +func TestPickBestUnionCandidate_NullNonPointerField(t *testing.T) { + type A struct { + Foo string `json:"foo"` + } + type B struct { + Foo string `json:"foo"` + Bar string `json:"bar"` + } + + payload := `{"foo": "", "bar": null}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_NullNestedFieldDifferentStructs(t *testing.T) { + type InnerA struct { + Bar string `json:"bar"` + } + type InnerB struct { + Baz *string `json:"baz"` + } + type A struct { + Foo InnerA `json:"foo"` + } + type B struct { + Foo InnerB `json:"foo"` + } + + payload := `{"foo": {"baz": null}}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_NullNestedFieldBothPresent(t *testing.T) { + type InnerA struct { + Bar *string `json:"bar"` + } + type InnerB struct { + Baz *string `json:"baz"` + } + type A struct { + Foo InnerA `json:"foo"` + } + type B struct { + Foo InnerB `json:"foo"` + } + + payload := `{"foo": {"bar": null, "baz": null}}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, A{}, result.Type) // first wins on tie +} + +// EnumA represents an enum with values 1 or 2 +type EnumA int + +func (e *EnumA) IsExact() bool { + return *e == 1 || *e == 2 +} + +func (e *EnumA) UnmarshalJSON(data []byte) error { + var v int + if err := json.Unmarshal(data, &v); err != nil { + return err + } + *e = EnumA(v) + return nil +} + +// EnumB represents an enum with values 3 or 4 +type EnumB int + +func (e *EnumB) IsExact() bool { + return *e == 3 || *e == 4 +} + +func (e *EnumB) UnmarshalJSON(data []byte) error { + var v int + if err := json.Unmarshal(data, &v); err != nil { + return err + } + *e = EnumB(v) + return nil +} + +func TestPickBestUnionCandidate_EnumDiscrimination(t *testing.T) { + type A struct { + Val EnumA `json:"a"` + } + type B struct { + Val EnumB `json:"a"` + } + + payload := `{"a": 4}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_ThreeWayFieldDiscrimination(t *testing.T) { + type A struct { + FieldA string `json:"a"` + FieldB string `json:"b"` + } + type B struct { + FieldA string `json:"a"` + FieldC string `json:"c"` + } + type C struct { + FieldB string `json:"b"` + FieldC string `json:"c"` + } + + payload := `{"b": "", "c": ""}` + candidates := makeCandidates(t, payload, A{}, B{}, C{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, C{}, result.Type) +} + +func TestPickBestUnionCandidate_ConstFieldDiscrimination(t *testing.T) { + type A struct { + ConstA string `json:"a" const:"x"` + ConstB string `json:"b" const:"1"` + } + type B struct { + ConstA string `json:"a" const:"x"` + ConstC string `json:"c" const:"1"` + } + type C struct { + ConstB string `json:"b" const:"1"` + ConstC string `json:"c" const:"1"` + } + + payload := `{"b": "1", "c": "1"}` + candidates := makeCandidates(t, payload, A{}, B{}, C{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, C{}, result.Type) +} + +func TestPickBestUnionCandidate_NullPayload(t *testing.T) { + type A struct { + Foo string `json:"foo"` + } + type B *string // nullable type + + payload := `null` + + candidates := makeCandidates(t, payload, A{}, B(nil)) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + _, isB := result.Type.(B) + assert.True(t, isB, "expected B (nullable type) to win for null payload") +} + +func TestPickBestUnionCandidate_PrimitiveStringTypes(t *testing.T) { + // When both types are strings, first wins on tie + type A = string + type B = string + + payload := `"asdf"` + + candidates := makeCandidates(t, payload, A(""), B("")) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + _, isA := result.Type.(A) + assert.True(t, isA, "expected A (first type) to win on tie") +} + +func TestPickBestUnionCandidate_NullPointerPrimitives(t *testing.T) { + // A: *string, B: *float64 + // payload: null + // Both can be null, first wins + type A = *string + type B = *float64 + + payload := `null` + + candidates := makeCandidates(t, payload, A(nil), B(nil)) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + _, isA := result.Type.(A) + assert.True(t, isA, "expected A (*string) to win for null payload (first wins on tie)") +} + +func TestPickBestUnionCandidate_NullPointersMatchOverMissingFields(t *testing.T) { + // A: { a: string } + // B: { b: *string, c: *string } + // payload: { "b": null, "c": null } + // B wins because it has 2 matched fields, A has 0 + type A struct { + A string `json:"a"` + } + type B struct { + B *string `json:"b"` + C *string `json:"c"` + } + + payload := `{"b": null, "c": null}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_MapOfStructs(t *testing.T) { + // A: map[string]{ a: string } + // B: map[string]{ b: string } + // payload: { "x": null, "y": null, "z": { "b": "b" } } + // B wins because it has a matched field in the nested struct + type InnerA struct { + A string `json:"a"` + } + type InnerB struct { + B string `json:"b"` + } + type A = map[string]*InnerA + type B = map[string]*InnerB + + payload := `{"x": null, "y": null, "z": {"b": "b"}}` + + candidates := makeCandidates(t, payload, A(nil), B(nil)) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + _, isB := result.Type.(B) + assert.True(t, isB, "expected B (map with matching struct field) to win") +} + +func TestPickBestUnionCandidate_NullPointerStructVsString(t *testing.T) { + // A: *{foo: string}, B: *string + // payload: null + type Inner struct { + Foo string `json:"foo"` + } + type A = *Inner + type B = *string + + payload := `null` + + candidates := makeCandidates(t, payload, A(nil), B(nil)) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + _, isA := result.Type.(A) + assert.True(t, isA, "expected A (*struct) to win for null payload (first wins on tie)") +} + +func TestPickBestUnionCandidate_MapWithNestedStructsVsSimpleField(t *testing.T) { + // A: { a: string } + // B: { b: map[string]{ id: string, name: string } } + // payload: { "a": "", "b": { "foo": { "id": "", "name": "" } } } + // B should win because it has more matched fields (id, name in nested struct) + type Inner struct { + ID string `json:"id"` + Name string `json:"name"` + } + type A struct { + A string `json:"a"` + } + type B struct { + B map[string]Inner `json:"b"` + } + + payload := `{"a": "", "b": {"foo": {"id": "", "name": ""}}}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_AdditionalPropertiesWins(t *testing.T) { + type A struct { + A string `json:"a"` + } + type B struct { + B string `json:"b"` + AdditionalProperties map[string]string `additionalProperties:"true"` + } + + payload := `{"a": "", "b": "", "c": ""}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_StructVsMapOfStrings(t *testing.T) { + // A: map[string]string + // B: { id: string } + // payload: { "id": "", "foo": "" } + // B should win because struct fields are more specific than map + type A = map[string]string + type B struct { + ID string `json:"id"` + } + + payload := `{"id": "", "foo": ""}` + + candidates := makeCandidates(t, payload, A(nil), B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, A{}, result.Type) +} + +func TestPickBestUnionCandidate_AdditionalPropertiesVsExactField(t *testing.T) { + // A: { id: *string, additionalProperties: true } + // B: { foo: string } + // payload: { "foo": "" } + // B should win because it has an exact field match, while A only matches via additionalProperties + type A struct { + ID *string `json:"id"` + AdditionalProperties map[string]string `additionalProperties:"true"` + } + type B struct { + Foo string `json:"foo"` + } + + payload := `{"foo": ""}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_ArrayOfNullableStructs(t *testing.T) { + // A: Array<{ foo: *string } | null> + // B: Array<{ bar: *string } | null> + // payload: [null, null, { "bar": "" }] + // B should win because it has a matching field in the non-null element + type ItemA struct { + Foo *string `json:"foo"` + } + type ItemB struct { + Bar *string `json:"bar"` + } + type A = []*ItemA + type B = []*ItemB + + payload := `[null, null, {"bar": ""}]` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} + +func TestPickBestUnionCandidate_AnyFieldType(t *testing.T) { + // A: { a: string } + // B: { b: any } + // payload: { "b": "asdf" } + // B should win because it has a matching field + type A struct { + A string `json:"a"` + } + type B struct { + B any `json:"b"` + } + + payload := `{"b": "asdf"}` + candidates := makeCandidates(t, payload, A{}, B{}) + result := PickBestUnionCandidate(candidates, []byte(payload)) + + require.NotNil(t, result) + assert.IsType(t, B{}, result.Type) +} diff --git a/internal/sdk/internal/utils/utils.go b/internal/sdk/internal/utils/utils.go index 031a71a..0415b53 100644 --- a/internal/sdk/internal/utils/utils.go +++ b/internal/sdk/internal/utils/utils.go @@ -14,8 +14,6 @@ import ( "strconv" "strings" "time" - - "github.com/ericlagergren/decimal" ) const ( @@ -40,8 +38,8 @@ func UnmarshalJsonFromResponseBody(body io.Reader, out interface{}, tag string) if err != nil { return fmt.Errorf("error reading response body: %w", err) } - if err := UnmarshalJSON(data, out, reflect.StructTag(tag), true, false); err != nil { - return fmt.Errorf("error unmarshalling json response body: %w", err) + if err := UnmarshalJSON(data, out, reflect.StructTag(tag), true, nil); err != nil { + return fmt.Errorf("error unmarshaling json response body: %w", err) } return nil @@ -96,6 +94,26 @@ func AsSecuritySource(security interface{}) func(context.Context) (interface{}, } } +func parseConstTag(field reflect.StructField) *string { + value := field.Tag.Get("const") + + if value == "" { + return nil + } + + return &value +} + +func parseDefaultTag(field reflect.StructField) *string { + value := field.Tag.Get("default") + + if value == "" { + return nil + } + + return &value +} + func parseStructTag(tagKey string, field reflect.StructField) map[string]string { tag := field.Tag.Get(tagKey) if tag == "" { @@ -163,8 +181,6 @@ func valToString(val interface{}) string { return v.Format(time.RFC3339Nano) case big.Int: return v.String() - case decimal.Big: - return v.String() default: return fmt.Sprintf("%v", v) } @@ -225,6 +241,21 @@ func isNil(typ reflect.Type, val reflect.Value) bool { return false } +func isEmptyContainer(typ reflect.Type, val reflect.Value) bool { + if isNil(typ, val) { + return true + } + + switch typ.Kind() { + case reflect.Slice, reflect.Array: + return val.Len() == 0 + case reflect.Map: + return val.Len() == 0 + default: + return false + } +} + func contains(arr []string, str string) bool { for _, a := range arr { if a == str { diff --git a/internal/sdk/models/operations/addconsumer.go b/internal/sdk/models/operations/addconsumer.go index 6a40e83..ddd873f 100644 --- a/internal/sdk/models/operations/addconsumer.go +++ b/internal/sdk/models/operations/addconsumer.go @@ -12,29 +12,28 @@ type AddConsumerRequest struct { AddConsumerReq shared.AddConsumerReq `request:"mediaType=application/json"` // Type of application that uses the design Application string `pathParam:"style=simple,explode=false,name=application"` - // Id of the design - DesignID string `pathParam:"style=simple,explode=false,name=designId"` + DesignID string `pathParam:"style=simple,explode=false,name=designId"` } -func (o *AddConsumerRequest) GetAddConsumerReq() shared.AddConsumerReq { - if o == nil { +func (a *AddConsumerRequest) GetAddConsumerReq() shared.AddConsumerReq { + if a == nil { return shared.AddConsumerReq{} } - return o.AddConsumerReq + return a.AddConsumerReq } -func (o *AddConsumerRequest) GetApplication() string { - if o == nil { +func (a *AddConsumerRequest) GetApplication() string { + if a == nil { return "" } - return o.Application + return a.Application } -func (o *AddConsumerRequest) GetDesignID() string { - if o == nil { +func (a *AddConsumerRequest) GetDesignID() string { + if a == nil { return "" } - return o.DesignID + return a.DesignID } type AddConsumerResponse struct { @@ -48,30 +47,30 @@ type AddConsumerResponse struct { RawResponse *http.Response } -func (o *AddConsumerResponse) GetContentType() string { - if o == nil { +func (a *AddConsumerResponse) GetContentType() string { + if a == nil { return "" } - return o.ContentType + return a.ContentType } -func (o *AddConsumerResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (a *AddConsumerResponse) GetErrorResp() *shared.ErrorResp { + if a == nil { return nil } - return o.ErrorResp + return a.ErrorResp } -func (o *AddConsumerResponse) GetStatusCode() int { - if o == nil { +func (a *AddConsumerResponse) GetStatusCode() int { + if a == nil { return 0 } - return o.StatusCode + return a.StatusCode } -func (o *AddConsumerResponse) GetRawResponse() *http.Response { - if o == nil { +func (a *AddConsumerResponse) GetRawResponse() *http.Response { + if a == nil { return nil } - return o.RawResponse + return a.RawResponse } diff --git a/internal/sdk/models/operations/adddesign.go b/internal/sdk/models/operations/adddesign.go index d9f8b32..0eb9e3c 100644 --- a/internal/sdk/models/operations/adddesign.go +++ b/internal/sdk/models/operations/adddesign.go @@ -20,37 +20,37 @@ type AddDesignResponse struct { RawResponse *http.Response } -func (o *AddDesignResponse) GetAddDesignRes() *shared.AddDesignRes { - if o == nil { +func (a *AddDesignResponse) GetAddDesignRes() *shared.AddDesignRes { + if a == nil { return nil } - return o.AddDesignRes + return a.AddDesignRes } -func (o *AddDesignResponse) GetContentType() string { - if o == nil { +func (a *AddDesignResponse) GetContentType() string { + if a == nil { return "" } - return o.ContentType + return a.ContentType } -func (o *AddDesignResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (a *AddDesignResponse) GetErrorResp() *shared.ErrorResp { + if a == nil { return nil } - return o.ErrorResp + return a.ErrorResp } -func (o *AddDesignResponse) GetStatusCode() int { - if o == nil { +func (a *AddDesignResponse) GetStatusCode() int { + if a == nil { return 0 } - return o.StatusCode + return a.StatusCode } -func (o *AddDesignResponse) GetRawResponse() *http.Response { - if o == nil { +func (a *AddDesignResponse) GetRawResponse() *http.Response { + if a == nil { return nil } - return o.RawResponse + return a.RawResponse } diff --git a/internal/sdk/models/operations/deletedesign.go b/internal/sdk/models/operations/deletedesign.go index 61cf58f..2b2b364 100644 --- a/internal/sdk/models/operations/deletedesign.go +++ b/internal/sdk/models/operations/deletedesign.go @@ -8,15 +8,14 @@ import ( ) type DeleteDesignRequest struct { - // Id of the design DesignID string `pathParam:"style=simple,explode=false,name=designId"` } -func (o *DeleteDesignRequest) GetDesignID() string { - if o == nil { +func (d *DeleteDesignRequest) GetDesignID() string { + if d == nil { return "" } - return o.DesignID + return d.DesignID } type DeleteDesignResponse struct { @@ -30,30 +29,30 @@ type DeleteDesignResponse struct { RawResponse *http.Response } -func (o *DeleteDesignResponse) GetContentType() string { - if o == nil { +func (d *DeleteDesignResponse) GetContentType() string { + if d == nil { return "" } - return o.ContentType + return d.ContentType } -func (o *DeleteDesignResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (d *DeleteDesignResponse) GetErrorResp() *shared.ErrorResp { + if d == nil { return nil } - return o.ErrorResp + return d.ErrorResp } -func (o *DeleteDesignResponse) GetStatusCode() int { - if o == nil { +func (d *DeleteDesignResponse) GetStatusCode() int { + if d == nil { return 0 } - return o.StatusCode + return d.StatusCode } -func (o *DeleteDesignResponse) GetRawResponse() *http.Response { - if o == nil { +func (d *DeleteDesignResponse) GetRawResponse() *http.Response { + if d == nil { return nil } - return o.RawResponse + return d.RawResponse } diff --git a/internal/sdk/models/operations/getalldesigns.go b/internal/sdk/models/operations/getalldesigns.go index 5aba95e..a01d93a 100644 --- a/internal/sdk/models/operations/getalldesigns.go +++ b/internal/sdk/models/operations/getalldesigns.go @@ -12,45 +12,45 @@ type GetAllDesignsResponse struct { ContentType string // Other errors ErrorResp *shared.ErrorResp + // Success - designs loaded with success. Empty array if org has no designs. + GetAllDesignsRes *shared.GetAllDesignsRes // HTTP response status code for this operation StatusCode int // Raw HTTP response; suitable for custom response parsing RawResponse *http.Response - // Success - designs loaded with success. Empty array if org has no designs. - Classes []shared.GetAllDesignsRes } -func (o *GetAllDesignsResponse) GetContentType() string { - if o == nil { +func (g *GetAllDesignsResponse) GetContentType() string { + if g == nil { return "" } - return o.ContentType + return g.ContentType } -func (o *GetAllDesignsResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (g *GetAllDesignsResponse) GetErrorResp() *shared.ErrorResp { + if g == nil { return nil } - return o.ErrorResp + return g.ErrorResp } -func (o *GetAllDesignsResponse) GetStatusCode() int { - if o == nil { - return 0 +func (g *GetAllDesignsResponse) GetGetAllDesignsRes() *shared.GetAllDesignsRes { + if g == nil { + return nil } - return o.StatusCode + return g.GetAllDesignsRes } -func (o *GetAllDesignsResponse) GetRawResponse() *http.Response { - if o == nil { - return nil +func (g *GetAllDesignsResponse) GetStatusCode() int { + if g == nil { + return 0 } - return o.RawResponse + return g.StatusCode } -func (o *GetAllDesignsResponse) GetClasses() []shared.GetAllDesignsRes { - if o == nil { +func (g *GetAllDesignsResponse) GetRawResponse() *http.Response { + if g == nil { return nil } - return o.Classes + return g.RawResponse } diff --git a/internal/sdk/models/operations/getbrands.go b/internal/sdk/models/operations/getbrands.go index 666f9a0..b57e7bc 100644 --- a/internal/sdk/models/operations/getbrands.go +++ b/internal/sdk/models/operations/getbrands.go @@ -20,37 +20,37 @@ type GetBrandsResponse struct { Classes []shared.GetBrandsRes } -func (o *GetBrandsResponse) GetContentType() string { - if o == nil { +func (g *GetBrandsResponse) GetContentType() string { + if g == nil { return "" } - return o.ContentType + return g.ContentType } -func (o *GetBrandsResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (g *GetBrandsResponse) GetErrorResp() *shared.ErrorResp { + if g == nil { return nil } - return o.ErrorResp + return g.ErrorResp } -func (o *GetBrandsResponse) GetStatusCode() int { - if o == nil { +func (g *GetBrandsResponse) GetStatusCode() int { + if g == nil { return 0 } - return o.StatusCode + return g.StatusCode } -func (o *GetBrandsResponse) GetRawResponse() *http.Response { - if o == nil { +func (g *GetBrandsResponse) GetRawResponse() *http.Response { + if g == nil { return nil } - return o.RawResponse + return g.RawResponse } -func (o *GetBrandsResponse) GetClasses() []shared.GetBrandsRes { - if o == nil { +func (g *GetBrandsResponse) GetClasses() []shared.GetBrandsRes { + if g == nil { return nil } - return o.Classes + return g.Classes } diff --git a/internal/sdk/models/operations/getconsumerdesign.go b/internal/sdk/models/operations/getconsumerdesign.go index 82c224a..342bf64 100644 --- a/internal/sdk/models/operations/getconsumerdesign.go +++ b/internal/sdk/models/operations/getconsumerdesign.go @@ -8,24 +8,22 @@ import ( ) type GetConsumerDesignRequest struct { - // Type of application that uses the design Application string `pathParam:"style=simple,explode=false,name=application"` - // Id of the design - ConsumerID string `pathParam:"style=simple,explode=false,name=consumerId"` + ConsumerID string `pathParam:"style=simple,explode=false,name=consumerId"` } -func (o *GetConsumerDesignRequest) GetApplication() string { - if o == nil { +func (g *GetConsumerDesignRequest) GetApplication() string { + if g == nil { return "" } - return o.Application + return g.Application } -func (o *GetConsumerDesignRequest) GetConsumerID() string { - if o == nil { +func (g *GetConsumerDesignRequest) GetConsumerID() string { + if g == nil { return "" } - return o.ConsumerID + return g.ConsumerID } type GetConsumerDesignResponse struct { @@ -41,37 +39,37 @@ type GetConsumerDesignResponse struct { RawResponse *http.Response } -func (o *GetConsumerDesignResponse) GetContentType() string { - if o == nil { +func (g *GetConsumerDesignResponse) GetContentType() string { + if g == nil { return "" } - return o.ContentType + return g.ContentType } -func (o *GetConsumerDesignResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (g *GetConsumerDesignResponse) GetErrorResp() *shared.ErrorResp { + if g == nil { return nil } - return o.ErrorResp + return g.ErrorResp } -func (o *GetConsumerDesignResponse) GetGetDesignRes() *shared.GetDesignRes { - if o == nil { +func (g *GetConsumerDesignResponse) GetGetDesignRes() *shared.GetDesignRes { + if g == nil { return nil } - return o.GetDesignRes + return g.GetDesignRes } -func (o *GetConsumerDesignResponse) GetStatusCode() int { - if o == nil { +func (g *GetConsumerDesignResponse) GetStatusCode() int { + if g == nil { return 0 } - return o.StatusCode + return g.StatusCode } -func (o *GetConsumerDesignResponse) GetRawResponse() *http.Response { - if o == nil { +func (g *GetConsumerDesignResponse) GetRawResponse() *http.Response { + if g == nil { return nil } - return o.RawResponse + return g.RawResponse } diff --git a/internal/sdk/models/operations/getdesign.go b/internal/sdk/models/operations/getdesign.go index e6341d9..2dcb9ae 100644 --- a/internal/sdk/models/operations/getdesign.go +++ b/internal/sdk/models/operations/getdesign.go @@ -8,15 +8,14 @@ import ( ) type GetDesignRequest struct { - // Id of the design DesignID string `pathParam:"style=simple,explode=false,name=designId"` } -func (o *GetDesignRequest) GetDesignID() string { - if o == nil { +func (g *GetDesignRequest) GetDesignID() string { + if g == nil { return "" } - return o.DesignID + return g.DesignID } type GetDesignResponse struct { @@ -32,37 +31,37 @@ type GetDesignResponse struct { RawResponse *http.Response } -func (o *GetDesignResponse) GetContentType() string { - if o == nil { +func (g *GetDesignResponse) GetContentType() string { + if g == nil { return "" } - return o.ContentType + return g.ContentType } -func (o *GetDesignResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (g *GetDesignResponse) GetErrorResp() *shared.ErrorResp { + if g == nil { return nil } - return o.ErrorResp + return g.ErrorResp } -func (o *GetDesignResponse) GetGetDesignRes() *shared.GetDesignRes { - if o == nil { +func (g *GetDesignResponse) GetGetDesignRes() *shared.GetDesignRes { + if g == nil { return nil } - return o.GetDesignRes + return g.GetDesignRes } -func (o *GetDesignResponse) GetStatusCode() int { - if o == nil { +func (g *GetDesignResponse) GetStatusCode() int { + if g == nil { return 0 } - return o.StatusCode + return g.StatusCode } -func (o *GetDesignResponse) GetRawResponse() *http.Response { - if o == nil { +func (g *GetDesignResponse) GetRawResponse() *http.Response { + if g == nil { return nil } - return o.RawResponse + return g.RawResponse } diff --git a/internal/sdk/models/operations/getfiles.go b/internal/sdk/models/operations/getfiles.go index eb50ca2..58cbaf8 100644 --- a/internal/sdk/models/operations/getfiles.go +++ b/internal/sdk/models/operations/getfiles.go @@ -41,11 +41,11 @@ type GetFilesRequest struct { Type *Type `queryParam:"style=form,explode=true,name=type"` } -func (o *GetFilesRequest) GetType() *Type { - if o == nil { +func (g *GetFilesRequest) GetType() *Type { + if g == nil { return nil } - return o.Type + return g.Type } type GetFilesResponse struct { @@ -61,37 +61,37 @@ type GetFilesResponse struct { RawResponse *http.Response } -func (o *GetFilesResponse) GetContentType() string { - if o == nil { +func (g *GetFilesResponse) GetContentType() string { + if g == nil { return "" } - return o.ContentType + return g.ContentType } -func (o *GetFilesResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (g *GetFilesResponse) GetErrorResp() *shared.ErrorResp { + if g == nil { return nil } - return o.ErrorResp + return g.ErrorResp } -func (o *GetFilesResponse) GetGetFilesRes() []shared.FileData { - if o == nil { +func (g *GetFilesResponse) GetGetFilesRes() []shared.FileData { + if g == nil { return nil } - return o.GetFilesRes + return g.GetFilesRes } -func (o *GetFilesResponse) GetStatusCode() int { - if o == nil { +func (g *GetFilesResponse) GetStatusCode() int { + if g == nil { return 0 } - return o.StatusCode + return g.StatusCode } -func (o *GetFilesResponse) GetRawResponse() *http.Response { - if o == nil { +func (g *GetFilesResponse) GetRawResponse() *http.Response { + if g == nil { return nil } - return o.RawResponse + return g.RawResponse } diff --git a/internal/sdk/models/operations/getlimit.go b/internal/sdk/models/operations/getlimit.go index fc520d8..4b8d1b2 100644 --- a/internal/sdk/models/operations/getlimit.go +++ b/internal/sdk/models/operations/getlimit.go @@ -20,37 +20,37 @@ type GetLimitResponse struct { Number *float64 } -func (o *GetLimitResponse) GetContentType() string { - if o == nil { +func (g *GetLimitResponse) GetContentType() string { + if g == nil { return "" } - return o.ContentType + return g.ContentType } -func (o *GetLimitResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (g *GetLimitResponse) GetErrorResp() *shared.ErrorResp { + if g == nil { return nil } - return o.ErrorResp + return g.ErrorResp } -func (o *GetLimitResponse) GetStatusCode() int { - if o == nil { +func (g *GetLimitResponse) GetStatusCode() int { + if g == nil { return 0 } - return o.StatusCode + return g.StatusCode } -func (o *GetLimitResponse) GetRawResponse() *http.Response { - if o == nil { +func (g *GetLimitResponse) GetRawResponse() *http.Response { + if g == nil { return nil } - return o.RawResponse + return g.RawResponse } -func (o *GetLimitResponse) GetNumber() *float64 { - if o == nil { +func (g *GetLimitResponse) GetNumber() *float64 { + if g == nil { return nil } - return o.Number + return g.Number } diff --git a/internal/sdk/models/operations/getthemefromdesign.go b/internal/sdk/models/operations/getthemefromdesign.go index 0cb36b1..bf837f4 100644 --- a/internal/sdk/models/operations/getthemefromdesign.go +++ b/internal/sdk/models/operations/getthemefromdesign.go @@ -3,67 +3,37 @@ package operations import ( - "encoding/json" - "fmt" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/shared" "net/http" ) -// Theme - Type of theme to be parsed and returned -type Theme string - -const ( - ThemeNew Theme = "NEW" - ThemeOld Theme = "OLD" -) - -func (e Theme) ToPointer() *Theme { - return &e -} -func (e *Theme) UnmarshalJSON(data []byte) error { - var v string - if err := json.Unmarshal(data, &v); err != nil { - return err - } - switch v { - case "NEW": - fallthrough - case "OLD": - *e = Theme(v) - return nil - default: - return fmt.Errorf("invalid value for Theme: %v", v) - } -} - type GetThemeFromDesignRequest struct { - // Id of the design DesignID string `pathParam:"style=simple,explode=false,name=designId"` // Organization id of the user OrgID *string `queryParam:"style=form,explode=true,name=orgId"` // Type of theme to be parsed and returned - Theme Theme `queryParam:"style=form,explode=true,name=theme"` + Theme shared.Theme `queryParam:"style=form,explode=true,name=theme"` } -func (o *GetThemeFromDesignRequest) GetDesignID() string { - if o == nil { +func (g *GetThemeFromDesignRequest) GetDesignID() string { + if g == nil { return "" } - return o.DesignID + return g.DesignID } -func (o *GetThemeFromDesignRequest) GetOrgID() *string { - if o == nil { +func (g *GetThemeFromDesignRequest) GetOrgID() *string { + if g == nil { return nil } - return o.OrgID + return g.OrgID } -func (o *GetThemeFromDesignRequest) GetTheme() Theme { - if o == nil { - return Theme("") +func (g *GetThemeFromDesignRequest) GetTheme() shared.Theme { + if g == nil { + return shared.Theme("") } - return o.Theme + return g.Theme } // GetThemeFromDesignResponseBody - Success - design parsed with success. @@ -83,37 +53,37 @@ type GetThemeFromDesignResponse struct { Object *GetThemeFromDesignResponseBody } -func (o *GetThemeFromDesignResponse) GetContentType() string { - if o == nil { +func (g *GetThemeFromDesignResponse) GetContentType() string { + if g == nil { return "" } - return o.ContentType + return g.ContentType } -func (o *GetThemeFromDesignResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (g *GetThemeFromDesignResponse) GetErrorResp() *shared.ErrorResp { + if g == nil { return nil } - return o.ErrorResp + return g.ErrorResp } -func (o *GetThemeFromDesignResponse) GetStatusCode() int { - if o == nil { +func (g *GetThemeFromDesignResponse) GetStatusCode() int { + if g == nil { return 0 } - return o.StatusCode + return g.StatusCode } -func (o *GetThemeFromDesignResponse) GetRawResponse() *http.Response { - if o == nil { +func (g *GetThemeFromDesignResponse) GetRawResponse() *http.Response { + if g == nil { return nil } - return o.RawResponse + return g.RawResponse } -func (o *GetThemeFromDesignResponse) GetObject() *GetThemeFromDesignResponseBody { - if o == nil { +func (g *GetThemeFromDesignResponse) GetObject() *GetThemeFromDesignResponseBody { + if g == nil { return nil } - return o.Object + return g.Object } diff --git a/internal/sdk/models/operations/removeconsumer.go b/internal/sdk/models/operations/removeconsumer.go index 267cde6..5b09563 100644 --- a/internal/sdk/models/operations/removeconsumer.go +++ b/internal/sdk/models/operations/removeconsumer.go @@ -9,32 +9,31 @@ import ( type RemoveConsumerRequest struct { // widget id payload - AddConsumerReq shared.AddConsumerReq `request:"mediaType=application/json"` + RemoveConsumerReq shared.RemoveConsumerReq `request:"mediaType=application/json"` // Type of application that uses the design Application string `pathParam:"style=simple,explode=false,name=application"` - // Id of the design - DesignID string `pathParam:"style=simple,explode=false,name=designId"` + DesignID string `pathParam:"style=simple,explode=false,name=designId"` } -func (o *RemoveConsumerRequest) GetAddConsumerReq() shared.AddConsumerReq { - if o == nil { - return shared.AddConsumerReq{} +func (r *RemoveConsumerRequest) GetRemoveConsumerReq() shared.RemoveConsumerReq { + if r == nil { + return shared.RemoveConsumerReq{} } - return o.AddConsumerReq + return r.RemoveConsumerReq } -func (o *RemoveConsumerRequest) GetApplication() string { - if o == nil { +func (r *RemoveConsumerRequest) GetApplication() string { + if r == nil { return "" } - return o.Application + return r.Application } -func (o *RemoveConsumerRequest) GetDesignID() string { - if o == nil { +func (r *RemoveConsumerRequest) GetDesignID() string { + if r == nil { return "" } - return o.DesignID + return r.DesignID } type RemoveConsumerResponse struct { @@ -48,30 +47,30 @@ type RemoveConsumerResponse struct { RawResponse *http.Response } -func (o *RemoveConsumerResponse) GetContentType() string { - if o == nil { +func (r *RemoveConsumerResponse) GetContentType() string { + if r == nil { return "" } - return o.ContentType + return r.ContentType } -func (o *RemoveConsumerResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (r *RemoveConsumerResponse) GetErrorResp() *shared.ErrorResp { + if r == nil { return nil } - return o.ErrorResp + return r.ErrorResp } -func (o *RemoveConsumerResponse) GetStatusCode() int { - if o == nil { +func (r *RemoveConsumerResponse) GetStatusCode() int { + if r == nil { return 0 } - return o.StatusCode + return r.StatusCode } -func (o *RemoveConsumerResponse) GetRawResponse() *http.Response { - if o == nil { +func (r *RemoveConsumerResponse) GetRawResponse() *http.Response { + if r == nil { return nil } - return o.RawResponse + return r.RawResponse } diff --git a/internal/sdk/models/operations/updatedesign.go b/internal/sdk/models/operations/updatedesign.go index a0e0180..8182957 100644 --- a/internal/sdk/models/operations/updatedesign.go +++ b/internal/sdk/models/operations/updatedesign.go @@ -10,22 +10,21 @@ import ( type UpdateDesignRequest struct { // Design payload UpdateDesignReq shared.UpdateDesignReq `request:"mediaType=application/json"` - // Id of the design - DesignID string `pathParam:"style=simple,explode=false,name=designId"` + DesignID string `pathParam:"style=simple,explode=false,name=designId"` } -func (o *UpdateDesignRequest) GetUpdateDesignReq() shared.UpdateDesignReq { - if o == nil { +func (u *UpdateDesignRequest) GetUpdateDesignReq() shared.UpdateDesignReq { + if u == nil { return shared.UpdateDesignReq{} } - return o.UpdateDesignReq + return u.UpdateDesignReq } -func (o *UpdateDesignRequest) GetDesignID() string { - if o == nil { +func (u *UpdateDesignRequest) GetDesignID() string { + if u == nil { return "" } - return o.DesignID + return u.DesignID } type UpdateDesignResponse struct { @@ -39,30 +38,30 @@ type UpdateDesignResponse struct { RawResponse *http.Response } -func (o *UpdateDesignResponse) GetContentType() string { - if o == nil { +func (u *UpdateDesignResponse) GetContentType() string { + if u == nil { return "" } - return o.ContentType + return u.ContentType } -func (o *UpdateDesignResponse) GetErrorResp() *shared.ErrorResp { - if o == nil { +func (u *UpdateDesignResponse) GetErrorResp() *shared.ErrorResp { + if u == nil { return nil } - return o.ErrorResp + return u.ErrorResp } -func (o *UpdateDesignResponse) GetStatusCode() int { - if o == nil { +func (u *UpdateDesignResponse) GetStatusCode() int { + if u == nil { return 0 } - return o.StatusCode + return u.StatusCode } -func (o *UpdateDesignResponse) GetRawResponse() *http.Response { - if o == nil { +func (u *UpdateDesignResponse) GetRawResponse() *http.Response { + if u == nil { return nil } - return o.RawResponse + return u.RawResponse } diff --git a/internal/sdk/models/operations/uploadfile.go b/internal/sdk/models/operations/uploadfile.go new file mode 100644 index 0000000..ac47db2 --- /dev/null +++ b/internal/sdk/models/operations/uploadfile.go @@ -0,0 +1,56 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package operations + +import ( + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/shared" + "net/http" +) + +type UploadFileResponse struct { + // HTTP response content type for this operation + ContentType string + // Validation Errors + ErrorResp *shared.ErrorResp + // HTTP response status code for this operation + StatusCode int + // Raw HTTP response; suitable for custom response parsing + RawResponse *http.Response + // Success - upload with success. + UploadFileRes *shared.UploadFileRes +} + +func (u *UploadFileResponse) GetContentType() string { + if u == nil { + return "" + } + return u.ContentType +} + +func (u *UploadFileResponse) GetErrorResp() *shared.ErrorResp { + if u == nil { + return nil + } + return u.ErrorResp +} + +func (u *UploadFileResponse) GetStatusCode() int { + if u == nil { + return 0 + } + return u.StatusCode +} + +func (u *UploadFileResponse) GetRawResponse() *http.Response { + if u == nil { + return nil + } + return u.RawResponse +} + +func (u *UploadFileResponse) GetUploadFileRes() *shared.UploadFileRes { + if u == nil { + return nil + } + return u.UploadFileRes +} diff --git a/internal/sdk/models/shared/addconsumerreq.go b/internal/sdk/models/shared/addconsumerreq.go index f5b41bc..7aa50be 100644 --- a/internal/sdk/models/shared/addconsumerreq.go +++ b/internal/sdk/models/shared/addconsumerreq.go @@ -3,28 +3,29 @@ package shared type AddConsumerReq struct { + // Id of the design ConsumerID string `json:"consumer_id"` ConsumerName string `json:"consumer_name"` ShouldDelete *string `json:"should_delete,omitempty"` } -func (o *AddConsumerReq) GetConsumerID() string { - if o == nil { +func (a *AddConsumerReq) GetConsumerID() string { + if a == nil { return "" } - return o.ConsumerID + return a.ConsumerID } -func (o *AddConsumerReq) GetConsumerName() string { - if o == nil { +func (a *AddConsumerReq) GetConsumerName() string { + if a == nil { return "" } - return o.ConsumerName + return a.ConsumerName } -func (o *AddConsumerReq) GetShouldDelete() *string { - if o == nil { +func (a *AddConsumerReq) GetShouldDelete() *string { + if a == nil { return nil } - return o.ShouldDelete + return a.ShouldDelete } diff --git a/internal/sdk/models/shared/adddesignreq.go b/internal/sdk/models/shared/adddesignreq.go index 8685d9b..0e079e3 100644 --- a/internal/sdk/models/shared/adddesignreq.go +++ b/internal/sdk/models/shared/adddesignreq.go @@ -8,25 +8,25 @@ type DesignTokens struct { CustomCSS *string `json:"custom_css,omitempty"` } -func (o *DesignTokens) GetCashback() *string { - if o == nil { +func (d *DesignTokens) GetCashback() *string { + if d == nil { return nil } - return o.Cashback + return d.Cashback } -func (o *DesignTokens) GetCoupon() *string { - if o == nil { +func (d *DesignTokens) GetCoupon() *string { + if d == nil { return nil } - return o.Coupon + return d.Coupon } -func (o *DesignTokens) GetCustomCSS() *string { - if o == nil { +func (d *DesignTokens) GetCustomCSS() *string { + if d == nil { return nil } - return o.CustomCSS + return d.CustomCSS } type User struct { @@ -36,32 +36,32 @@ type User struct { Userid *string `json:"userid,omitempty"` } -func (o *User) GetEmailaddress() *string { - if o == nil { +func (u *User) GetEmailaddress() *string { + if u == nil { return nil } - return o.Emailaddress + return u.Emailaddress } -func (o *User) GetFullname() *string { - if o == nil { +func (u *User) GetFullname() *string { + if u == nil { return nil } - return o.Fullname + return u.Fullname } -func (o *User) GetName() *string { - if o == nil { +func (u *User) GetName() *string { + if u == nil { return nil } - return o.Name + return u.Name } -func (o *User) GetUserid() *string { - if o == nil { +func (u *User) GetUserid() *string { + if u == nil { return nil } - return o.Userid + return u.Userid } type Design struct { @@ -76,76 +76,76 @@ type Design struct { User *User `json:"user,omitempty"` } -func (o *Design) GetBrandID() any { - if o == nil { +func (d *Design) GetBrandID() any { + if d == nil { return nil } - return o.BrandID + return d.BrandID } -func (o *Design) GetBrandName() *string { - if o == nil { +func (d *Design) GetBrandName() *string { + if d == nil { return nil } - return o.BrandName + return d.BrandName } -func (o *Design) GetCustomTheme() any { - if o == nil { +func (d *Design) GetCustomTheme() any { + if d == nil { return nil } - return o.CustomTheme + return d.CustomTheme } -func (o *Design) GetDesignTokens() *DesignTokens { - if o == nil { +func (d *Design) GetDesignTokens() *DesignTokens { + if d == nil { return nil } - return o.DesignTokens + return d.DesignTokens } -func (o *Design) GetIsDefault() *bool { - if o == nil { +func (d *Design) GetIsDefault() *bool { + if d == nil { return nil } - return o.IsDefault + return d.IsDefault } -func (o *Design) GetStyle() any { - if o == nil { +func (d *Design) GetStyle() any { + if d == nil { return nil } - return o.Style + return d.Style } -func (o *Design) GetStyleName() string { - if o == nil { +func (d *Design) GetStyleName() string { + if d == nil { return "" } - return o.StyleName + return d.StyleName } -func (o *Design) GetUseCustomTheme() *bool { - if o == nil { +func (d *Design) GetUseCustomTheme() *bool { + if d == nil { return nil } - return o.UseCustomTheme + return d.UseCustomTheme } -func (o *Design) GetUser() *User { - if o == nil { +func (d *Design) GetUser() *User { + if d == nil { return nil } - return o.User + return d.User } type AddDesignReq struct { Design Design `json:"design"` } -func (o *AddDesignReq) GetDesign() Design { - if o == nil { +func (a *AddDesignReq) GetDesign() Design { + if a == nil { return Design{} } - return o.Design + return a.Design } diff --git a/internal/sdk/models/shared/adddesignres.go b/internal/sdk/models/shared/adddesignres.go index 39860c3..449d0c7 100644 --- a/internal/sdk/models/shared/adddesignres.go +++ b/internal/sdk/models/shared/adddesignres.go @@ -8,25 +8,25 @@ type AddDesignResDesignTokens struct { CustomCSS *string `json:"custom_css,omitempty"` } -func (o *AddDesignResDesignTokens) GetCashback() *string { - if o == nil { +func (a *AddDesignResDesignTokens) GetCashback() *string { + if a == nil { return nil } - return o.Cashback + return a.Cashback } -func (o *AddDesignResDesignTokens) GetCoupon() *string { - if o == nil { +func (a *AddDesignResDesignTokens) GetCoupon() *string { + if a == nil { return nil } - return o.Coupon + return a.Coupon } -func (o *AddDesignResDesignTokens) GetCustomCSS() *string { - if o == nil { +func (a *AddDesignResDesignTokens) GetCustomCSS() *string { + if a == nil { return nil } - return o.CustomCSS + return a.CustomCSS } type AddDesignResUser struct { @@ -36,32 +36,32 @@ type AddDesignResUser struct { Userid *string `json:"userid,omitempty"` } -func (o *AddDesignResUser) GetEmailaddress() *string { - if o == nil { +func (a *AddDesignResUser) GetEmailaddress() *string { + if a == nil { return nil } - return o.Emailaddress + return a.Emailaddress } -func (o *AddDesignResUser) GetFullname() *string { - if o == nil { +func (a *AddDesignResUser) GetFullname() *string { + if a == nil { return nil } - return o.Fullname + return a.Fullname } -func (o *AddDesignResUser) GetName() *string { - if o == nil { +func (a *AddDesignResUser) GetName() *string { + if a == nil { return nil } - return o.Name + return a.Name } -func (o *AddDesignResUser) GetUserid() *string { - if o == nil { +func (a *AddDesignResUser) GetUserid() *string { + if a == nil { return nil } - return o.Userid + return a.Userid } type AddDesignResDesign struct { @@ -82,111 +82,111 @@ type AddDesignResDesign struct { User *AddDesignResUser `json:"user,omitempty"` } -func (o *AddDesignResDesign) GetBrandID() any { - if o == nil { +func (a *AddDesignResDesign) GetBrandID() any { + if a == nil { return nil } - return o.BrandID + return a.BrandID } -func (o *AddDesignResDesign) GetBrandName() *string { - if o == nil { +func (a *AddDesignResDesign) GetBrandName() *string { + if a == nil { return nil } - return o.BrandName + return a.BrandName } -func (o *AddDesignResDesign) GetCreatedAt() *string { - if o == nil { +func (a *AddDesignResDesign) GetCreatedAt() *string { + if a == nil { return nil } - return o.CreatedAt + return a.CreatedAt } -func (o *AddDesignResDesign) GetCreatedBy() *string { - if o == nil { +func (a *AddDesignResDesign) GetCreatedBy() *string { + if a == nil { return nil } - return o.CreatedBy + return a.CreatedBy } -func (o *AddDesignResDesign) GetCustomTheme() any { - if o == nil { +func (a *AddDesignResDesign) GetCustomTheme() any { + if a == nil { return nil } - return o.CustomTheme + return a.CustomTheme } -func (o *AddDesignResDesign) GetDesignTokens() *AddDesignResDesignTokens { - if o == nil { +func (a *AddDesignResDesign) GetDesignTokens() *AddDesignResDesignTokens { + if a == nil { return nil } - return o.DesignTokens + return a.DesignTokens } -func (o *AddDesignResDesign) GetEdited() bool { - if o == nil { +func (a *AddDesignResDesign) GetEdited() bool { + if a == nil { return false } - return o.Edited + return a.Edited } -func (o *AddDesignResDesign) GetID() *string { - if o == nil { +func (a *AddDesignResDesign) GetID() *string { + if a == nil { return nil } - return o.ID + return a.ID } -func (o *AddDesignResDesign) GetIsDefault() *bool { - if o == nil { +func (a *AddDesignResDesign) GetIsDefault() *bool { + if a == nil { return nil } - return o.IsDefault + return a.IsDefault } -func (o *AddDesignResDesign) GetLastModifiedAt() *string { - if o == nil { +func (a *AddDesignResDesign) GetLastModifiedAt() *string { + if a == nil { return nil } - return o.LastModifiedAt + return a.LastModifiedAt } -func (o *AddDesignResDesign) GetStyle() any { - if o == nil { +func (a *AddDesignResDesign) GetStyle() any { + if a == nil { return nil } - return o.Style + return a.Style } -func (o *AddDesignResDesign) GetStyleName() string { - if o == nil { +func (a *AddDesignResDesign) GetStyleName() string { + if a == nil { return "" } - return o.StyleName + return a.StyleName } -func (o *AddDesignResDesign) GetUseCustomTheme() *bool { - if o == nil { +func (a *AddDesignResDesign) GetUseCustomTheme() *bool { + if a == nil { return nil } - return o.UseCustomTheme + return a.UseCustomTheme } -func (o *AddDesignResDesign) GetUser() *AddDesignResUser { - if o == nil { +func (a *AddDesignResDesign) GetUser() *AddDesignResUser { + if a == nil { return nil } - return o.User + return a.User } type AddDesignRes struct { Design *AddDesignResDesign `json:"design,omitempty"` } -func (o *AddDesignRes) GetDesign() *AddDesignResDesign { - if o == nil { +func (a *AddDesignRes) GetDesign() *AddDesignResDesign { + if a == nil { return nil } - return o.Design + return a.Design } diff --git a/internal/sdk/models/shared/branditem.go b/internal/sdk/models/shared/branditem.go index c3eecb4..251e54e 100644 --- a/internal/sdk/models/shared/branditem.go +++ b/internal/sdk/models/shared/branditem.go @@ -14,65 +14,65 @@ type BrandItem struct { UpdatedDate *string `json:"updated_date,omitempty"` } -func (o *BrandItem) GetCreatedBy() *string { - if o == nil { +func (b *BrandItem) GetCreatedBy() *string { + if b == nil { return nil } - return o.CreatedBy + return b.CreatedBy } -func (o *BrandItem) GetCreatedDate() *string { - if o == nil { +func (b *BrandItem) GetCreatedDate() *string { + if b == nil { return nil } - return o.CreatedDate + return b.CreatedDate } -func (o *BrandItem) GetID() string { - if o == nil { +func (b *BrandItem) GetID() string { + if b == nil { return "" } - return o.ID + return b.ID } -func (o *BrandItem) GetMainBrand() *string { - if o == nil { +func (b *BrandItem) GetMainBrand() *string { + if b == nil { return nil } - return o.MainBrand + return b.MainBrand } -func (o *BrandItem) GetName() string { - if o == nil { +func (b *BrandItem) GetName() string { + if b == nil { return "" } - return o.Name + return b.Name } -func (o *BrandItem) GetOrganizationID() *string { - if o == nil { +func (b *BrandItem) GetOrganizationID() *string { + if b == nil { return nil } - return o.OrganizationID + return b.OrganizationID } -func (o *BrandItem) GetStatus() *string { - if o == nil { +func (b *BrandItem) GetStatus() *string { + if b == nil { return nil } - return o.Status + return b.Status } -func (o *BrandItem) GetUpdatedBy() *string { - if o == nil { +func (b *BrandItem) GetUpdatedBy() *string { + if b == nil { return nil } - return o.UpdatedBy + return b.UpdatedBy } -func (o *BrandItem) GetUpdatedDate() *string { - if o == nil { +func (b *BrandItem) GetUpdatedDate() *string { + if b == nil { return nil } - return o.UpdatedDate + return b.UpdatedDate } diff --git a/internal/sdk/models/shared/errorresp.go b/internal/sdk/models/shared/errorresp.go index 4f53535..574d2ce 100644 --- a/internal/sdk/models/shared/errorresp.go +++ b/internal/sdk/models/shared/errorresp.go @@ -2,13 +2,24 @@ package shared +type Error struct { +} + type ErrorResp struct { + Error *Error `json:"error,omitempty"` Message *string `json:"message,omitempty"` } -func (o *ErrorResp) GetMessage() *string { - if o == nil { +func (e *ErrorResp) GetError() *Error { + if e == nil { + return nil + } + return e.Error +} + +func (e *ErrorResp) GetMessage() *string { + if e == nil { return nil } - return o.Message + return e.Message } diff --git a/internal/sdk/models/shared/filedata.go b/internal/sdk/models/shared/filedata.go index e4802e9..124e1da 100644 --- a/internal/sdk/models/shared/filedata.go +++ b/internal/sdk/models/shared/filedata.go @@ -41,37 +41,37 @@ type FileData struct { URL string `json:"url"` } -func (o *FileData) GetDisplayName() *string { - if o == nil { +func (f *FileData) GetDisplayName() *string { + if f == nil { return nil } - return o.DisplayName + return f.DisplayName } -func (o *FileData) GetFileType() *FileType { - if o == nil { +func (f *FileData) GetFileType() *FileType { + if f == nil { return nil } - return o.FileType + return f.FileType } -func (o *FileData) GetName() string { - if o == nil { +func (f *FileData) GetName() string { + if f == nil { return "" } - return o.Name + return f.Name } -func (o *FileData) GetS3ObjectKey() string { - if o == nil { +func (f *FileData) GetS3ObjectKey() string { + if f == nil { return "" } - return o.S3ObjectKey + return f.S3ObjectKey } -func (o *FileData) GetURL() string { - if o == nil { +func (f *FileData) GetURL() string { + if f == nil { return "" } - return o.URL + return f.URL } diff --git a/internal/sdk/models/shared/getalldesignsres.go b/internal/sdk/models/shared/getalldesignsres.go index 077ea36..447619a 100644 --- a/internal/sdk/models/shared/getalldesignsres.go +++ b/internal/sdk/models/shared/getalldesignsres.go @@ -8,25 +8,25 @@ type GetAllDesignsResDesignTokens struct { CustomCSS *string `json:"custom_css,omitempty"` } -func (o *GetAllDesignsResDesignTokens) GetCashback() *string { - if o == nil { +func (g *GetAllDesignsResDesignTokens) GetCashback() *string { + if g == nil { return nil } - return o.Cashback + return g.Cashback } -func (o *GetAllDesignsResDesignTokens) GetCoupon() *string { - if o == nil { +func (g *GetAllDesignsResDesignTokens) GetCoupon() *string { + if g == nil { return nil } - return o.Coupon + return g.Coupon } -func (o *GetAllDesignsResDesignTokens) GetCustomCSS() *string { - if o == nil { +func (g *GetAllDesignsResDesignTokens) GetCustomCSS() *string { + if g == nil { return nil } - return o.CustomCSS + return g.CustomCSS } type GetAllDesignsResUser struct { @@ -36,32 +36,32 @@ type GetAllDesignsResUser struct { Userid *string `json:"userid,omitempty"` } -func (o *GetAllDesignsResUser) GetEmailaddress() *string { - if o == nil { +func (g *GetAllDesignsResUser) GetEmailaddress() *string { + if g == nil { return nil } - return o.Emailaddress + return g.Emailaddress } -func (o *GetAllDesignsResUser) GetFullname() *string { - if o == nil { +func (g *GetAllDesignsResUser) GetFullname() *string { + if g == nil { return nil } - return o.Fullname + return g.Fullname } -func (o *GetAllDesignsResUser) GetName() *string { - if o == nil { +func (g *GetAllDesignsResUser) GetName() *string { + if g == nil { return nil } - return o.Name + return g.Name } -func (o *GetAllDesignsResUser) GetUserid() *string { - if o == nil { +func (g *GetAllDesignsResUser) GetUserid() *string { + if g == nil { return nil } - return o.Userid + return g.Userid } type Designs struct { @@ -82,111 +82,111 @@ type Designs struct { User *GetAllDesignsResUser `json:"user,omitempty"` } -func (o *Designs) GetBrandID() any { - if o == nil { +func (d *Designs) GetBrandID() any { + if d == nil { return nil } - return o.BrandID + return d.BrandID } -func (o *Designs) GetBrandName() *string { - if o == nil { +func (d *Designs) GetBrandName() *string { + if d == nil { return nil } - return o.BrandName + return d.BrandName } -func (o *Designs) GetCreatedAt() *string { - if o == nil { +func (d *Designs) GetCreatedAt() *string { + if d == nil { return nil } - return o.CreatedAt + return d.CreatedAt } -func (o *Designs) GetCreatedBy() *string { - if o == nil { +func (d *Designs) GetCreatedBy() *string { + if d == nil { return nil } - return o.CreatedBy + return d.CreatedBy } -func (o *Designs) GetCustomTheme() any { - if o == nil { +func (d *Designs) GetCustomTheme() any { + if d == nil { return nil } - return o.CustomTheme + return d.CustomTheme } -func (o *Designs) GetDesignTokens() *GetAllDesignsResDesignTokens { - if o == nil { +func (d *Designs) GetDesignTokens() *GetAllDesignsResDesignTokens { + if d == nil { return nil } - return o.DesignTokens + return d.DesignTokens } -func (o *Designs) GetEdited() bool { - if o == nil { +func (d *Designs) GetEdited() bool { + if d == nil { return false } - return o.Edited + return d.Edited } -func (o *Designs) GetID() *string { - if o == nil { +func (d *Designs) GetID() *string { + if d == nil { return nil } - return o.ID + return d.ID } -func (o *Designs) GetIsDefault() *bool { - if o == nil { +func (d *Designs) GetIsDefault() *bool { + if d == nil { return nil } - return o.IsDefault + return d.IsDefault } -func (o *Designs) GetLastModifiedAt() *string { - if o == nil { +func (d *Designs) GetLastModifiedAt() *string { + if d == nil { return nil } - return o.LastModifiedAt + return d.LastModifiedAt } -func (o *Designs) GetStyle() any { - if o == nil { +func (d *Designs) GetStyle() any { + if d == nil { return nil } - return o.Style + return d.Style } -func (o *Designs) GetStyleName() string { - if o == nil { +func (d *Designs) GetStyleName() string { + if d == nil { return "" } - return o.StyleName + return d.StyleName } -func (o *Designs) GetUseCustomTheme() *bool { - if o == nil { +func (d *Designs) GetUseCustomTheme() *bool { + if d == nil { return nil } - return o.UseCustomTheme + return d.UseCustomTheme } -func (o *Designs) GetUser() *GetAllDesignsResUser { - if o == nil { +func (d *Designs) GetUser() *GetAllDesignsResUser { + if d == nil { return nil } - return o.User + return d.User } type GetAllDesignsRes struct { Designs []Designs `json:"designs,omitempty"` } -func (o *GetAllDesignsRes) GetDesigns() []Designs { - if o == nil { +func (g *GetAllDesignsRes) GetDesigns() []Designs { + if g == nil { return nil } - return o.Designs + return g.Designs } diff --git a/internal/sdk/models/shared/getbrandsres.go b/internal/sdk/models/shared/getbrandsres.go index a52cbc1..e31eb4f 100644 --- a/internal/sdk/models/shared/getbrandsres.go +++ b/internal/sdk/models/shared/getbrandsres.go @@ -6,9 +6,9 @@ type GetBrandsRes struct { Brands []BrandItem `json:"brands,omitempty"` } -func (o *GetBrandsRes) GetBrands() []BrandItem { - if o == nil { +func (g *GetBrandsRes) GetBrands() []BrandItem { + if g == nil { return nil } - return o.Brands + return g.Brands } diff --git a/internal/sdk/models/shared/getdesignres.go b/internal/sdk/models/shared/getdesignres.go index 5488ca7..c78ed6c 100644 --- a/internal/sdk/models/shared/getdesignres.go +++ b/internal/sdk/models/shared/getdesignres.go @@ -8,25 +8,25 @@ type GetDesignResDesignTokens struct { CustomCSS *string `json:"custom_css,omitempty"` } -func (o *GetDesignResDesignTokens) GetCashback() *string { - if o == nil { +func (g *GetDesignResDesignTokens) GetCashback() *string { + if g == nil { return nil } - return o.Cashback + return g.Cashback } -func (o *GetDesignResDesignTokens) GetCoupon() *string { - if o == nil { +func (g *GetDesignResDesignTokens) GetCoupon() *string { + if g == nil { return nil } - return o.Coupon + return g.Coupon } -func (o *GetDesignResDesignTokens) GetCustomCSS() *string { - if o == nil { +func (g *GetDesignResDesignTokens) GetCustomCSS() *string { + if g == nil { return nil } - return o.CustomCSS + return g.CustomCSS } type GetDesignResUser struct { @@ -36,32 +36,32 @@ type GetDesignResUser struct { Userid *string `json:"userid,omitempty"` } -func (o *GetDesignResUser) GetEmailaddress() *string { - if o == nil { +func (g *GetDesignResUser) GetEmailaddress() *string { + if g == nil { return nil } - return o.Emailaddress + return g.Emailaddress } -func (o *GetDesignResUser) GetFullname() *string { - if o == nil { +func (g *GetDesignResUser) GetFullname() *string { + if g == nil { return nil } - return o.Fullname + return g.Fullname } -func (o *GetDesignResUser) GetName() *string { - if o == nil { +func (g *GetDesignResUser) GetName() *string { + if g == nil { return nil } - return o.Name + return g.Name } -func (o *GetDesignResUser) GetUserid() *string { - if o == nil { +func (g *GetDesignResUser) GetUserid() *string { + if g == nil { return nil } - return o.Userid + return g.Userid } type GetDesignResDesign struct { @@ -82,111 +82,111 @@ type GetDesignResDesign struct { User *GetDesignResUser `json:"user,omitempty"` } -func (o *GetDesignResDesign) GetBrandID() any { - if o == nil { +func (g *GetDesignResDesign) GetBrandID() any { + if g == nil { return nil } - return o.BrandID + return g.BrandID } -func (o *GetDesignResDesign) GetBrandName() *string { - if o == nil { +func (g *GetDesignResDesign) GetBrandName() *string { + if g == nil { return nil } - return o.BrandName + return g.BrandName } -func (o *GetDesignResDesign) GetCreatedAt() *string { - if o == nil { +func (g *GetDesignResDesign) GetCreatedAt() *string { + if g == nil { return nil } - return o.CreatedAt + return g.CreatedAt } -func (o *GetDesignResDesign) GetCreatedBy() *string { - if o == nil { +func (g *GetDesignResDesign) GetCreatedBy() *string { + if g == nil { return nil } - return o.CreatedBy + return g.CreatedBy } -func (o *GetDesignResDesign) GetCustomTheme() any { - if o == nil { +func (g *GetDesignResDesign) GetCustomTheme() any { + if g == nil { return nil } - return o.CustomTheme + return g.CustomTheme } -func (o *GetDesignResDesign) GetDesignTokens() *GetDesignResDesignTokens { - if o == nil { +func (g *GetDesignResDesign) GetDesignTokens() *GetDesignResDesignTokens { + if g == nil { return nil } - return o.DesignTokens + return g.DesignTokens } -func (o *GetDesignResDesign) GetEdited() bool { - if o == nil { +func (g *GetDesignResDesign) GetEdited() bool { + if g == nil { return false } - return o.Edited + return g.Edited } -func (o *GetDesignResDesign) GetID() *string { - if o == nil { +func (g *GetDesignResDesign) GetID() *string { + if g == nil { return nil } - return o.ID + return g.ID } -func (o *GetDesignResDesign) GetIsDefault() *bool { - if o == nil { +func (g *GetDesignResDesign) GetIsDefault() *bool { + if g == nil { return nil } - return o.IsDefault + return g.IsDefault } -func (o *GetDesignResDesign) GetLastModifiedAt() *string { - if o == nil { +func (g *GetDesignResDesign) GetLastModifiedAt() *string { + if g == nil { return nil } - return o.LastModifiedAt + return g.LastModifiedAt } -func (o *GetDesignResDesign) GetStyle() any { - if o == nil { +func (g *GetDesignResDesign) GetStyle() any { + if g == nil { return nil } - return o.Style + return g.Style } -func (o *GetDesignResDesign) GetStyleName() string { - if o == nil { +func (g *GetDesignResDesign) GetStyleName() string { + if g == nil { return "" } - return o.StyleName + return g.StyleName } -func (o *GetDesignResDesign) GetUseCustomTheme() *bool { - if o == nil { +func (g *GetDesignResDesign) GetUseCustomTheme() *bool { + if g == nil { return nil } - return o.UseCustomTheme + return g.UseCustomTheme } -func (o *GetDesignResDesign) GetUser() *GetDesignResUser { - if o == nil { +func (g *GetDesignResDesign) GetUser() *GetDesignResUser { + if g == nil { return nil } - return o.User + return g.User } type GetDesignRes struct { Design *GetDesignResDesign `json:"design,omitempty"` } -func (o *GetDesignRes) GetDesign() *GetDesignResDesign { - if o == nil { +func (g *GetDesignRes) GetDesign() *GetDesignResDesign { + if g == nil { return nil } - return o.Design + return g.Design } diff --git a/internal/sdk/models/shared/removeconsumerreq.go b/internal/sdk/models/shared/removeconsumerreq.go new file mode 100644 index 0000000..08fd66c --- /dev/null +++ b/internal/sdk/models/shared/removeconsumerreq.go @@ -0,0 +1,24 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package shared + +type RemoveConsumerReq struct { + // Id of the design + ConsumerID string `json:"consumer_id"` + // Deprecated: This will be removed in a future release, please migrate away from it as soon as possible. + ShouldDelete *string `json:"should_delete,omitempty"` +} + +func (r *RemoveConsumerReq) GetConsumerID() string { + if r == nil { + return "" + } + return r.ConsumerID +} + +func (r *RemoveConsumerReq) GetShouldDelete() *string { + if r == nil { + return nil + } + return r.ShouldDelete +} diff --git a/internal/sdk/models/shared/security.go b/internal/sdk/models/shared/security.go index b256b4f..4c8dd96 100644 --- a/internal/sdk/models/shared/security.go +++ b/internal/sdk/models/shared/security.go @@ -6,9 +6,9 @@ type Security struct { CustomAuthorizer *string `security:"scheme,type=http,subtype=bearer,name=Authorization"` } -func (o *Security) GetCustomAuthorizer() *string { - if o == nil { +func (s *Security) GetCustomAuthorizer() *string { + if s == nil { return nil } - return o.CustomAuthorizer + return s.CustomAuthorizer } diff --git a/internal/sdk/models/shared/theme.go b/internal/sdk/models/shared/theme.go new file mode 100644 index 0000000..0db1760 --- /dev/null +++ b/internal/sdk/models/shared/theme.go @@ -0,0 +1,35 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package shared + +import ( + "encoding/json" + "fmt" +) + +// Theme - Type of theme to be parsed and returned +type Theme string + +const ( + ThemeNew Theme = "NEW" + ThemeOld Theme = "OLD" +) + +func (e Theme) ToPointer() *Theme { + return &e +} +func (e *Theme) UnmarshalJSON(data []byte) error { + var v string + if err := json.Unmarshal(data, &v); err != nil { + return err + } + switch v { + case "NEW": + fallthrough + case "OLD": + *e = Theme(v) + return nil + default: + return fmt.Errorf("invalid value for Theme: %v", v) + } +} diff --git a/internal/sdk/models/shared/updatedesignreq.go b/internal/sdk/models/shared/updatedesignreq.go index c0b5e0c..fd34568 100644 --- a/internal/sdk/models/shared/updatedesignreq.go +++ b/internal/sdk/models/shared/updatedesignreq.go @@ -8,25 +8,25 @@ type UpdateDesignReqDesignTokens struct { CustomCSS *string `json:"custom_css,omitempty"` } -func (o *UpdateDesignReqDesignTokens) GetCashback() *string { - if o == nil { +func (u *UpdateDesignReqDesignTokens) GetCashback() *string { + if u == nil { return nil } - return o.Cashback + return u.Cashback } -func (o *UpdateDesignReqDesignTokens) GetCoupon() *string { - if o == nil { +func (u *UpdateDesignReqDesignTokens) GetCoupon() *string { + if u == nil { return nil } - return o.Coupon + return u.Coupon } -func (o *UpdateDesignReqDesignTokens) GetCustomCSS() *string { - if o == nil { +func (u *UpdateDesignReqDesignTokens) GetCustomCSS() *string { + if u == nil { return nil } - return o.CustomCSS + return u.CustomCSS } type UpdateDesignReqUser struct { @@ -36,32 +36,32 @@ type UpdateDesignReqUser struct { Userid *string `json:"userid,omitempty"` } -func (o *UpdateDesignReqUser) GetEmailaddress() *string { - if o == nil { +func (u *UpdateDesignReqUser) GetEmailaddress() *string { + if u == nil { return nil } - return o.Emailaddress + return u.Emailaddress } -func (o *UpdateDesignReqUser) GetFullname() *string { - if o == nil { +func (u *UpdateDesignReqUser) GetFullname() *string { + if u == nil { return nil } - return o.Fullname + return u.Fullname } -func (o *UpdateDesignReqUser) GetName() *string { - if o == nil { +func (u *UpdateDesignReqUser) GetName() *string { + if u == nil { return nil } - return o.Name + return u.Name } -func (o *UpdateDesignReqUser) GetUserid() *string { - if o == nil { +func (u *UpdateDesignReqUser) GetUserid() *string { + if u == nil { return nil } - return o.Userid + return u.Userid } type UpdateDesignReqDesign struct { @@ -76,76 +76,76 @@ type UpdateDesignReqDesign struct { User *UpdateDesignReqUser `json:"user,omitempty"` } -func (o *UpdateDesignReqDesign) GetBrandID() any { - if o == nil { +func (u *UpdateDesignReqDesign) GetBrandID() any { + if u == nil { return nil } - return o.BrandID + return u.BrandID } -func (o *UpdateDesignReqDesign) GetBrandName() *string { - if o == nil { +func (u *UpdateDesignReqDesign) GetBrandName() *string { + if u == nil { return nil } - return o.BrandName + return u.BrandName } -func (o *UpdateDesignReqDesign) GetCustomTheme() any { - if o == nil { +func (u *UpdateDesignReqDesign) GetCustomTheme() any { + if u == nil { return nil } - return o.CustomTheme + return u.CustomTheme } -func (o *UpdateDesignReqDesign) GetDesignTokens() *UpdateDesignReqDesignTokens { - if o == nil { +func (u *UpdateDesignReqDesign) GetDesignTokens() *UpdateDesignReqDesignTokens { + if u == nil { return nil } - return o.DesignTokens + return u.DesignTokens } -func (o *UpdateDesignReqDesign) GetIsDefault() *bool { - if o == nil { +func (u *UpdateDesignReqDesign) GetIsDefault() *bool { + if u == nil { return nil } - return o.IsDefault + return u.IsDefault } -func (o *UpdateDesignReqDesign) GetStyle() any { - if o == nil { +func (u *UpdateDesignReqDesign) GetStyle() any { + if u == nil { return nil } - return o.Style + return u.Style } -func (o *UpdateDesignReqDesign) GetStyleName() string { - if o == nil { +func (u *UpdateDesignReqDesign) GetStyleName() string { + if u == nil { return "" } - return o.StyleName + return u.StyleName } -func (o *UpdateDesignReqDesign) GetUseCustomTheme() *bool { - if o == nil { +func (u *UpdateDesignReqDesign) GetUseCustomTheme() *bool { + if u == nil { return nil } - return o.UseCustomTheme + return u.UseCustomTheme } -func (o *UpdateDesignReqDesign) GetUser() *UpdateDesignReqUser { - if o == nil { +func (u *UpdateDesignReqDesign) GetUser() *UpdateDesignReqUser { + if u == nil { return nil } - return o.User + return u.User } type UpdateDesignReq struct { Design UpdateDesignReqDesign `json:"design"` } -func (o *UpdateDesignReq) GetDesign() UpdateDesignReqDesign { - if o == nil { +func (u *UpdateDesignReq) GetDesign() UpdateDesignReqDesign { + if u == nil { return UpdateDesignReqDesign{} } - return o.Design + return u.Design } diff --git a/internal/sdk/models/shared/uploadfilereq.go b/internal/sdk/models/shared/uploadfilereq.go new file mode 100644 index 0000000..8a60fe4 --- /dev/null +++ b/internal/sdk/models/shared/uploadfilereq.go @@ -0,0 +1,69 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package shared + +import ( + "encoding/json" + "fmt" +) + +type UploadFileReqFileType string + +const ( + UploadFileReqFileTypeLogo UploadFileReqFileType = "LOGO" + UploadFileReqFileTypeFont UploadFileReqFileType = "FONT" +) + +func (e UploadFileReqFileType) ToPointer() *UploadFileReqFileType { + return &e +} +func (e *UploadFileReqFileType) UnmarshalJSON(data []byte) error { + var v string + if err := json.Unmarshal(data, &v); err != nil { + return err + } + switch v { + case "LOGO": + fallthrough + case "FONT": + *e = UploadFileReqFileType(v) + return nil + default: + return fmt.Errorf("invalid value for UploadFileReqFileType: %v", v) + } +} + +type UploadFileReq struct { + DisplayName *string `multipartForm:"name=display_name"` + FileData string `multipartForm:"name=file_data"` + FileName string `multipartForm:"name=file_name"` + FileType UploadFileReqFileType `multipartForm:"name=file_type"` +} + +func (u *UploadFileReq) GetDisplayName() *string { + if u == nil { + return nil + } + return u.DisplayName +} + +func (u *UploadFileReq) GetFileData() string { + if u == nil { + return "" + } + return u.FileData +} + +func (u *UploadFileReq) GetFileName() string { + if u == nil { + return "" + } + return u.FileName +} + +func (u *UploadFileReq) GetFileType() UploadFileReqFileType { + if u == nil { + return UploadFileReqFileType("") + } + return u.FileType +} diff --git a/internal/sdk/models/shared/uploadfileres.go b/internal/sdk/models/shared/uploadfileres.go new file mode 100644 index 0000000..6423dd2 --- /dev/null +++ b/internal/sdk/models/shared/uploadfileres.go @@ -0,0 +1,77 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package shared + +import ( + "encoding/json" + "fmt" +) + +type UploadFileResFileType string + +const ( + UploadFileResFileTypeLogo UploadFileResFileType = "LOGO" + UploadFileResFileTypeFont UploadFileResFileType = "FONT" +) + +func (e UploadFileResFileType) ToPointer() *UploadFileResFileType { + return &e +} +func (e *UploadFileResFileType) UnmarshalJSON(data []byte) error { + var v string + if err := json.Unmarshal(data, &v); err != nil { + return err + } + switch v { + case "LOGO": + fallthrough + case "FONT": + *e = UploadFileResFileType(v) + return nil + default: + return fmt.Errorf("invalid value for UploadFileResFileType: %v", v) + } +} + +type UploadFileRes struct { + DisplayName *string `json:"display_name,omitempty"` + FileType *UploadFileResFileType `json:"file_type,omitempty"` + Name string `json:"name"` + S3ObjectKey string `json:"s3_object_key"` + URL string `json:"url"` +} + +func (u *UploadFileRes) GetDisplayName() *string { + if u == nil { + return nil + } + return u.DisplayName +} + +func (u *UploadFileRes) GetFileType() *UploadFileResFileType { + if u == nil { + return nil + } + return u.FileType +} + +func (u *UploadFileRes) GetName() string { + if u == nil { + return "" + } + return u.Name +} + +func (u *UploadFileRes) GetS3ObjectKey() string { + if u == nil { + return "" + } + return u.S3ObjectKey +} + +func (u *UploadFileRes) GetURL() string { + if u == nil { + return "" + } + return u.URL +} diff --git a/internal/sdk/optionalnullable/optionalnullable.go b/internal/sdk/optionalnullable/optionalnullable.go new file mode 100644 index 0000000..c6739be --- /dev/null +++ b/internal/sdk/optionalnullable/optionalnullable.go @@ -0,0 +1,233 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package optionalnullable + +import ( + "bytes" + "encoding/json" + "reflect" +) + +// OptionalNullable represents a field that can distinguish between three states: +// 1. Set to a value: field is present with a non-nil value +// 2. Set to nil: field is present but explicitly set to null in JSON +// 3. Unset: field is omitted from JSON entirely +// +// This type is designed to work with JSON marshaling/unmarshaling and supports +// the `omitempty` struct tag to properly omit unset fields from JSON output. +// +// Usage: +// +// type User struct { +// Name OptionalNullable[string] `json:"name,omitempty"` +// Age OptionalNullable[int] `json:"age,omitempty"` +// Tags OptionalNullable[[]string] `json:"tags,omitempty"` +// } +// +// // Set to value +// name := "John" +// user.Name = From(&name) +// +// // Set to nil (will appear as "name": null in JSON) +// user.Name = From[string](nil) +// +// // Leave unset (will be omitted from JSON with omitempty) +// user := User{} +// +// WARNING: Do NOT use *OptionalNullable[T] as a field type. Always use OptionalNullable[T] directly. +// Using *OptionalNullable[T] will break the omitempty behavior and JSON marshaling. +// +// The type is implemented as a map[bool]*T where: +// - nil map represents unset state +// - Map with true key represents set state (value may be nil) +type OptionalNullable[T any] map[bool]*T + +// From creates a new OptionalNullable with the given value. +// Pass nil to create a OptionalNullable that is set to null. +// Pass a pointer to a value to create a OptionalNullable with that value. +// +// Examples: +// +// hello := "hello" +// From(&hello) // set to "hello" +// From[string](nil) // set to null +func From[T any](value *T) OptionalNullable[T] { + return map[bool]*T{ + true: value, + } +} + +// IsNull returns true if the OptionalNullable is explicitly set to nil. +// Returns false if the OptionalNullable is unset or has a value. +// +// Note: This differs from traditional null checks because unset fields +// return false, not true. Use IsSet() to check if a field was provided. +func (n OptionalNullable[T]) IsNull() bool { + v, ok := n[true] + return ok && v == nil +} + +// IsSet returns true if the OptionalNullable has been explicitly set (to either a value or nil). +// Returns false if the OptionalNullable is unset (omitted from JSON). +// +// This is the key method for distinguishing between: +// - Set to nil: IsSet() = true, IsNull() = true +// - Unset: IsSet() = false, IsNull() = false +func (n OptionalNullable[T]) IsSet() bool { + _, ok := n[true] + return ok +} + +// Get returns the internal pointer and whether the field was set. +// +// Return values: +// - (ptr, true): field was set (ptr may be nil if set to null) +// - (nil, false): field was unset/omitted +// +// This method provides direct access to the internal pointer representation. +func (n OptionalNullable[T]) Get() (*T, bool) { + v, ok := n[true] + return v, ok +} + +// GetOrZero returns the value and whether it was set. +// +// Return values: +// - (value, true): field was set to a non-nil value +// - (zero, true): field was explicitly set to nil +// - (zero, false): field was unset/omitted +// +// Examples: +// +// val, ok := nullable.GetOrZero() +// if !ok { +// // Field was unset/omitted +// } else if nullable.IsNull() { +// // Field was explicitly set to null +// } else { +// // Field has a value: val +// } +func (n OptionalNullable[T]) GetOrZero() (T, bool) { + var zero T + + if v, ok := n[true]; ok { + if v == nil { + return zero, true + } + return *v, true + } + return zero, false +} + +// GetUntyped returns the value as interface{} and whether it was set. +// This is useful for reflection-based code that needs to work with the value +// without knowing the specific type T. +// +// Return values: +// - (value, true): field was set to a non-nil value +// - (nil, true): field was explicitly set to nil +// - (nil, false): field was unset/omitted +func (n OptionalNullable[T]) GetUntyped() (interface{}, bool) { + if v, ok := n[true]; ok { + if v == nil { + return nil, true + } + return *v, true + } + return nil, false +} + +// Set sets the OptionalNullable to the given value pointer. +// Pass nil to set the field to null. +// Pass a pointer to a value to set the field to that value. +// +// Examples: +// +// nullable.Set(ptrFrom("hello")) // set to "hello" +// nullable.Set(nil) // set to null +func (n *OptionalNullable[T]) Set(value *T) { + *n = map[bool]*T{ + true: value, + } +} + +// Unset removes the value, making the field unset/omitted. +// After calling Unset(), IsSet() will return false and the field +// will be omitted from JSON output when using omitempty. +func (n *OptionalNullable[T]) Unset() { + *n = map[bool]*T{} +} + +// MarshalJSON implements json.Marshaler. +// +// Behavior: +// - Unset fields: omitted from JSON when struct field has omitempty tag +// - Null fields: serialized as "null" +// - Value fields: serialized as the actual value +// +// The omitempty behavior works because an empty map is considered +// a zero value by Go's JSON package. +func (n OptionalNullable[T]) MarshalJSON() ([]byte, error) { + if n.IsNull() { + return []byte("null"), nil + } + + return json.Marshal(n[true]) +} + +// UnmarshalJSON implements json.Unmarshaler. +// +// Behavior: +// - "null" in JSON: sets the field to null (IsSet=true, IsNull=true) +// - Any other value: sets the field to that value (IsSet=true, IsNull=false) +// - Missing from JSON: field remains unset (IsSet=false, IsNull=false) +func (n *OptionalNullable[T]) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, []byte("null")) { + n.Set(nil) + return nil + } + var v T + if err := json.Unmarshal(data, &v); err != nil { + return err + } + n.Set(&v) + return nil +} + +// NullableInterface defines the interface that all OptionalNullable[T] types implement. +// This interface provides untyped access to optional nullable values for reflection-based code. +type OptionalNullableInterface interface { + GetUntyped() (interface{}, bool) +} + +// AsOptionalNullable attempts to convert a reflect.Value to a OptionalNullableInterface. +// This is a helper function for reflection-based code that needs to check +// if a value implements the optional nullable interface pattern. +// +// Returns: +// - (nullable, true): if the value implements OptionalNullableInterface +// - (nil, false): if the value does not implement OptionalNullableInterface +// +// Example usage: +// +// if nullable, ok := AsOptionalNullable(reflectValue); ok { +// if value, isSet := nullable.GetUntyped(); isSet { +// // Handle the nullable value +// } +// } +func AsOptionalNullable(v reflect.Value) (OptionalNullableInterface, bool) { + // Check if the value can be converted to an interface first + if !v.CanInterface() { + return nil, false + } + + // Check if the underlying value is a nil map (unset nullable) + if v.Kind() == reflect.Map && v.IsNil() { + return nil, false + } + + if nullable, ok := v.Interface().(OptionalNullableInterface); ok { + return nullable, true + } + return nil, false +} diff --git a/internal/sdk/optionalnullable/optionalnullable_test.go b/internal/sdk/optionalnullable/optionalnullable_test.go new file mode 100644 index 0000000..e6e5a01 --- /dev/null +++ b/internal/sdk/optionalnullable/optionalnullable_test.go @@ -0,0 +1,1806 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package optionalnullable + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// Test helper function to create pointers from values +func ptrFrom[T any](value T) *T { + return &value +} + +// Test helper types for comprehensive testing +type TestStruct struct { + Name string `json:"name"` + Age int `json:"age"` +} + +type TestContainer struct { + StringField OptionalNullable[string] `json:"string_field,omitempty"` + IntField OptionalNullable[int] `json:"int_field,omitempty"` + SliceField OptionalNullable[[]string] `json:"slice_field,omitempty"` + StructField OptionalNullable[TestStruct] `json:"struct_field,omitempty"` +} + +// TestNewNullable tests the From constructor +func TestNewNullable(t *testing.T) { + t.Parallel() + t.Run("with string value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("test")) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "test", got) + }) + + t.Run("with nil pointer", func(t *testing.T) { + t.Parallel() + nullable := From[string](nil) + + assert.True(t, nullable.IsSet()) + assert.True(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "", got) // zero value for string + }) + + t.Run("with int value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom(42)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, 42, got) + }) + + t.Run("with slice value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom([]string{"a", "b", "c"})) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{"a", "b", "c"}, got) + }) + + t.Run("with empty slice", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom([]string{})) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{}, got) + }) + + t.Run("with struct value", func(t *testing.T) { + t.Parallel() + val := TestStruct{Name: "John", Age: 30} + nullable := From(&val) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + v, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, val, v) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, TestStruct{Name: "John", Age: 30}, got) + }) +} + +// TestNewNullableUnset tests the NewNullableUnset constructor +func TestNewNullableUnset(t *testing.T) { + t.Parallel() + t.Run("string type", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + + assert.False(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) // Unset is not null + + got, ok := nullable.GetOrZero() + assert.False(t, ok) + assert.Equal(t, "", got) // zero value for string + }) + + t.Run("int type", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[int] + + assert.False(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) // Unset is not null + + got, ok := nullable.GetOrZero() + assert.False(t, ok) + assert.Equal(t, 0, got) // zero value for int + }) + + t.Run("slice type", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[[]string] + + assert.False(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) // Unset is not null + + got, ok := nullable.GetOrZero() + assert.False(t, ok) + assert.Nil(t, got) // zero value for slice is nil + }) +} + +// TestIsNull tests the IsNull method +func TestIsNull(t *testing.T) { + t.Parallel() + t.Run("with value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("test")) + assert.False(t, nullable.IsNull()) + }) + + t.Run("with nil pointer", func(t *testing.T) { + t.Parallel() + nullable := From[string](nil) + assert.True(t, nullable.IsNull()) + }) + + t.Run("unset", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + assert.False(t, nullable.IsNull()) + }) +} + +// TestIsSet tests the IsSet method +func TestIsSet(t *testing.T) { + t.Parallel() + t.Run("with value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("test")) + assert.True(t, nullable.IsSet()) + }) + + t.Run("with nil pointer", func(t *testing.T) { + t.Parallel() + nullable := From[string](nil) + assert.True(t, nullable.IsSet()) + }) + + t.Run("unset", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + assert.False(t, nullable.IsSet()) + }) +} + +// TestGet tests the Get method +func TestGet(t *testing.T) { + t.Parallel() + t.Run("with string value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("test")) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "test", got) + }) + + t.Run("with nil pointer", func(t *testing.T) { + t.Parallel() + nullable := From[string](nil) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "", got) // zero value + }) + + t.Run("unset", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + + got, ok := nullable.GetOrZero() + assert.False(t, ok) + assert.Equal(t, "", got) // zero value + }) + + t.Run("with slice value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom([]string{"a", "b"})) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{"a", "b"}, got) + }) + + t.Run("with nil slice pointer", func(t *testing.T) { + t.Parallel() + nullable := From[[]string](nil) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Nil(t, got) // zero value for slice is nil + }) +} + +// TestPointer tests the Pointer method +func TestPointer(t *testing.T) { + t.Parallel() + t.Run("with value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("test")) + + ptr, ok := nullable.Get() + assert.True(t, ok) + assert.NotNil(t, ptr) + assert.Equal(t, "test", *ptr) + }) + + t.Run("with nil pointer", func(t *testing.T) { + t.Parallel() + nullable := From[string](nil) + + ptr, ok := nullable.Get() + assert.True(t, ok) + assert.Nil(t, ptr) + }) + + t.Run("unset", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + + ptr, ok := nullable.Get() + assert.False(t, ok) + assert.Nil(t, ptr) + }) +} + +// TestSet tests the Set method +func TestSet(t *testing.T) { + t.Parallel() + t.Run("set string value", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + + // Initially unset + assert.False(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) // Unset is not null + + // Set a value + nullable.Set(ptrFrom("test")) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "test", got) + }) + + t.Run("set int value", func(t *testing.T) { + t.Parallel() + nullable := OptionalNullable[int]{} + + nullable.Set(ptrFrom(42)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, 42, got) + }) + + t.Run("set slice value", func(t *testing.T) { + t.Parallel() + nullable := OptionalNullable[[]string]{} + + slice := []string{"a", "b"} + nullable.Set(ptrFrom(slice)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{"a", "b"}, got) + }) + + t.Run("set empty slice", func(t *testing.T) { + t.Parallel() + nullable := OptionalNullable[[]string]{} + + slice := []string{} + nullable.Set(ptrFrom(slice)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{}, got) + }) + + t.Run("overwrite existing value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("original")) + + // Verify original value + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "original", got) + + // Set new value + nullable.Set(ptrFrom("new")) + + got, ok = nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "new", got) + }) +} + +// TestUnset tests the Unset method +func TestUnset(t *testing.T) { + t.Parallel() + t.Run("unset from value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("test")) + + // Initially set + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + // Unset + nullable.Unset() + + assert.False(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) // After unset is not null + // Value is now internal to the map implementation + + got, ok := nullable.GetOrZero() + assert.False(t, ok) + assert.Equal(t, "", got) // zero value + }) + + t.Run("unset from nil", func(t *testing.T) { + t.Parallel() + nullable := From[string](nil) + + // Initially set to nil + assert.True(t, nullable.IsSet()) + assert.True(t, nullable.IsNull()) // Set to nil should be null + + // Unset + nullable.Unset() + + assert.False(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) // After unset is not null + }) + + t.Run("unset already unset", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + + // Initially unset + assert.False(t, nullable.IsSet()) + + // Unset again + nullable.Unset() + + assert.False(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) // Empty map is not null + }) +} + +// TestMarshalJSON tests JSON marshaling +func TestMarshalJSON(t *testing.T) { + t.Parallel() + t.Run("marshal string value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("test")) + + data, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, `"test"`, string(data)) + }) + + t.Run("marshal int value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom(42)) + + data, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, `42`, string(data)) + }) + + t.Run("marshal nil value", func(t *testing.T) { + t.Parallel() + nullable := From[string](nil) + + data, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, `null`, string(data)) + }) + + t.Run("marshal slice value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom([]string{"a", "b", "c"})) + + data, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, `["a","b","c"]`, string(data)) + }) + + t.Run("marshal empty slice", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom([]string{})) + + data, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, `[]`, string(data)) + }) + + t.Run("marshal struct value", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom(TestStruct{Name: "John", Age: 30})) + + data, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, `{"name":"John","age":30}`, string(data)) + }) + + // Note: Unset values are not tested here because the current implementation + // doesn't handle unset fields in marshaling (see TODO in the code) +} + +// TestUnmarshalJSON tests JSON unmarshaling +func TestUnmarshalJSON(t *testing.T) { + t.Parallel() + t.Run("unmarshal string value", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + err := json.Unmarshal([]byte(`"test"`), &nullable) + require.NoError(t, err) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "test", got) + }) + + t.Run("unmarshal int value", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[int] + err := json.Unmarshal([]byte(`42`), &nullable) + require.NoError(t, err) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, 42, got) + }) + + t.Run("unmarshal null value", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + err := json.Unmarshal([]byte(`null`), &nullable) + require.NoError(t, err) + + assert.True(t, nullable.IsSet()) + assert.True(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "", got) // zero value + }) + + t.Run("unmarshal slice value", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[[]string] + err := json.Unmarshal([]byte(`["a","b","c"]`), &nullable) + require.NoError(t, err) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{"a", "b", "c"}, got) + }) + + t.Run("unmarshal empty slice", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[[]string] + err := json.Unmarshal([]byte(`[]`), &nullable) + require.NoError(t, err) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{}, got) + }) + + t.Run("unmarshal struct value", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[TestStruct] + err := json.Unmarshal([]byte(`{"name":"John","age":30}`), &nullable) + require.NoError(t, err) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, TestStruct{Name: "John", Age: 30}, got) + }) + + t.Run("unmarshal invalid JSON", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + err := json.Unmarshal([]byte(`invalid`), &nullable) + assert.Error(t, err) + + // Ensure the nullable remains unset after error + assert.False(t, nullable.IsSet()) + }) + + t.Run("unmarshal invalid JSON for int", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[int] + err := json.Unmarshal([]byte(`"not_a_number"`), &nullable) + assert.Error(t, err) + + // Ensure the nullable remains unset after error + assert.False(t, nullable.IsSet()) + }) + + t.Run("unmarshal malformed JSON", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[TestStruct] + err := json.Unmarshal([]byte(`{invalid json`), &nullable) + assert.Error(t, err) + + // Ensure the nullable remains unset after error + assert.False(t, nullable.IsSet()) + }) +} + +// TestJSONRoundTrip tests marshaling and unmarshaling together +func TestJSONRoundTrip(t *testing.T) { + t.Parallel() + t.Run("string value round trip", func(t *testing.T) { + t.Parallel() + nullable1 := From(ptrFrom("test value")) + + // Marshal + data, err := json.Marshal(nullable1) + require.NoError(t, err) + + // Unmarshal + var nullable2 OptionalNullable[string] + err = json.Unmarshal(data, &nullable2) + require.NoError(t, err) + + // Compare + assert.Equal(t, nullable1.IsSet(), nullable2.IsSet()) + assert.Equal(t, nullable1.IsNull(), nullable2.IsNull()) + + got1, ok1 := nullable1.GetOrZero() + got2, ok2 := nullable2.GetOrZero() + assert.Equal(t, ok1, ok2) + assert.Equal(t, got1, got2) + }) + + t.Run("nil value round trip", func(t *testing.T) { + t.Parallel() + nullable1 := From[string](nil) + + // Marshal + data, err := json.Marshal(nullable1) + require.NoError(t, err) + + // Unmarshal + var nullable2 OptionalNullable[string] + err = json.Unmarshal(data, &nullable2) + require.NoError(t, err) + + // Compare + assert.Equal(t, nullable1.IsSet(), nullable2.IsSet()) + assert.Equal(t, nullable1.IsNull(), nullable2.IsNull()) + + got1, ok1 := nullable1.GetOrZero() + got2, ok2 := nullable2.GetOrZero() + assert.Equal(t, ok1, ok2) + assert.Equal(t, got1, got2) + }) + + t.Run("slice round trip", func(t *testing.T) { + t.Parallel() + nullable1 := From(ptrFrom([]string{"a", "b", "c"})) + + // Marshal + data, err := json.Marshal(nullable1) + require.NoError(t, err) + + // Unmarshal + var nullable2 OptionalNullable[[]string] + err = json.Unmarshal(data, &nullable2) + require.NoError(t, err) + + // Compare + assert.Equal(t, nullable1.IsSet(), nullable2.IsSet()) + assert.Equal(t, nullable1.IsNull(), nullable2.IsNull()) + + got1, ok1 := nullable1.GetOrZero() + got2, ok2 := nullable2.GetOrZero() + assert.Equal(t, ok1, ok2) + assert.Equal(t, got1, got2) + }) +} + +// TestJSONToJSONRoundTrip tests starting with JSON and ensuring we can serialize back to the same JSON +func TestJSONToJSONRoundTrip(t *testing.T) { + t.Parallel() + t.Run("string value JSON round trip", func(t *testing.T) { + t.Parallel() + originalJSON := `"hello world"` + + // Unmarshal from JSON + var nullable OptionalNullable[string] + err := json.Unmarshal([]byte(originalJSON), &nullable) + require.NoError(t, err) + + // Verify state + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "hello world", got) + + // Marshal back to JSON + resultJSON, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, originalJSON, string(resultJSON)) + }) + + t.Run("null value JSON round trip", func(t *testing.T) { + t.Parallel() + originalJSON := `null` + + // Unmarshal from JSON + var nullable OptionalNullable[string] + err := json.Unmarshal([]byte(originalJSON), &nullable) + require.NoError(t, err) + + // Verify state + assert.True(t, nullable.IsSet()) + assert.True(t, nullable.IsNull()) + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "", got) // zero value + + // Marshal back to JSON + resultJSON, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, originalJSON, string(resultJSON)) + }) + + t.Run("int value JSON round trip", func(t *testing.T) { + t.Parallel() + originalJSON := `42` + + // Unmarshal from JSON + var nullable OptionalNullable[int] + err := json.Unmarshal([]byte(originalJSON), &nullable) + require.NoError(t, err) + + // Verify state + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, 42, got) + + // Marshal back to JSON + resultJSON, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, originalJSON, string(resultJSON)) + }) + + t.Run("slice value JSON round trip", func(t *testing.T) { + t.Parallel() + originalJSON := `["a","b","c"]` + + // Unmarshal from JSON + var nullable OptionalNullable[[]string] + err := json.Unmarshal([]byte(originalJSON), &nullable) + require.NoError(t, err) + + // Verify state + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{"a", "b", "c"}, got) + + // Marshal back to JSON + resultJSON, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, originalJSON, string(resultJSON)) + }) + + t.Run("empty slice JSON round trip", func(t *testing.T) { + t.Parallel() + originalJSON := `[]` + + // Unmarshal from JSON + var nullable OptionalNullable[[]string] + err := json.Unmarshal([]byte(originalJSON), &nullable) + require.NoError(t, err) + + // Verify state + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{}, got) + + // Marshal back to JSON + resultJSON, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, originalJSON, string(resultJSON)) + }) + + t.Run("struct value JSON round trip", func(t *testing.T) { + t.Parallel() + originalJSON := `{"name":"Alice","age":25}` + + // Unmarshal from JSON + var nullable OptionalNullable[TestStruct] + err := json.Unmarshal([]byte(originalJSON), &nullable) + require.NoError(t, err) + + // Verify state + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, TestStruct{Name: "Alice", Age: 25}, got) + + // Marshal back to JSON + resultJSON, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, originalJSON, string(resultJSON)) + }) +} + +// TestContainerStates tests comprehensive state detection and serialization with TestContainer +func TestContainerStates(t *testing.T) { + t.Parallel() + t.Run("all fields set to values", func(t *testing.T) { + t.Parallel() + container := TestContainer{ + StringField: From(ptrFrom("hello")), + IntField: From(ptrFrom(42)), + SliceField: From(ptrFrom([]string{"a", "b"})), + StructField: From(ptrFrom(TestStruct{Name: "John", Age: 30})), + } + + // Verify all fields are set and not null + assert.True(t, container.StringField.IsSet()) + assert.False(t, container.StringField.IsNull()) + assert.True(t, container.IntField.IsSet()) + assert.False(t, container.IntField.IsNull()) + assert.True(t, container.SliceField.IsSet()) + assert.False(t, container.SliceField.IsNull()) + assert.True(t, container.StructField.IsSet()) + assert.False(t, container.StructField.IsNull()) + + // Verify values + stringVal, ok := container.StringField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "hello", stringVal) + + intVal, ok := container.IntField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, 42, intVal) + + sliceVal, ok := container.SliceField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{"a", "b"}, sliceVal) + + structVal, ok := container.StructField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, TestStruct{Name: "John", Age: 30}, structVal) + + // Test JSON serialization + data, err := json.Marshal(container) + require.NoError(t, err) + + var result map[string]interface{} + err = json.Unmarshal(data, &result) + require.NoError(t, err) + + assert.Equal(t, "hello", result["string_field"]) + assert.Equal(t, float64(42), result["int_field"]) // JSON numbers are float64 + assert.Equal(t, []interface{}{"a", "b"}, result["slice_field"]) + structResult := result["struct_field"].(map[string]interface{}) + assert.Equal(t, "John", structResult["name"]) + assert.Equal(t, float64(30), structResult["age"]) + }) + + t.Run("all fields set to nil", func(t *testing.T) { + t.Parallel() + container := TestContainer{ + StringField: From[string](nil), + IntField: From[int](nil), + SliceField: From[[]string](nil), + StructField: From[TestStruct](nil), + } + + // Verify all fields are set but null + assert.True(t, container.StringField.IsSet()) + assert.True(t, container.StringField.IsNull()) + assert.True(t, container.IntField.IsSet()) + assert.True(t, container.IntField.IsNull()) + assert.True(t, container.SliceField.IsSet()) + assert.True(t, container.SliceField.IsNull()) + assert.True(t, container.StructField.IsSet()) + assert.True(t, container.StructField.IsNull()) + + // Verify GetOrZero() behavior for nil values + stringVal, ok := container.StringField.GetOrZero() + assert.True(t, ok) // set to nil still returns true + assert.Equal(t, "", stringVal) // zero value + + intVal, ok := container.IntField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, 0, intVal) // zero value + + sliceVal, ok := container.SliceField.GetOrZero() + assert.True(t, ok) + assert.Nil(t, sliceVal) // zero value for slice is nil + + structVal, ok := container.StructField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, TestStruct{}, structVal) // zero value + + // Test JSON serialization - all should be null + data, err := json.Marshal(container) + require.NoError(t, err) + + var result map[string]interface{} + err = json.Unmarshal(data, &result) + require.NoError(t, err) + + assert.Nil(t, result["string_field"]) + assert.Nil(t, result["int_field"]) + assert.Nil(t, result["slice_field"]) + assert.Nil(t, result["struct_field"]) + }) + + t.Run("all fields unset", func(t *testing.T) { + t.Parallel() + container := TestContainer{} + + // Verify all fields are unset + assert.False(t, container.StringField.IsSet()) + assert.False(t, container.StringField.IsNull()) // unset is not null in new implementation + assert.False(t, container.IntField.IsSet()) + assert.False(t, container.IntField.IsNull()) + assert.False(t, container.SliceField.IsSet()) + assert.False(t, container.SliceField.IsNull()) + assert.False(t, container.StructField.IsSet()) + assert.False(t, container.StructField.IsNull()) + + // Verify GetOrZero() behavior for unset values + stringVal, ok := container.StringField.GetOrZero() + assert.False(t, ok) // unset returns false + assert.Equal(t, "", stringVal) // zero value + + intVal, ok := container.IntField.GetOrZero() + assert.False(t, ok) + assert.Equal(t, 0, intVal) // zero value + + sliceVal, ok := container.SliceField.GetOrZero() + assert.False(t, ok) + assert.Nil(t, sliceVal) // zero value + + structVal, ok := container.StructField.GetOrZero() + assert.False(t, ok) + assert.Equal(t, TestStruct{}, structVal) // zero value + + // Test JSON serialization - unset fields should be omitted due to omitempty + data, err := json.Marshal(container) + require.NoError(t, err) + + var result map[string]interface{} + err = json.Unmarshal(data, &result) + require.NoError(t, err) + + // With omitempty, unset fields should not appear in JSON + assert.NotContains(t, result, "string_field") + assert.NotContains(t, result, "int_field") + assert.NotContains(t, result, "slice_field") + assert.NotContains(t, result, "struct_field") + }) + + t.Run("slice field states: nil vs unset vs empty vs set", func(t *testing.T) { + t.Parallel() + // Test all possible slice states + nilSlice := TestContainer{ + SliceField: From[[]string](nil), // explicitly set to nil + } + unsetSlice := TestContainer{} // unset + emptySlice := TestContainer{ + SliceField: From(ptrFrom([]string{})), // empty slice + } + setSlice := TestContainer{ + SliceField: From(ptrFrom([]string{"a", "b"})), // slice with values + } + + // Verify nil slice + assert.True(t, nilSlice.SliceField.IsSet()) + assert.True(t, nilSlice.SliceField.IsNull()) + val, ok := nilSlice.SliceField.GetOrZero() + assert.True(t, ok) + assert.Nil(t, val) + + // Verify unset slice + assert.False(t, unsetSlice.SliceField.IsSet()) + assert.False(t, unsetSlice.SliceField.IsNull()) // Unset is not null + val, ok = unsetSlice.SliceField.GetOrZero() + assert.False(t, ok) + assert.Nil(t, val) + + // Verify empty slice + assert.True(t, emptySlice.SliceField.IsSet()) + assert.False(t, emptySlice.SliceField.IsNull()) + val, ok = emptySlice.SliceField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{}, val) + + // Verify set slice + assert.True(t, setSlice.SliceField.IsSet()) + assert.False(t, setSlice.SliceField.IsNull()) + val, ok = setSlice.SliceField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, []string{"a", "b"}, val) + + // Test JSON serialization for each state + nilData, err := json.Marshal(nilSlice) + require.NoError(t, err) + assert.Contains(t, string(nilData), `"slice_field":null`) + + unsetData, err := json.Marshal(unsetSlice) + require.NoError(t, err) + assert.NotContains(t, string(unsetData), "slice_field") // omitted due to omitempty + + emptyData, err := json.Marshal(emptySlice) + require.NoError(t, err) + assert.Contains(t, string(emptyData), `"slice_field":[]`) + + setData, err := json.Marshal(setSlice) + require.NoError(t, err) + assert.Contains(t, string(setData), `"slice_field":["a","b"]`) + }) + + t.Run("mixed states container", func(t *testing.T) { + t.Parallel() + container := TestContainer{ + StringField: From(ptrFrom("hello")), // set to value + IntField: From[int](nil), // set to nil + StructField: From(ptrFrom(TestStruct{Name: "Alice", Age: 25})), // set to value + } + + // Verify states + assert.True(t, container.StringField.IsSet()) + assert.False(t, container.StringField.IsNull()) + + assert.True(t, container.IntField.IsSet()) + assert.True(t, container.IntField.IsNull()) + + assert.False(t, container.SliceField.IsSet()) + assert.False(t, container.SliceField.IsNull()) // Unset is not null + + assert.True(t, container.StructField.IsSet()) + assert.False(t, container.StructField.IsNull()) + + // Test JSON serialization + data, err := json.Marshal(container) + require.NoError(t, err) + + var result map[string]interface{} + err = json.Unmarshal(data, &result) + require.NoError(t, err) + + assert.Equal(t, "hello", result["string_field"]) + assert.Nil(t, result["int_field"]) + assert.NotContains(t, result, "slice_field") // unset, so omitted + structResult := result["struct_field"].(map[string]interface{}) + assert.Equal(t, "Alice", structResult["name"]) + assert.Equal(t, float64(25), structResult["age"]) + }) + + t.Run("JSON unmarshaling preserves states", func(t *testing.T) { + t.Parallel() + // JSON with some fields missing, some null, some with values + jsonData := `{ + "string_field": "test", + "int_field": null, + "struct_field": {"name": "Bob", "age": 35} + }` + + var container TestContainer + err := json.Unmarshal([]byte(jsonData), &container) + require.NoError(t, err) + + // string_field: present with value + assert.True(t, container.StringField.IsSet()) + assert.False(t, container.StringField.IsNull()) + stringVal, ok := container.StringField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "test", stringVal) + + // int_field: present but null + assert.True(t, container.IntField.IsSet()) + assert.True(t, container.IntField.IsNull()) + intVal, ok := container.IntField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, 0, intVal) // zero value + + // slice_field: missing from JSON, should remain unset + assert.False(t, container.SliceField.IsSet()) + assert.False(t, container.SliceField.IsNull()) // Unset is not null + sliceVal, ok := container.SliceField.GetOrZero() + assert.False(t, ok) + assert.Nil(t, sliceVal) + + // struct_field: present with value + assert.True(t, container.StructField.IsSet()) + assert.False(t, container.StructField.IsNull()) + structVal, ok := container.StructField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, TestStruct{Name: "Bob", Age: 35}, structVal) + }) +} + +// TestNilVsUnsetDistinction tests the key feature of distinguishing nil from unset +func TestNilVsUnsetDistinction(t *testing.T) { + t.Parallel() + t.Run("explicit nil vs unset", func(t *testing.T) { + t.Parallel() + // Explicitly set to nil + explicitNil := From[string](nil) + + // Unset + var unset OptionalNullable[string] + + // Both are null, but only one is set + assert.True(t, explicitNil.IsNull()) + assert.True(t, explicitNil.IsSet()) + + assert.False(t, unset.IsNull()) // Unset is not null + assert.False(t, unset.IsSet()) + + // Get behavior differs + got1, ok1 := explicitNil.GetOrZero() + got2, ok2 := unset.GetOrZero() + + assert.True(t, ok1) // explicitly set to nil returns true + assert.False(t, ok2) // unset returns false + assert.Equal(t, "", got1) // both return zero value + assert.Equal(t, "", got2) + + // Get behavior differs + ptr1, ok1 := explicitNil.Get() + ptr2, ok2 := unset.Get() + + assert.True(t, ok1) // explicitly set to nil returns true + assert.False(t, ok2) // unset returns false + assert.Nil(t, ptr1) // both return nil pointer + assert.Nil(t, ptr2) + }) + + t.Run("empty slice vs nil slice vs unset", func(t *testing.T) { + t.Parallel() + // Empty slice + emptyNullable := From(ptrFrom([]string{})) + + // Nil slice + nilNullable := From[[]string](nil) + + // Unset + var unsetNullable OptionalNullable[[]string] + + // All have different characteristics + assert.True(t, emptyNullable.IsSet()) + assert.False(t, emptyNullable.IsNull()) + + assert.True(t, nilNullable.IsSet()) + assert.True(t, nilNullable.IsNull()) + + assert.False(t, unsetNullable.IsSet()) + assert.False(t, unsetNullable.IsNull()) // Unset is not null + + // Get behavior + got1, ok1 := emptyNullable.GetOrZero() + got2, ok2 := nilNullable.GetOrZero() + got3, ok3 := unsetNullable.GetOrZero() + + assert.True(t, ok1) + assert.Equal(t, []string{}, got1) + + assert.True(t, ok2) + assert.Nil(t, got2) + + assert.False(t, ok3) + assert.Nil(t, got3) + }) +} + +// TestJSONOmitEmpty tests behavior with omitempty tag +func TestJSONOmitEmpty(t *testing.T) { + t.Parallel() + t.Run("marshal with omitempty", func(t *testing.T) { + t.Parallel() + // Test container with various nullable states + container := TestContainer{ + StringField: From(ptrFrom("test")), + IntField: From(ptrFrom(42)), + StructField: From[TestStruct](nil), // explicitly nil + } + + data, err := json.Marshal(container) + require.NoError(t, err) + + // Parse back to verify structure + var result map[string]interface{} + err = json.Unmarshal(data, &result) + require.NoError(t, err) + + // Should contain set fields + assert.Contains(t, result, "string_field") + assert.Contains(t, result, "int_field") + assert.Contains(t, result, "struct_field") + + // Should not contain unset field (due to omitempty) + // Note: This depends on how the marshaling handles unset fields + // The current implementation doesn't handle this case properly (see TODO) + }) + + t.Run("unmarshal missing fields", func(t *testing.T) { + t.Parallel() + // JSON with some fields missing + jsonData := `{"string_field": "test", "int_field": null}` + + var container TestContainer + err := json.Unmarshal([]byte(jsonData), &container) + require.NoError(t, err) + + // Present fields should be set + assert.True(t, container.StringField.IsSet()) + assert.False(t, container.StringField.IsNull()) + got, ok := container.StringField.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "test", got) + + // Null field should be set to nil + assert.True(t, container.IntField.IsSet()) + assert.True(t, container.IntField.IsNull()) + + // Missing fields should remain unset + assert.False(t, container.SliceField.IsSet()) + assert.False(t, container.StructField.IsSet()) + }) +} + +// TestEdgeCases tests various edge cases +func TestEdgeCases(t *testing.T) { + t.Parallel() + t.Run("zero values", func(t *testing.T) { + t.Parallel() + // Test with zero values that are not nil + intNullable := From(ptrFrom(0)) + stringNullable := From(ptrFrom("")) + + assert.True(t, intNullable.IsSet()) + assert.False(t, intNullable.IsNull()) + got, ok := intNullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, 0, got) + + assert.True(t, stringNullable.IsSet()) + assert.False(t, stringNullable.IsNull()) + got2, ok2 := stringNullable.GetOrZero() + assert.True(t, ok2) + assert.Equal(t, "", got2) + }) + + t.Run("pointer to pointer", func(t *testing.T) { + t.Parallel() + // Test with pointer to pointer type + inner := "test" + nullable := From(ptrFrom(&inner)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, &inner, got) + assert.Equal(t, "test", *got) + }) + + t.Run("complex struct", func(t *testing.T) { + t.Parallel() + complexStruct := struct { + Name string + Values []int + Metadata map[string]string + }{ + Name: "complex", + Values: []int{1, 2, 3}, + Metadata: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + } + + nullable := From(ptrFrom(complexStruct)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, complexStruct, got) + }) +} + +// TestDoublePointers tests comprehensive double pointer scenarios +func TestDoublePointers(t *testing.T) { + t.Parallel() + + t.Run("string double pointer with value", func(t *testing.T) { + t.Parallel() + inner := "hello world" + ptr := &inner + nullable := From(ptrFrom(ptr)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, ptr, got) + assert.Equal(t, &inner, got) + assert.Equal(t, "hello world", *got) + }) + + t.Run("int double pointer with value", func(t *testing.T) { + t.Parallel() + inner := 42 + ptr := &inner + nullable := From(ptrFrom(ptr)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, ptr, got) + assert.Equal(t, &inner, got) + assert.Equal(t, 42, *got) + }) + + t.Run("double pointer to nil", func(t *testing.T) { + t.Parallel() + var ptr *string = nil + nullable := From(ptrFrom(ptr)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, ptr, got) + assert.Nil(t, got) + }) + + t.Run("nil double pointer", func(t *testing.T) { + t.Parallel() + nullable := From[*string](nil) + + assert.True(t, nullable.IsSet()) + assert.True(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Nil(t, got) // zero value for **string is nil + }) + + t.Run("unset double pointer", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[*string] + + assert.False(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.False(t, ok) + assert.Nil(t, got) // zero value for **string is nil + }) + + t.Run("double pointer modification", func(t *testing.T) { + t.Parallel() + inner := "original" + ptr := &inner + nullable := From(ptrFrom(ptr)) + + // Verify original value + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "original", *got) + + // Modify through double pointer + *got = "modified" + assert.Equal(t, "modified", inner) + assert.Equal(t, "modified", *got) + }) + + t.Run("double pointer to struct", func(t *testing.T) { + t.Parallel() + inner := TestStruct{Name: "Alice", Age: 30} + ptr := &inner + nullable := From(ptrFrom(ptr)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, ptr, got) + assert.Equal(t, TestStruct{Name: "Alice", Age: 30}, *got) + + // Modify through double pointer + (*got).Name = "Bob" + assert.Equal(t, "Bob", inner.Name) + assert.Equal(t, "Bob", (*got).Name) + }) + + t.Run("double pointer to slice", func(t *testing.T) { + t.Parallel() + inner := []string{"a", "b", "c"} + ptr := &inner + nullable := From(ptrFrom(ptr)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, ptr, got) + assert.Equal(t, []string{"a", "b", "c"}, *got) + + // Modify through double pointer + *got = append(*got, "d") + assert.Equal(t, []string{"a", "b", "c", "d"}, inner) + assert.Equal(t, []string{"a", "b", "c", "d"}, *got) + }) + + t.Run("double pointer to empty slice", func(t *testing.T) { + t.Parallel() + inner := []string{} + ptr := &inner + nullable := From(ptrFrom(ptr)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, ptr, got) + assert.Equal(t, []string{}, *got) + }) + + t.Run("double pointer to nil slice", func(t *testing.T) { + t.Parallel() + var inner []string = nil + ptr := &inner + nullable := From(ptrFrom(ptr)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, ptr, got) + assert.Nil(t, *got) + }) + + t.Run("double pointer JSON marshaling", func(t *testing.T) { + t.Parallel() + inner := "json test" + ptr := &inner + nullable := From(ptrFrom(ptr)) + + data, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, `"json test"`, string(data)) + }) + + t.Run("double pointer JSON unmarshaling", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[*string] + err := json.Unmarshal([]byte(`"json test"`), &nullable) + require.NoError(t, err) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.NotNil(t, got) + assert.Equal(t, "json test", *got) + }) + + t.Run("double pointer JSON null marshaling", func(t *testing.T) { + t.Parallel() + nullable := From[*string](nil) + + data, err := json.Marshal(nullable) + require.NoError(t, err) + assert.Equal(t, `null`, string(data)) + }) + + t.Run("double pointer JSON null unmarshaling", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[*string] + err := json.Unmarshal([]byte(`null`), &nullable) + require.NoError(t, err) + + assert.True(t, nullable.IsSet()) + assert.True(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Nil(t, got) + }) + + t.Run("double pointer round trip", func(t *testing.T) { + t.Parallel() + inner := "round trip test" + ptr := &inner + nullable1 := From(ptrFrom(ptr)) + + // Marshal + data, err := json.Marshal(nullable1) + require.NoError(t, err) + + // Unmarshal + var nullable2 OptionalNullable[*string] + err = json.Unmarshal(data, &nullable2) + require.NoError(t, err) + + // Compare states + assert.Equal(t, nullable1.IsSet(), nullable2.IsSet()) + assert.Equal(t, nullable1.IsNull(), nullable2.IsNull()) + + got1, ok1 := nullable1.GetOrZero() + got2, ok2 := nullable2.GetOrZero() + assert.Equal(t, ok1, ok2) + + // Values should be equal + assert.Equal(t, *got1, *got2) + }) + + t.Run("triple pointer", func(t *testing.T) { + t.Parallel() + inner := "triple" + ptr1 := &inner + ptr2 := &ptr1 + nullable := From(ptrFrom(ptr2)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, ptr2, got) + assert.Equal(t, ptr1, *got) + assert.Equal(t, "triple", **got) + }) + + t.Run("double pointer set and unset", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[*string] + + // Initially unset + assert.False(t, nullable.IsSet()) + + // Set to double pointer + inner := "set test" + ptr := &inner + nullable.Set(ptrFrom(ptr)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "set test", *got) + + // Set to nil + nullable.Set(nil) + + assert.True(t, nullable.IsSet()) + assert.True(t, nullable.IsNull()) + + got, ok = nullable.GetOrZero() + assert.True(t, ok) + assert.Nil(t, got) + + // Unset + nullable.Unset() + + assert.False(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok = nullable.GetOrZero() + assert.False(t, ok) + assert.Nil(t, got) + }) + + t.Run("double pointer Get method", func(t *testing.T) { + t.Parallel() + inner := "get test" + ptr := &inner + nullable := From(ptrFrom(ptr)) + + // Test Get method + gotPtr, ok := nullable.Get() + assert.True(t, ok) + assert.NotNil(t, gotPtr) + assert.Equal(t, ptr, *gotPtr) + assert.Equal(t, "get test", **gotPtr) + + // Test with nil + nilNullable := From[*string](nil) + gotPtr, ok = nilNullable.Get() + assert.True(t, ok) + assert.Nil(t, gotPtr) + + // Test with unset + var unsetNullable OptionalNullable[*string] + gotPtr, ok = unsetNullable.Get() + assert.False(t, ok) + assert.Nil(t, gotPtr) + }) + + t.Run("double pointer zero values", func(t *testing.T) { + t.Parallel() + // Test with zero value string + inner := "" + ptr := &inner + nullable := From(ptrFrom(ptr)) + + assert.True(t, nullable.IsSet()) + assert.False(t, nullable.IsNull()) + + got, ok := nullable.GetOrZero() + assert.True(t, ok) + assert.Equal(t, "", *got) + + // Test with zero value int + innerInt := 0 + ptrInt := &innerInt + nullableInt := From(ptrFrom(ptrInt)) + + assert.True(t, nullableInt.IsSet()) + assert.False(t, nullableInt.IsNull()) + + gotInt, okInt := nullableInt.GetOrZero() + assert.True(t, okInt) + assert.Equal(t, 0, *gotInt) + }) +} + +// TestAsOptionalNullable tests the AsOptionalNullable helper function +func TestAsOptionalNullable(t *testing.T) { + t.Parallel() + + t.Run("with nullable string", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("test")) + reflectValue := reflect.ValueOf(nullable) + + result, ok := AsOptionalNullable(reflectValue) + assert.True(t, ok) + assert.NotNil(t, result) + + value, isSet := result.GetUntyped() + assert.True(t, isSet) + assert.Equal(t, "test", value) + }) + + t.Run("with nullable int", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom(42)) + reflectValue := reflect.ValueOf(nullable) + + result, ok := AsOptionalNullable(reflectValue) + assert.True(t, ok) + assert.NotNil(t, result) + + value, isSet := result.GetUntyped() + assert.True(t, isSet) + assert.Equal(t, 42, value) + }) + + t.Run("with nullable nil", func(t *testing.T) { + t.Parallel() + nullable := From[string](nil) + reflectValue := reflect.ValueOf(nullable) + + result, ok := AsOptionalNullable(reflectValue) + assert.True(t, ok) + assert.NotNil(t, result) + + value, isSet := result.GetUntyped() + assert.True(t, isSet) + assert.Nil(t, value) + }) + + t.Run("with unset nullable", func(t *testing.T) { + t.Parallel() + var nullable OptionalNullable[string] + reflectValue := reflect.ValueOf(nullable) + + result, ok := AsOptionalNullable(reflectValue) + assert.False(t, ok) + assert.Nil(t, result) + }) + + t.Run("with non-nullable string", func(t *testing.T) { + t.Parallel() + regularString := "not nullable" + reflectValue := reflect.ValueOf(regularString) + + result, ok := AsOptionalNullable(reflectValue) + assert.False(t, ok) + assert.Nil(t, result) + }) + + t.Run("with non-nullable int", func(t *testing.T) { + t.Parallel() + regularInt := 42 + reflectValue := reflect.ValueOf(regularInt) + + result, ok := AsOptionalNullable(reflectValue) + assert.False(t, ok) + assert.Nil(t, result) + }) + + t.Run("with non-nullable map", func(t *testing.T) { + t.Parallel() + regularMap := map[string]int{"key": 42} + reflectValue := reflect.ValueOf(regularMap) + + result, ok := AsOptionalNullable(reflectValue) + assert.False(t, ok) + assert.Nil(t, result) + }) + + t.Run("with non-nullable struct", func(t *testing.T) { + t.Parallel() + regularStruct := TestStruct{Name: "test", Age: 30} + reflectValue := reflect.ValueOf(regularStruct) + + result, ok := AsOptionalNullable(reflectValue) + assert.False(t, ok) + assert.Nil(t, result) + }) + + t.Run("with nullable double pointer", func(t *testing.T) { + t.Parallel() + inner := "test" + ptr := &inner + nullable := From(ptrFrom(ptr)) + reflectValue := reflect.ValueOf(nullable) + + result, ok := AsOptionalNullable(reflectValue) + assert.True(t, ok) + assert.NotNil(t, result) + + value, isSet := result.GetUntyped() + assert.True(t, isSet) + assert.Equal(t, ptr, value) + assert.Equal(t, "test", *value.(*string)) + }) + + t.Run("with nullable slice", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom([]string{"a", "b", "c"})) + reflectValue := reflect.ValueOf(nullable) + + result, ok := AsOptionalNullable(reflectValue) + assert.True(t, ok) + assert.NotNil(t, result) + + value, isSet := result.GetUntyped() + assert.True(t, isSet) + assert.Equal(t, []string{"a", "b", "c"}, value) + }) + + t.Run("with nullable struct", func(t *testing.T) { + t.Parallel() + testStruct := TestStruct{Name: "Alice", Age: 25} + nullable := From(ptrFrom(testStruct)) + reflectValue := reflect.ValueOf(nullable) + + result, ok := AsOptionalNullable(reflectValue) + assert.True(t, ok) + assert.NotNil(t, result) + + value, isSet := result.GetUntyped() + assert.True(t, isSet) + assert.Equal(t, testStruct, value) + }) + + t.Run("with pointer to nullable", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("test")) + ptrToNullable := &nullable + reflectValue := reflect.ValueOf(ptrToNullable) + + // This should work since the pointer to nullable still contains a nullable + result, ok := AsOptionalNullable(reflectValue) + assert.True(t, ok) + assert.NotNil(t, result) + + value, isSet := result.GetUntyped() + assert.True(t, isSet) + assert.Equal(t, "test", value) + }) + + t.Run("with interface containing nullable", func(t *testing.T) { + t.Parallel() + nullable := From(ptrFrom("test")) + var iface interface{} = nullable + reflectValue := reflect.ValueOf(iface) + + result, ok := AsOptionalNullable(reflectValue) + assert.True(t, ok) + assert.NotNil(t, result) + + value, isSet := result.GetUntyped() + assert.True(t, isSet) + assert.Equal(t, "test", value) + }) +} diff --git a/internal/sdk/sdk.go b/internal/sdk/sdk.go index 5db0da2..0ff6996 100644 --- a/internal/sdk/sdk.go +++ b/internal/sdk/sdk.go @@ -2,9 +2,12 @@ package sdk +// Generated from OpenAPI doc version 0.0.1 and generator version 2.788.7 + import ( "context" "fmt" + "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/internal/config" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/internal/hooks" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/internal/utils" "github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk/models/shared" @@ -18,7 +21,7 @@ var ServerList = []string{ "https://design-builder-api.sls.epilot.io", } -// HTTPClient provides an interface for suplying the SDK with a custom HTTP client +// HTTPClient provides an interface for supplying the SDK with a custom HTTP client type HTTPClient interface { Do(req *http.Request) (*http.Response, error) } @@ -44,34 +47,13 @@ func Float64(f float64) *float64 { return &f } // Pointer provides a helper function to return a pointer to a type func Pointer[T any](v T) *T { return &v } -type sdkConfiguration struct { - Client HTTPClient - Security func(context.Context) (interface{}, error) - ServerURL string - ServerIndex int - Language string - OpenAPIDocVersion string - SDKVersion string - GenVersion string - UserAgent string - RetryConfig *retry.Config - Hooks *hooks.Hooks - Timeout *time.Duration -} - -func (c *sdkConfiguration) GetServerDetails() (string, map[string]string) { - if c.ServerURL != "" { - return c.ServerURL, nil - } - - return ServerList[c.ServerIndex], nil -} - type SDK struct { + SDKVersion string // Available design-builder over designs provided by Design Builder v2 DesignBuilder *DesignBuilder - sdkConfiguration sdkConfiguration + sdkConfiguration config.SDKConfiguration + hooks *hooks.Hooks } type SDKOption func(*SDK) @@ -144,14 +126,12 @@ func WithTimeout(timeout time.Duration) SDKOption { // New creates a new instance of the SDK with the provided options func New(opts ...SDKOption) *SDK { sdk := &SDK{ - sdkConfiguration: sdkConfiguration{ - Language: "go", - OpenAPIDocVersion: "0.0.1", - SDKVersion: "0.14.2", - GenVersion: "2.497.0", - UserAgent: "speakeasy-sdk/terraform 0.14.2 2.497.0 0.0.1 github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk", - Hooks: hooks.New(), + SDKVersion: "0.15.0", + sdkConfiguration: config.SDKConfiguration{ + UserAgent: "speakeasy-sdk/terraform 0.15.0 2.788.7 0.0.1 github.com/epilot-dev/terraform-provider-epilot-designbuilder/internal/sdk", + ServerList: ServerList, }, + hooks: hooks.New(), } for _, opt := range opts { opt(sdk) @@ -164,12 +144,12 @@ func New(opts ...SDKOption) *SDK { currentServerURL, _ := sdk.sdkConfiguration.GetServerDetails() serverURL := currentServerURL - serverURL, sdk.sdkConfiguration.Client = sdk.sdkConfiguration.Hooks.SDKInit(currentServerURL, sdk.sdkConfiguration.Client) - if serverURL != currentServerURL { + serverURL, sdk.sdkConfiguration.Client = sdk.hooks.SDKInit(currentServerURL, sdk.sdkConfiguration.Client) + if currentServerURL != serverURL { sdk.sdkConfiguration.ServerURL = serverURL } - sdk.DesignBuilder = newDesignBuilder(sdk.sdkConfiguration) + sdk.DesignBuilder = newDesignBuilder(sdk, sdk.sdkConfiguration, sdk.hooks) return sdk } diff --git a/internal/validators/float32validators/not_null.go b/internal/validators/float32validators/not_null.go new file mode 100644 index 0000000..c9a8973 --- /dev/null +++ b/internal/validators/float32validators/not_null.go @@ -0,0 +1,49 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package float32validators + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ validator.Float32 = Float32NotNullValidator{} + +// Float32NotNullValidator validates that an attribute is not null. Most +// attributes should set Required: true instead, however in certain scenarios, +// such as a computed nested attribute, all underlying attributes must also be +// computed for planning to not show unexpected differences. +type Float32NotNullValidator struct{} + +// Description describes the validation in plain text formatting. +func (v Float32NotNullValidator) Description(_ context.Context) string { + return "value must be configured" +} + +// MarkdownDescription describes the validation in Markdown formatting. +func (v Float32NotNullValidator) MarkdownDescription(ctx context.Context) string { + return v.Description(ctx) +} + +// Validate performs the validation. +func (v Float32NotNullValidator) ValidateFloat32(ctx context.Context, req validator.Float32Request, resp *validator.Float32Response) { + if !req.ConfigValue.IsNull() { + return + } + + resp.Diagnostics.AddAttributeError( + req.Path, + "Missing Attribute Value", + req.Path.String()+": "+v.Description(ctx), + ) +} + +// NotNull returns an validator which ensures that the attribute is +// configured. Most attributes should set Required: true instead, however in +// certain scenarios, such as a computed nested attribute, all underlying +// attributes must also be computed for planning to not show unexpected +// differences. +func NotNull() validator.Float32 { + return Float32NotNullValidator{} +} diff --git a/internal/validators/int32validators/not_null.go b/internal/validators/int32validators/not_null.go new file mode 100644 index 0000000..ec9a3f1 --- /dev/null +++ b/internal/validators/int32validators/not_null.go @@ -0,0 +1,49 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package int32validators + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ validator.Int32 = Int32NotNullValidator{} + +// Int32NotNullValidator validates that an attribute is not null. Most +// attributes should set Required: true instead, however in certain scenarios, +// such as a computed nested attribute, all underlying attributes must also be +// computed for planning to not show unexpected differences. +type Int32NotNullValidator struct{} + +// Description describes the validation in plain text formatting. +func (v Int32NotNullValidator) Description(_ context.Context) string { + return "value must be configured" +} + +// MarkdownDescription describes the validation in Markdown formatting. +func (v Int32NotNullValidator) MarkdownDescription(ctx context.Context) string { + return v.Description(ctx) +} + +// Validate performs the validation. +func (v Int32NotNullValidator) ValidateInt32(ctx context.Context, req validator.Int32Request, resp *validator.Int32Response) { + if !req.ConfigValue.IsNull() { + return + } + + resp.Diagnostics.AddAttributeError( + req.Path, + "Missing Attribute Value", + req.Path.String()+": "+v.Description(ctx), + ) +} + +// NotNull returns an validator which ensures that the attribute is +// configured. Most attributes should set Required: true instead, however in +// certain scenarios, such as a computed nested attribute, all underlying +// attributes must also be computed for planning to not show unexpected +// differences. +func NotNull() validator.Int32 { + return Int32NotNullValidator{} +}