Giter Club home page Giter Club logo

swift-prefixed-type's Introduction

Prefixed: A type-safe, Codable struct for prefixed types

Tests

πŸ€” What is Prefixed for?

UUIDs are great, you can use them everywhere… but when you do so, it starts being hard to recognize where a UUID comes from.

A common pattern is to add readable prefixes to the UUIDs. This way, you can have user_ee505428-a17b-4935-b81c-266b81a63515 and post_d58a3f88-0493-458d-bd4b-a6ca4a2cc98c for example, making it easy to find which is which.

Writing this library, I wanted to keep it very simple and straight-forward. I also wanted the PrefixedUUIDs to be type-safe, meaning a UUID prefixed with user_ could not be used instead of a UUID prefixed by post_.

After writing PrefixedUUID, I realized prefixed UUIDs are just a subset of all the types we could want to prefix. That's why I made it more generic, by creating the Prefixed struct.

πŸ›  Features

These are the features of PrefixedUUIDs, but you can say the same with any other prefixed type.

  • Type safety: User.ID != Post.ID, even though they are stored the same way
  • Codable: (Encodable & Decodable) conformance
  • Practical: PrefixedUUIDs allow you to access the underlying UUID or the prefixed String, without storing anything more in memory or requiring expensive computations.
  • Convenient: Foundation's UUID extensions make it easy to work with PrefixedUUIDs
  • Type inference: Most of the time, you don't need to make associated types explicit
  • Lightweight: PrefixedUUIDs take (almost) as little space in memory as UUIDs do. String prefixes are stored once ever and dashes in the UUID are not stored. The only thing that's stored for each PrefixedUUID is a UUID (which directly stores bytes).
  • Case (in)sensitive: By default, prefixes are case sensitive, but with a simple option, you can choose for a prefix to be case insensitive.
  • Debugging: Failing to decode a Prefixed type shows a human-readable error:
    • "'usr_abcdef' is not prefixed by 'user_'"
    • "'USR_MONPQR' is not prefixed by 'user_' (case insensitive)"
    • "user_ABCD" with a Prefixed Int => "'ABCD' is not a valid `Int`"
    • "user_56C68C54" with a Prefixed UUID => "'56C68C54' is not a valid `UUID`"

πŸ“¦ Installation

Using Package.swift in another Swift Package

To use this package in a project, import the "prefixed-uuid" package like so:

dependencies: [
	// Other dependencies
	.package(
		name: "prefixed",
		url: "https://github.com/RemiBardon/swift-prefixed-type",
		.upToNextMajor(from: "2.0.0")
	),
],

Then add it to your target like so:

targets: [
	// ...
	.target(
		name: "<YourTarget>",
		dependencies: [
			// Other dependencies
			.product(name: "Prefixed", package: "prefixed"),
		]
	),
	// ...
]

In a full project

To add Prefixed to your project, go to your project's configuration, then go to the Swift Packages tab, click + and follow XCode's instructions (Assuming you use XCode). When you're asked for a URL, enter https://github.com/RemiBardon/swift-prefixed-type.

πŸ§‘β€πŸ’» Usage

The following uses PrefixedUUIDs, but you can use Prefixed<Prefix, Base> instead if you want.

First, create a type conforming to PrefixProtocol:

struct UserIDPrefix: PrefixProtocol {
	static var prefix: String { "user_" }
}

If you want the prefix to be case-insensitive, you can override the default (true) value:

struct CaseInsensitiveUserIDPrefix: PrefixProtocol {
	static var prefix: String { "lower_user_" }
	static var isCaseSensitive: Bool { false }
}

Then, use your new type as you would normally do:

struct User: Codable, Identifiable {
	typealias ID = PrefixedUUID<UserIDPrefix>
	let id: ID
}

Identifiable is not necessary, it's just here as a good practice. Codable is not necessary either, but you can use it: PrefixedUUID conforms to Codable.

There are many ways to create a PrefixedUUID:

  • Using the verbose initializer:

    let prefixedUUID = PrefixedUUID<UserIDPrefix>(uuid: UUID())
  • Using the default value (UUID()):

    let prefixedUUID = PrefixedUUID<UserIDPrefix>()
  • Using the convenient UUID extensions:

    let prefixedUUID = UUID().prefixed(by: UserIDPrefix.self)
  • The compiler can infer the type of your UUIDPrefix, so most of the time you just have to use .prefixed():

    let prefixedUUID: PrefixedUUID<UserIDPrefix> = UUID().prefixed()

⚠️ Warnings

  • Do not make an existing struct conform to PrefixProtocol: PrefixProtocol sets custom String and debug descriptions which would override the one you expect.

❌ Major versions migrations

From 1.X.X to 2.X.X

  • Package has been renamed from prefixed-uuid to prefixed
  • Package library has been renamed from PrefixedUUID to Prefixed
  • UUIDPrefix has been renamed to PrefixProtocol
    • UUIDPrefix.uuidPrefix has been renamed to PrefixProtocol.prefix
    • UUIDPrefix.uuidPrefixIsCaseSensitive has been renamed to PrefixProtocol.isCaseSensitive

πŸ—Ί Roadmap

As you would expect from a package this small, it is not actively developed. However, I still have a few things to add:

  • Generic Prefixed struct, to be UUID-independent
  • Swift documentation comments, to make the package more understandable
  • Continuous Integration, to be sure the package runs in all environments
  • Documentation page
  • (Installation guides for older Swift Package Manager versions)
  • (CONTRIBUTING guidelines)

βš–οΈ License

This package is provided under MIT License. For more information, see LICENSE.

swift-prefixed-type's People

Contributors

remibardon avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.