Skip to content

Commit

Permalink
Add QueryGranularity struct (#15)
Browse files Browse the repository at this point in the history
This struct is applicable everywhere a granularity is expected, such as Insight.groupby and CustomQuery.granularity. It replaces various implementations of the same concept.
  • Loading branch information
winsmith authored Jan 11, 2023
1 parent 74e94b0 commit 2c15bbd
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 64 deletions.
11 changes: 2 additions & 9 deletions Sources/DataTransferObjects/DTOs/DTOv2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public enum DTOv2 {
public var breakdownKey: String?

/// If set, group and count found signals by this time interval. Incompatible with breakdownKey
public var groupBy: InsightGroupByInterval?
public var groupBy: QueryGranularity?

/// How should this insight's data be displayed?
public var displayMode: InsightDisplayMode
Expand All @@ -229,7 +229,7 @@ public enum DTOv2 {
uniqueUser: Bool,
filters: [String: String],
breakdownKey: String?,
groupBy: InsightGroupByInterval?,
groupBy: QueryGranularity?,
displayMode: InsightDisplayMode,
isExpanded: Bool,
lastRunTime: TimeInterval?,
Expand Down Expand Up @@ -425,13 +425,6 @@ public enum InsightDisplayMode: String, Codable {
case pieChart
}

public enum InsightGroupByInterval: String, Codable {
case hour
case day
case week
case month
}

public extension DTOv2.Insight {
static func newTimeSeriesInsight(groupID: UUID) -> DTOv2.Insight {
DTOv2.Insight(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public extension DTOv1 {
public var breakdownKey: String?

/// If set, group and count found signals by this time interval. Incompatible with breakdownKey
public var groupBy: InsightGroupByInterval?
public var groupBy: QueryGranularity?

/// How should this insight's data be displayed?
public var displayMode: InsightDisplayMode
Expand All @@ -55,7 +55,7 @@ public extension DTOv1 {
/// Defines the result of an insight calculation
struct InsightCalculationResult: Identifiable, Codable {
public init(id: UUID, order: Double?, title: String, signalType: String?, uniqueUser: Bool, filters: [String: String],
rollingWindowSize _: TimeInterval, breakdownKey: String? = nil, groupBy: InsightGroupByInterval? = nil,
rollingWindowSize _: TimeInterval, breakdownKey: String? = nil, groupBy: QueryGranularity? = nil,
displayMode: InsightDisplayMode, isExpanded: Bool, data: [DTOv1.InsightData], calculatedAt: Date, calculationDuration: TimeInterval)
{
self.id = id
Expand Down Expand Up @@ -91,7 +91,7 @@ public extension DTOv1 {
public var breakdownKey: String?

/// If set, group and count found signals by this time interval. Incompatible with breakdownKey
public var groupBy: InsightGroupByInterval?
public var groupBy: QueryGranularity?

/// How should this insight's data be displayed?
public var displayMode: InsightDisplayMode
Expand Down
4 changes: 2 additions & 2 deletions Sources/DataTransferObjects/Models.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public struct TelemetryApp: Codable, Hashable, Identifiable {
public struct InsightDefinitionRequestBody: Codable {
public init(order: Double? = nil, title: String, signalType: String? = nil, uniqueUser: Bool,
filters: [String: String], rollingWindowSize: TimeInterval, breakdownKey: String? = nil,
groupBy: InsightGroupByInterval? = nil, displayMode: InsightDisplayMode, groupID: UUID? = nil, id: UUID? = nil, isExpanded: Bool)
groupBy: QueryGranularity? = nil, displayMode: InsightDisplayMode, groupID: UUID? = nil, id: UUID? = nil, isExpanded: Bool)
{
self.order = order
self.title = title
Expand Down Expand Up @@ -111,7 +111,7 @@ public struct InsightDefinitionRequestBody: Codable {
public var breakdownKey: String?

/// If set, group and count found signals by this time interval. Incompatible with breakdownKey
public var groupBy: InsightGroupByInterval?
public var groupBy: QueryGranularity?

/// How should this insight's data be displayed?
public var displayMode: InsightDisplayMode
Expand Down
54 changes: 4 additions & 50 deletions Sources/DataTransferObjects/Query/CustomQuery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Foundation
public struct CustomQuery: Codable, Hashable, Equatable {
public init(queryType: CustomQuery.QueryType, dataSource: String = "telemetry-signals",
descending: Bool? = nil, filter: Filter? = nil, intervals: [QueryTimeInterval]? = nil,
relativeIntervals: [RelativeTimeInterval]? = nil, granularity: CustomQuery.Granularity,
relativeIntervals: [RelativeTimeInterval]? = nil, granularity: QueryGranularity,
aggregations: [Aggregator]? = nil, postAggregations: [PostAggregator]? = nil,
limit: Int? = nil, context: QueryContext? = nil,
threshold: Int? = nil, metric: TopNMetricSpec? = nil,
Expand All @@ -29,7 +29,7 @@ public struct CustomQuery: Codable, Hashable, Equatable {

public init(queryType: CustomQuery.QueryType, dataSource: DataSource = .init(type: .table, name: "telemetry-signals"),
descending: Bool? = nil, filter: Filter? = nil, intervals: [QueryTimeInterval]? = nil,
relativeIntervals: [RelativeTimeInterval]? = nil, granularity: CustomQuery.Granularity,
relativeIntervals: [RelativeTimeInterval]? = nil, granularity: QueryGranularity,
aggregations: [Aggregator]? = nil, postAggregations: [PostAggregator]? = nil,
limit: Int? = nil, context: QueryContext? = nil,
threshold: Int? = nil, metric: TopNMetricSpec? = nil,
Expand Down Expand Up @@ -60,52 +60,6 @@ public struct CustomQuery: Codable, Hashable, Equatable {
case topN
}

public enum Granularity: String, Codable, Hashable, CaseIterable {
case all
case none
case second
case minute
case fifteen_minute
case thirty_minute
case hour
case day
case week
case month
case quarter
case year

enum CodingKeys: String, CodingKey {
case type
}

public init(from decoder: Decoder) throws {
let type: String

let singleValueContainer = try decoder.singleValueContainer()
if let singleValueType = try? singleValueContainer.decode(String.self) {
type = singleValueType
}

else {
let keyedContainer = try decoder.container(keyedBy: CodingKeys.self)
type = try keyedContainer.decode(String.self, forKey: .type)
}

for possibleCase in Self.allCases {
if type == possibleCase.rawValue {
self = possibleCase
return
}
}

throw DecodingError.dataCorrupted(.init(
codingPath: [],
debugDescription: "needs to be a string or a dict",
underlyingError: nil
))
}
}

public var queryType: QueryType
public var dataSource: DataSource = .init(type: .table, name: "telemetry-signals")
public var descending: Bool?
Expand All @@ -114,7 +68,7 @@ public struct CustomQuery: Codable, Hashable, Equatable {

/// If a relative intervals are set, their calculated output replaces the regular intervals
public var relativeIntervals: [RelativeTimeInterval]?
public let granularity: Granularity
public let granularity: QueryGranularity
public var aggregations: [Aggregator]?
public var postAggregations: [PostAggregator]?
public var limit: Int?
Expand Down Expand Up @@ -161,7 +115,7 @@ public struct CustomQuery: Codable, Hashable, Equatable {
self.descending = try container.decodeIfPresent(Bool.self, forKey: CustomQuery.CodingKeys.descending)
self.filter = try container.decodeIfPresent(Filter.self, forKey: CustomQuery.CodingKeys.filter)
self.relativeIntervals = try container.decodeIfPresent([RelativeTimeInterval].self, forKey: CustomQuery.CodingKeys.relativeIntervals)
self.granularity = try container.decode(CustomQuery.Granularity.self, forKey: CustomQuery.CodingKeys.granularity)
self.granularity = try container.decode(QueryGranularity.self, forKey: CustomQuery.CodingKeys.granularity)
self.aggregations = try container.decodeIfPresent([Aggregator].self, forKey: CustomQuery.CodingKeys.aggregations)
self.postAggregations = try container.decodeIfPresent([PostAggregator].self, forKey: CustomQuery.CodingKeys.postAggregations)
self.limit = try container.decodeIfPresent(Int.self, forKey: CustomQuery.CodingKeys.limit)
Expand Down
45 changes: 45 additions & 0 deletions Sources/DataTransferObjects/Query/QueryGranularity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
public enum QueryGranularity: String, Codable, Hashable, CaseIterable {
case all
case none
case second
case minute
case fifteen_minute
case thirty_minute
case hour
case day
case week
case month
case quarter
case year

enum CodingKeys: String, CodingKey {
case type
}

public init(from decoder: Decoder) throws {
let type: String

let singleValueContainer = try decoder.singleValueContainer()
if let singleValueType = try? singleValueContainer.decode(String.self) {
type = singleValueType
}

else {
let keyedContainer = try decoder.container(keyedBy: CodingKeys.self)
type = try keyedContainer.decode(String.self, forKey: .type)
}

for possibleCase in Self.allCases {
if type == possibleCase.rawValue {
self = possibleCase
return
}
}

throw DecodingError.dataCorrupted(.init(
codingPath: [],
debugDescription: "needs to be a string or a dict",
underlyingError: nil
))
}
}

0 comments on commit 2c15bbd

Please sign in to comment.