([FromQuery] DownloadRequest body)
| 46 | } |
| 47 | |
| 48 | [HttpGet("/api/_export/download")] |
| 49 | public async Task<IActionResult> Download([FromQuery] DownloadRequest body) |
| 50 | { |
| 51 | if (!body.StartDate.HasValue || !body.EndDate.HasValue) |
| 52 | { |
| 53 | return BadRequest(); |
| 54 | } |
| 55 | |
| 56 | var startDate = body.StartDate.Value; |
| 57 | var endDate = body.EndDate.Value; |
| 58 | |
| 59 | var (formatName, contentType, fileExtension) = GetFormat(body.Format); |
| 60 | var appName = UnsafeCharacters().Replace(body.AppName, "").ToLower(); |
| 61 | var fileName = $"{appName}-{body.BuildMode.ToLower()}-{startDate:yyyy-MM-dd}.{fileExtension}"; |
| 62 | |
| 63 | var countQuery = $@"SELECT COUNT(*) as event_count |
| 64 | FROM events |
| 65 | WHERE app_id = '{GetAppId(body.BuildMode, body.AppId)}' |
| 66 | AND timestamp BETWEEN '{startDate:yyyy-MM-dd HH:mm:ss}' AND '{endDate:yyyy-MM-dd HH:mm:ss}' |
| 67 | FORMAT JSON"; |
| 68 | |
| 69 | using var stream = await _queryClient.StreamResponseAsync(countQuery, HttpContext.RequestAborted); |
| 70 | long eventCount = 0; |
| 71 | using var reader = new StreamReader(stream); |
| 72 | var jsonString = await reader.ReadToEndAsync(); |
| 73 | using var doc = JsonDocument.Parse(jsonString); |
| 74 | var root = doc.RootElement; |
| 75 | |
| 76 | if (root.TryGetProperty("data", out JsonElement data) && |
| 77 | data.GetArrayLength() > 0 && |
| 78 | data[0].TryGetProperty("event_count", out JsonElement countElement)) |
| 79 | { |
| 80 | switch (countElement.ValueKind) |
| 81 | { |
| 82 | case JsonValueKind.Number: |
| 83 | _ = countElement.TryGetInt64(out eventCount); |
| 84 | break; |
| 85 | case JsonValueKind.String: |
| 86 | var countString = countElement.GetString(); |
| 87 | _ = long.TryParse(countString, out eventCount); |
| 88 | break; |
| 89 | default: |
| 90 | throw new InvalidOperationException($"Unexpected event_count type: {countElement.ValueKind}"); |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | if (formatName == "Parquet") |
| 95 | { |
| 96 | var query = $@"SELECT timestamp, user_id, session_id, |
| 97 | event_name, |
| 98 | replace(replace(string_props, '\u0022', '\''), '\u0027', '\'') as string_props, |
| 99 | numeric_props, |
| 100 | os_name, os_version, |
| 101 | locale, app_version, app_build_number, |
| 102 | engine_name, engine_version, |
| 103 | country_code, {COUNTRY_NAME_COLUMN}, region_name |
| 104 | FROM events |
| 105 | WHERE app_id = '{GetAppId(body.BuildMode, body.AppId)}' |
nothing calls this directly
no test coverage detected