Skip to content

Commit

Permalink
feat: updated Point to be a sendable struct
Browse files Browse the repository at this point in the history
Deprecated addTag(key:value:), addField(key:value:), and time(time:) in favor of using the mutable properties.

BREAKING CHANGE: Point is now a value type which can cause breaking behaviour in code expecting the behaviour of a reference type.
BREAKING CHANGE: addTag(key:value:), addField(key:value:), and time(time:) have mutating versions when called and the result is discarded.
  • Loading branch information
CraigSiemens committed Jan 13, 2025
1 parent 7876126 commit dde52c8
Show file tree
Hide file tree
Showing 7 changed files with 439 additions and 259 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Package.resolved
#
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
# .swiftpm
.swiftpm

.build/

Expand Down
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## 1.8.0 [unreleased]
## 2.0.0 [unreleased]

### Features
1. [#69](https://github.com/influxdata/influxdb-client-swift/pull/69) and [#70](https://github.com/influxdata/influxdb-client-swift/pull/70): Updated `Point` to be a sendable struct

## 1.7.0 [2024-05-17]

Expand Down
2 changes: 1 addition & 1 deletion Sources/InfluxDBSwift/InfluxDBClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ extension InfluxDBClient {

/// An enum represents the precision for the unix timestamps within the body line-protocol.
/// - SeeAlso: https://docs.influxdata.com/influxdb/latest/write-data/#timestamp-precision
public enum TimestampPrecision: String, Codable, CaseIterable {
public enum TimestampPrecision: String, Codable, CaseIterable, Sendable {
/// Milliseconds
case ms
/// Seconds
Expand Down
169 changes: 107 additions & 62 deletions Sources/InfluxDBSwift/Point.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,62 +8,31 @@ extension InfluxDBClient {
/// Point defines the values that will be written to the database.
///
/// - SeeAlso: http://bit.ly/influxdata-point
public class Point {
public struct Point: Sendable {
/// The measurement name.
private let measurement: String
public let measurement: String
// The measurement tags.
private var tags: [String: String?] = [:]
public var tags: [String: String?]
// The measurement fields.
private var fields: [String: FieldValue?] = [:]
public var fields: [String: FieldValue?]
/// The data point time.
var time: TimestampValue?
public var time: TimestampValue?

/// Create a new Point with specified a measurement name and precision.
///
/// - Parameters:
/// - measurement: the measurement name
/// - precision: the data point precision
public init(_ measurement: String) {
public init(
_ measurement: String,
tags: [String: String?] = [:],
fields: [String: FieldValue?] = [:],
time: TimestampValue? = nil
) {
self.measurement = measurement
}

/// Adds or replaces a tag value for this point.
///
/// - Parameters:
/// - key: the tag name
/// - value: the tag value
/// - Returns: self
@discardableResult
public func addTag(key: String?, value: String?) -> Point {
if let key = key {
tags[key] = value
}
return self
}

/// Adds or replaces a field value for this point.
///
/// - Parameters:
/// - key: the field name
/// - value: the field value
/// - Returns: self
@discardableResult
public func addField(key: String?, value: FieldValue?) -> Point {
if let key = key {
fields[key] = value
}
return self
}

/// Updates the timestamp for the point.
///
/// - Parameters:
/// - time: the timestamp. It can be `Int` or `Date`.
/// - Returns: self
@discardableResult
public func time(time: TimestampValue) -> Point {
self.tags = tags
self.fields = fields
self.time = time
return self
}

/// Creates Line Protocol from Data Point.
Expand Down Expand Up @@ -134,7 +103,7 @@ extension InfluxDBClient {

extension InfluxDBClient.Point {
/// Possible value types of Field
public enum FieldValue {
public enum FieldValue: Sendable {
/// Support for Int8
init(_ value: Int8) {
self = .int(Int(value))
Expand Down Expand Up @@ -185,7 +154,7 @@ extension InfluxDBClient.Point {
}

/// Possible value types of Field
public enum TimestampValue: CustomStringConvertible {
public enum TimestampValue: CustomStringConvertible, Sendable {
// The number of ticks since the UNIX epoch. The value has to be specified with correct precision.
case interval(Int, InfluxDBClient.TimestampPrecision = InfluxDBClient.defaultTimestampPrecision)
// The date timestamp.
Expand All @@ -205,29 +174,22 @@ extension InfluxDBClient.Point {
extension InfluxDBClient.Point {
/// Tuple definition for construct `Point`.
public typealias Tuple = (measurement: String,
tags: [String?: String?]?,
fields: [String?: InfluxDBClient.Point.FieldValue?],
tags: [String: String?]?,
fields: [String: InfluxDBClient.Point.FieldValue?],
time: InfluxDBClient.Point.TimestampValue?)
/// Create a new Point from Tuple.
///
/// - Parameters:
/// - tuple: the tuple with keys: `measurement`, `tags`, `fields` and `time`
/// - precision: the data point precision
/// - Returns: created Point
public class func fromTuple(_ tuple: Tuple) -> InfluxDBClient.Point {
let point = InfluxDBClient.Point(tuple.measurement)
if let tags = tuple.tags {
for tag in tags {
point.addTag(key: tag.0, value: tag.1)
}
}
for field in tuple.fields {
point.addField(key: field.0, value: field.1)
}
if let time = tuple.time {
point.time(time: time)
}
return point
public static func fromTuple(_ tuple: Tuple) -> InfluxDBClient.Point {
.init(
tuple.measurement,
tags: tuple.tags ?? [:],
fields: tuple.fields,
time: tuple.time
)
}
}

Expand Down Expand Up @@ -386,3 +348,86 @@ extension InfluxDBClient.Point {
return " \(sinceEpoch)"
}
}

extension InfluxDBClient.Point {
/// Adds or replaces a tag value for this point.
///
/// - Parameters:
/// - key: the tag name
/// - value: the tag value
/// - Returns: self
@_disfavoredOverload
@available(*, deprecated, message: "Pass tags to Point.init or use the tags property")
public func addTag(key: String?, value: String?) -> Self {
var point = self
if let key = key {
point.tags[key] = value
}
return point
}

/// Adds or replaces a tag value for this point.
///
/// - Parameters:
/// - key: the tag name
/// - value: the tag value
/// - Returns: self
@available(*, deprecated, message: "Pass tags to Point.init or use the tags property")
public mutating func addTag(key: String?, value: String?) {
if let key = key {
tags[key] = value
}
}

/// Adds or replaces a field value for this point.
///
/// - Parameters:
/// - key: the field name
/// - value: the field value
/// - Returns: self
@_disfavoredOverload
@available(*, deprecated, message: "Pass fields to Point.init or use the fields property")
public func addField(key: String?, value: FieldValue?) -> Self {
var point = self
if let key = key {
point.fields[key] = value
}
return point
}

/// Adds or replaces a field value for this point.
///
/// - Parameters:
/// - key: the field name
/// - value: the field value
/// - Returns: self
@available(*, deprecated, message: "Pass fields to Point.init or use the fields property")
public mutating func addField(key: String?, value: FieldValue?) {
if let key = key {
fields[key] = value
}
}

/// Updates the timestamp for the point.
///
/// - Parameters:
/// - time: the timestamp. It can be `Int` or `Date`.
/// - Returns: self
@_disfavoredOverload
@available(*, deprecated, message: "Pass time to Point.init or use the time property")
public func time(time: TimestampValue) -> Self {
var point = self
point.time = time
return point
}

/// Updates the timestamp for the point.
///
/// - Parameters:
/// - time: the timestamp. It can be `Int` or `Date`.
/// - Returns: self
@available(*, deprecated, message: "Pass time to Point.init or use the time property")
public mutating func time(time: TimestampValue) {
self.time = time
}
}
60 changes: 38 additions & 22 deletions Tests/InfluxDBSwiftTests/IntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,15 @@ final class IntegrationTests: XCTestCase {
let measurement = "h2o_\(Date().timeIntervalSince1970)"

let points = Array(1...5).map {
InfluxDBClient.Point(measurement)
.addTag(key: "host", value: "aws")
.addTag(key: "location", value: "west")
.addField(key: "value", value: .int($0))
.time(time: .date(Date(2020, 7, $0)))
InfluxDBClient.Point(
measurement,
tags: [
"host": "aws",
"location": "west"
],
fields: ["value": .int($0)],
time: .date(Date(2020, 7, $0))
)
}

client.makeWriteAPI().write(points: points) { _, error in
Expand Down Expand Up @@ -92,23 +96,35 @@ final class IntegrationTests: XCTestCase {

let measurement = "h2o_\(Date().timeIntervalSince1970)"

let point1 = InfluxDBClient.Point(measurement)
.addTag(key: "host", value: "aws")
.addTag(key: "location", value: "west")
.addField(key: "value", value: .int(1))
.time(time: .date(Date(2020, 7, 1)))

let point2 = InfluxDBClient.Point(measurement)
.addTag(key: "host", value: "azure")
.addTag(key: "location", value: "west")
.addField(key: "value", value: .int(2))
.time(time: .date(Date(2020, 7, 2)))

let point3 = InfluxDBClient.Point(measurement)
.addTag(key: "host", value: "gc")
.addTag(key: "location", value: "west")
.addField(key: "value", value: .int(3))
.time(time: .date(Date(2020, 7, 3)))
let point1 = InfluxDBClient.Point(
measurement,
tags: [
"host": "aws",
"location": "west"
],
fields: ["value": .int(1)],
time: .date(Date(2020, 7, 1))
)

let point2 = InfluxDBClient.Point(
measurement,
tags: [
"host": "azure",
"location": "west"
],
fields: ["value": .int(2)],
time: .date(Date(2020, 7, 2))
)

let point3 = InfluxDBClient.Point(
measurement,
tags: [
"host": "gc",
"location": "west"
],
fields: ["value": .int(3)],
time: .date(Date(2020, 7, 3))
)

client.makeWriteAPI().write(points: [point1, point2, point3]) { _, error in
if let error = error {
Expand Down
Loading

0 comments on commit dde52c8

Please sign in to comment.