Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions .swiftlint.yml

This file was deleted.

This file was deleted.

This file was deleted.

16 changes: 7 additions & 9 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
// swift-tools-version: 5.10
// The swift-tools-version declares the minimum version of Swift required to build this package.
// swift-tools-version: 6.0

import PackageDescription

let package = Package(
name: "UUIDV7",
platforms: [.visionOS(.v1), .iOS(.v12)],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "UUIDV7",
targets: ["UUIDV7"])
targets: ["UUIDV7"]
)
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "UUIDV7"),
name: "UUIDV7"
),
.testTarget(
name: "UUIDV7Tests",
dependencies: ["UUIDV7"])
dependencies: ["UUIDV7"]
),
]
)
6 changes: 5 additions & 1 deletion Sources/UUIDV7/String+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ extension String {
let regex = try? NSRegularExpression(pattern: pattern, options: [])
let range = NSRange(location: 0, length: count)

return regex?.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: "$1-$2-$3-$4-$5") ?? self
return regex?.stringByReplacingMatches(
in: self,
options: [],
range: range, withTemplate: "$1-$2-$3-$4-$5"
) ?? self
}
}
6 changes: 3 additions & 3 deletions Sources/UUIDV7/UUIDV7.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

import Foundation

public extension UUID {
extension UUID {

/// Generate a UUID Version 7 string
/// - Parameter withHyphens: Format the string with hypens
/// - Returns: A UUID Version 7 string
static func uuidV7String(withHyphens: Bool = true) -> String {
public static func uuidV7String(withHyphens: Bool = true) -> String {
let timestamp = Date().timeIntervalSince1970
let unixTimeMilliseconds = UInt64(timestamp * 1000)
let timeBytes = unixTimeMilliseconds.bigEndianData.suffix(6) // First 6 bytes for the timestamp
let timeBytes = unixTimeMilliseconds.bigEndianData.suffix(6) // First 6 bytes for the timestamp

// Prepare the random part (10 bytes to complete the UUID)
let randomBytes = Data((0..<10).map { _ in UInt8.random(in: 0...255) })
Expand Down
28 changes: 16 additions & 12 deletions Tests/UUIDV7Tests/UUIDV7Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
// Copyright © nthState Ltd. 2024. All rights reserved.
//

@testable import UUIDV7
import XCTest

final class UUIDv7GeneratorTests: XCTestCase {

func testGeneratedUUIDv7IsValidFormat() {
import Foundation
import Testing
import UUIDV7

@Suite
struct UUIDv7GeneratorTests {
@Test
func generatedUUIDv7IsValidFormat() {
let uuid = UUID.uuidV7String()

print("UUID: \(uuid)")
Expand All @@ -18,28 +20,30 @@ final class UUIDv7GeneratorTests: XCTestCase {
let range = NSRange(location: 0, length: uuid.count)
let matches = regex?.numberOfMatches(in: uuid, options: [], range: range)

XCTAssertEqual(matches, 1, "Generated UUIDv7 should match the expected format")
#expect(matches == 1, "Generated UUIDv7 should match the expected format")
}

func testGeneratedUUIDv7IsDifferentEachTime() {
@Test
func generatedUUIDv7IsDifferentEachTime() {
let uuid1 = UUID.uuidV7String()
let uuid2 = UUID.uuidV7String()

print("UUID:1 \(uuid1)")
print("UUID:2 \(uuid2)")

XCTAssertNotEqual(uuid1, uuid2, "Generated UUIDv7 should be different each time")
#expect(uuid1 != uuid2, "Generated UUIDv7 should be different each time")
}

func testGeneratedUUIDv7IsLexicallyTimeSortable() {
@Test
func generatedUUIDv7IsLexicallyTimeSortable() async throws {
let uuid1 = UUID.uuidV7String()
Thread.sleep(forTimeInterval: 0.05) // Wait for a few milliseconds
try await Task.sleep(nanoseconds: 5) // Wait for a few milliseconds
let uuid2 = UUID.uuidV7String()

print("UUID:1 \(uuid1)")
print("UUID:2 \(uuid2)")

// Directly compare the string representations
XCTAssertLessThan(uuid1, uuid2, "UUIDv7s should be lexically time-sortable")
#expect(uuid1 < uuid2, "UUIDv7s should be lexically time-sortable")
}
}