How to combine type requirements security with enumeration security?

So, I am working on the level of abstraction of sql database in swift, and I want to write it as safe as possible. By this I mean that I would prefer to prevent someone from doing anything illegal in the database using my library.

One thing that I am not yet able to solve is how to make the conversion from Swift types to SQL data types 100% safe. Therefore, I will explain my current implementation and its shortcomings:

Thus, in SQL, many data types have parameters. For example, if you want to define a column as VARCHAR , you need to specify a parameter that represents the maximum length of a VARCHAR , such as VARCHAR(255) . We can say that VARCHAR is one of the primitive SQL data types, and VARCHAR(255) is a more specific data type. To present this in a safe way in swift, I created two protocols:

 public protocol PrimitiveDataType { associatedtype Options = Void } public protocol SpecifiedDataType { associatedtype Primitive: PrimitiveDataType static var options: Primitive.Options { get } static func from(primitive: Primitive) -> Self var primitive: Primitive { get } } 

So here is an example of PrimitiveDataType :

 extension String: PrimitiveDataType { public enum DatabaseStringType { case char(length: Int), varchar(limit: Int), text } public typealias Options = DatabaseStringType } 

And here is an example of SpecifiedDataType :

 struct Name { let value: String init?(_ value: String) { guard case 0...50 = value.characters.count else { return nil } self.value = value } } extension Name: SpecifiedDataType { static let options = String.DatabaseStringType.varchar(limit: 50) static func from(primitive: String) -> Name { return Name(primitive)! } var primitive: String { return value } } 

Now I can use the information elsewhere in the library to find out what type of database column is expected whenever a Name type is requested. This gives my library the ability to verify that database columns are always of the correct type.

I haven't written all this code yet, but it might look something like this:

 func createColumn<SDT: SpecifiedDataType>(ofType type: SDT) -> String { switch SDT.options { case let options as String.DatabaseStringType: switch options { case .text: return "TEXT" case .char(let length): return "CHAR(\(length))" case .varchar(let limit): return "VARCHAR(\(limit))" } case let length as UInt32.Options: // return something like UNSIGNED INTEGER(\(length)) or whatever // case etcetera } } 

There is only one small problem with this. The set of valid primitive data types is limited, but the set of possible implementations of the PrimitiveDataType protocol is unlimited, because I cannot create my own implementation of this protocol for anyone.

Therefore, for this reason, it would be better to use some kind of enum instead of a number of protocol implementations. Since no one can extend the enum that I create, so I can limit the parameters that I define as valid types. However, enumeration would create another problem that does not exist in my current implementation.

You see in my current implementation when someone implements SpecifiedDataType with their parameters defined like this:

 static let options = String.DatabaseStringType.varchar(limit: 50) 

I can trust that the compiler will force them to make their type compatible with the string by implementing the from(primitive: String) method and the primitive: String variable (computed). AFAIK, if I switch the protocol to enumeration, I will lose this security associated with the compiler.

So, I want all of the following:

  • A way for the developer to declare what type of sql data they want their type to match.
  • A way to get this developer to actually make his type compatible with this sql data type.
  • To ensure that the developer using my library cannot extend the list of sql data data types in any way, but can only use those that I defined for him / her.

So far I only know how to do the first two, but not the last, or the last, but not the first two. How to get all three?

+5
source share

Source: https://habr.com/ru/post/1261914/


All Articles