@@ -168,4 +168,75 @@ function read_gsheet(spreadsheet_id::String;
168
168
169
169
return df
170
170
end
171
-
171
+
172
+ """
173
+ $docstring_write_gsheet
174
+ """
175
+ function write_gsheet (data:: DataFrame , spreadsheet_id:: String ; sheet:: String = " Sheet1" , range:: String = " " , missing_value:: String = " " , append:: Bool = false )
176
+ # URL-escape spreadsheet_id if necessary by extracting it from a full URL.
177
+ if occursin (" spreadsheets/d/" , spreadsheet_id)
178
+ m = match (r" spreadsheets/d/([^/]+)" , spreadsheet_id)
179
+ if m != = nothing
180
+ spreadsheet_id = m. captures[1 ]
181
+ end
182
+ end
183
+
184
+ # Use a default range if none is provided.
185
+ if isempty (range)
186
+ range = " A1"
187
+ end
188
+
189
+ # If appending, use only the sheet name; if not, use "sheet!range".
190
+ loc = append ? sheet : sheet * " !" * range
191
+ loc = HTTP. escapeuri (loc)
192
+
193
+ headers = [" Authorization" => " Bearer $(GSHEET_AUTH[]. access_token) " , " Content-Type" => " application/json" ]
194
+
195
+ # Convert the DataFrame to a JSON object replacing missing values.
196
+ col_names = [string (c) for c in names (data)]
197
+ rows_data = [map (x -> ismissing (x) ? missing_value : x, collect (row)) for row in eachrow (data)]
198
+ # If appending, do not include the header; otherwise, prepend the header.
199
+ rows = append ? rows_data : vcat ([col_names], rows_data)
200
+ body = Dict (" values" => rows)
201
+
202
+ if append
203
+ # For appending data, use the append endpoint with POST.
204
+ url = " https://sheets.googleapis.com/v4/spreadsheets/$spreadsheet_id /values/$loc :append?valueInputOption=USER_ENTERED&insertDataOption=INSERT_ROWS"
205
+ response = HTTP. post (url, headers, JSON3. write (body))
206
+ else
207
+ # For updating (overwriting) data, use the update endpoint with PUT.
208
+ url = " https://sheets.googleapis.com/v4/spreadsheets/$spreadsheet_id /values/$loc ?valueInputOption=USER_ENTERED"
209
+ response = HTTP. put (url, headers, JSON3. write (body))
210
+ end
211
+
212
+ if response. status != 200
213
+ error (" Failed to write to Google Sheets: $(String (response. body)) " )
214
+ end
215
+
216
+ # If not appending, clear out any cells below the new data.
217
+ if ! append
218
+ # Determine how many rows were written (including header).
219
+ new_N = length (rows)
220
+ # Helper function: convert a 1-indexed column number to its corresponding letter.
221
+ function col_letter (n:: Int )
222
+ s = " "
223
+ while n > 0
224
+ rem = (n - 1 ) % 26
225
+ s = Char (rem + ' A' ) * s
226
+ n = (n - 1 ) ÷ 26
227
+ end
228
+ return s
229
+ end
230
+ last_col = col_letter (length (col_names))
231
+ # Build a clear range from the row after new data to a high row (here, row 1000).
232
+ clear_range = " $(sheet) !A$(new_N+ 1 ) :$(last_col) 1000" # note the parentheses around sheet
233
+ clear_range = HTTP. escapeuri (clear_range)
234
+ clear_url = " https://sheets.googleapis.com/v4/spreadsheets/$spreadsheet_id /values/$clear_range :clear"
235
+ clear_response = HTTP. post (clear_url, headers, " {}" )
236
+ if clear_response. status != 200
237
+ error (" Failed to clear remaining cells: $(String (clear_response. body)) " )
238
+ end
239
+ end
240
+
241
+ return response
242
+ end
0 commit comments