Lawrence  Lesch

Lawrence Lesch

1677700380

Generate Typescript interface Definitions From SQL Database Schema

Schemats

Using Schemats, you can generate TypeScript interface definitions from (Postgres, MySQL) SQL database schema automatically.

Start with a database schema:

Users
idSERIAL
usernameVARCHAR
passwordVARCHAR
last_logonTIMESTAMP

Automatically have the following TypesScript Interface generated

interface Users {
    id: number;
    username: string;
    password: string;
    last_logon: Date;
}

For an overview on the motivation and rational behind this project, please take a look at Statically typed PostgreSQL queries in Typescript .

Quick Start

Installing Schemats

npm install -g schemats

Generating the type definition from schema

schemats generate -c postgres://postgres@localhost/osm -t users -o osm.ts
schemats generate -c mysql://mysql@localhost/osm -t users -o osm.ts

The above commands will generate typescript interfaces for osm database with table users. The resulting file is stored as osm.ts.

Generating the type definition for all the tables in a postgres schema

To generate all type definitions for all the tables within the schema 'public':

Note: MySQL does not have a default public schema, but should it have a schema named public, this will still work.

schemats generate -c postgres://postgres@localhost/osm -s public -o osm.ts
schemats generate -c mysql://mysql@localhost/osm -s public -o osm.ts

If neither the table parameter nor the schema parameter is provided, all tables in schema 'public' will be generated, so the command above is equivalent to:

schemats generate -c postgres://postgres@localhost/osm -o osm.ts
schemats generate -c mysql://mysql@localhost/osm -o osm.ts

Using schemats.json config file

Schemats supports reading configuration from a json config file (defaults to schemats.json). Instead of passing configuration via commandline parameter like done above, it is also possible to supply the configuration through a config file. The config file supports the same parameters as the commandline arguments.

For example, if a schemats.json exists in the current working directory with the following content:

{
    "conn": "postgres://postgres@localhost/osm",
    "table": ["users"]
}

Running schemats generate here is equivalent to running schemats generate -c postgres://postgres@localhost/osm -t users -o osm.ts.

Writing code with typed schema

We can import osm.ts directly


// imports the _osm_ namespace from ./osm.ts

import * as osm from './osm'


// Now query with pg-promise and have a completely typed return value
  
let usersCreatedAfter2013: Array<osm.users>
   = await db.query("SELECT * FROM users WHERE creation_time >= '2013-01-01'");

// We can decide to only get selected fields

let emailOfUsersCreatedAfter2013: Array<{
    email: osm.users['email'],
    creation_time: osm.users['creation_time']
}> = await db.query("SELECT (email, creation_time) FROM users WHERE creation_time >= '2013-01-01'");

With generated type definition for our database schema, we can write code with autocompletion and static type checks.

demo 1

demo 2

Using schemats as a library

Schemats exposes two high-level functions for generating typescript definition from a database schema. They can be used by a build tool such as grunt and gulp.

Upgrading to v1.0

Deprecation of Namespace

Version 1.0 deprecates generating schema typescript files with namespace.

Instead of generating schema typescript files with

schemats generate -c postgres://postgres@localhost/db -n yournamespace -o db.ts

and import them with

import {yournamespace} from './db'

It is now encouraged to generate without namespace

schemats generate -c postgres://postgres@localhost/db -o db.ts

and import them with

import * as yournamespace from './db'
// or
import {table_a, table_b} from './db'

As TypeScript's documentation describes, having a top level namespace is needless. This was discussed in #25.

Generating schema typescript files with namespace still works in v1.0, but it is discouraged and subjected to removal in the future.

Support Strict Null-Checking

Version 1.0 supports strict null-checking and reflects the NOT NULL constraint defined in PostgreSQL schema.


Download Details:

Author: SweetIQ
Source Code: https://github.com/SweetIQ/schemats 
License: MIT license

#typescript #mysql #postgre #automation #reflection 

Generate Typescript interface Definitions From SQL Database Schema
Rupert  Beatty

Rupert Beatty

1673118960

Reflection Based Object Mapping with Extensions for Alamofire and Moya

EVReflection

General information

At this moment the master branch is tested with Swift 4.2 and 5.0 beta If you want to continue using EVReflection in an older version, then use the corresponding branch. Run the unit tests to see EVReflection in action.

Please update to cocoapods 1.7.0 for now you could do that using

sudo gem install cocoapods --pre

This is required for libraries that want to support other swift versions besides 5.0 For more information see the cocoapods blog

EVReflection is used in EVCloudKitDao and EVWordPressAPI

In most cases EVReflection is very easy to use. Just take a look the section It's easy to use. But if you do want to do non standard specific things, then EVReflection will offer you an extensive range of functionality.

Available extensions

There are extension available for using EVReflection with XMLDictionairy, Realm, CloudKit, Alamofire and Moya with RxSwift or ReactiveSwift

All these extens can be installed by adding something like this in your podfile:

pod 'EVReflection/MoyaRxSwift'

For Carthage there is not (yet) an extension for all above extension. If needed, please let me know. For carthage you can use:

github "evermeer/EVReflection" 

Index

Main features of EVReflection:

  • Parsing objects based on NSObject to and from a dictionary. (also see the XML and .plist samples!)
  • Parsing objects to and from a JSON string.
  • Support NSCoding function encodeWithCoder and decodeObjectWithCoder
  • Supporting Printable, Hashable and Equatable while using all properties.
  • Mapping objects from one type to an other
  • Support for property mapping, converters, validators and key cleanup

It's easy to use:

Defining an object. You only have to set EVObject as it's base class (or extend an NSObject with EVReflectable):

class User: EVObject {
    var id: Int = 0
    var name: String = ""
    var friends: [User]? = []
}

Parsing JSON to an object:

let json:String = "{\"id\": 24, \"name\": \"Bob Jefferson\", \"friends\": [{\"id\": 29, \"name\": \"Jen Jackson\"}]}"
let user = User(json: json)

Parsing JSON to an array of objects:

let json:String = "[{\"id\": 27, \"name\": \"Bob Jefferson\"}, {\"id\": 29, \"name\": \"Jen Jackson\"}]"
let array = [User](json: json)

Parsing from and to a dictionary:

let dict = user.toDictionary()
let newUser = User(dictionary: dict)
XCTAssert(user == newUser, "Pass")

Saving and loading an object to and from a file:

user.saveToTemp("temp.dat")
let result = User(fileNameInTemp: "temp.dat")
XCTAssert(theObject == result, "Pass")

Mapping object to another type:

let administrator: Administrator = user.mapObjectTo()

If you have XML instead of JSON

If you want to do the same but you have XML, then you can achieve that using the XML subspec 'pod EVReflection/XML' It is a simple way to parse XML. With that your code will look like this:

let xml = "<user><id>27</id><name>Bob</name><friends><user><id>20</id><name>Jen</name></user></friends></user>"
let user = User(xmlString: xml)

Using EVReflection in your own App

'EVReflection' is available through the dependency manager CocoaPods. You do have to use cocoapods version 0.36 or later

You can just add EVReflection to your workspace by adding the following 2 lines to your Podfile:

use_frameworks!
pod "EVReflection"

You can also use the Swift2.2 or Swift2.3 version of EVReflection. You can get that version by using the podfile command:

use_frameworks!
pod "EVReflection"', :git => 'https://github.com/evermeer/EVReflection.git', :branch => 'Swift2.2'

Version 0.36 of cocoapods will make a dynamic framework of all the pods that you use. Because of that it's only supported in iOS 8.0 or later. When using a framework, you also have to add an import at the top of your swift file like this:

import EVReflection

If you want support for older versions than iOS 8.0, then you can also just copy the files from the pod folder to your project. You do have to use the Swift2.3 version or older. iOS 7 support is dropped from Swift 3.

Be aware that when you have your object definitions in a framework and not in your main app, then you have to let EVReflection know that it should also look in that framework for your classes. This can easilly be done by using the following one liner (for instance in the appdelegate)

EVReflection.setBundleIdentifier(YourDataObject.self)

More Sample code

Clone EVReflection to your desktop to see these and more unit tests

func testEquatable() {
    var theObjectA = TestObject2()
    theObjectA.objectValue = "value1"
    var theObjectB = TestObject2()
    theObjectB.objectValue = "value1"
    XCTAssert(theObjectA == theObjectB, "Pass")

    theObjectB.objectValue = "value2"
    XCTAssert(theObjectA != theObjectB, "Pass")
}

func testHashable() {
    var theObject = TestObject2()
    theObject.objectValue = "value1"
    var hash1 = theObject.hash
    NSLog("hash = \(hash)")
}

func testPrintable() {
    var theObject = TestObject2()
    theObject.objectValue = "value1"
    NSLog("theObject = \(theObject)")
}

func testArrayFunctions() {
    let dictionaryArray: [NSDictionary] = yourGetDictionaryArrayFunction()
    let userArray = [User](dictionaryArray: dictionaryArray)
    let newDictionaryArray = userArray.toDictionaryArray()
}

func testMapping() {
    let player = GamePlayer()
    player.name = "It's Me"

    let administrator = GameAdministrator(usingValuesFrom: player)
}

Direct conversion from a NSDictionary (or an array of NSDictionaries) to json and back.

let dict1: NSDictionary = [
  "requestId": "request",
  "postcode": "1111AA",
  "houseNumber": "1"
]
let json = dict1.toJsonString()
let dict2 = NSMutableDictionary(json: json)
print("dict:\n\(dict1)\n\njson:\n\(json)\n\ndict2:\n\(dict2)")

// You can do the same with arrays
let array:[NSDictionary] = [dict1, dict2]
let jsonArray = array.toJsonStringArray()
let array2 = [NSDictionary](jsonArray: jsonArray)
print("json array: \n\(jsonArray)\n\narray2:\n\(array2)")

This is how you can parse a .plist into an object model. See EVReflectionIssue124.swift to see it working.

   if let path = Bundle(for: type(of: self)).path(forResource: "EVReflectionIssue124", ofType: "plist") {
       if let data = NSDictionary(contentsOfFile: path) {
          let plistObject = Wrapper(dictionary: data)
          print(plistObject)
       }
   }

If you want to parse XML, then you can use the pod subxpec EVReflection/XML

    let xml: String = "<data><item name=\"attrib\">itemData</item></data>"
    let xmlObject = MyObject(xml: xml)
    print(xmlObject)

Extending existing objects:

It is possible to extend other objects with the EVReflectable protocol instead of changing the base class to EVObject. This will let you add the power of EVReflection to objects that also need another framework. In some cases you still need some aditional code. For a sample see the Realm and NSManagedObject subspecs. The most basic way to extend your objects is like this:

import EVReflection
extension MyObject : EVReflectable { }

Extra information:

Conversion options

With almost any EVReflection function you can specify what kind of conversion options should be used. This is done using an option set. You can use the following conversion options:

  • None - Do not use any conversion function.
  • PropertyConverter : If specified the function propertyConverters on the EVObject will be called
  • PropertyMapping : If specified the function propertyMapping on the EVObject will be called
  • SkipPropertyValue : If specified the function skipPropertyValue on the EVObject will be called
  • KeyCleanup : If specified the automatic pascalCase and snake_case property key mapping will be called.
  • Encoding : For if you want class level functionality for encoding values (like base64, unicode, encription, ...)
  • Decoding : For if you want class level functionality for decoding values (like base64, unicode, encription, ...)

In EVReflection all functions will use a default conversion option specific to it's function. The following 4 default conversion types are used:

  • DefaultNSCoding = [None]
  • DefaultComparing = [PropertyConverter, PropertyMapping, SkipPropertyValue]
  • DefaultDeserialize = [PropertyConverter, PropertyMapping, SkipPropertyValue, KeyCleanup, Decoding]
  • DefaultSerialize = [PropertyConverter, PropertyMapping, SkipPropertyValue, Encoding]

If you want to change one of the default conversion types, then you can do that using something like:

ConversionOptions.DefaultNSCoding = [.PropertyMapping]

Automatic keyword mapping for Swift keywords

If you have JSON fields that are Swift keywords, then prefix the property with an underscore. So the JSON value for self will be stored in the property \_self. At this moment the following keywords are handled:

"self", "description", "class", "deinit", "enum", "extension", "func", "import", "init", "let", "protocol", "static", "struct", "subscript", "typealias", "var", "break", "case", "continue", "default", "do", "else", "fallthrough", "if", "in", "for", "return", "switch", "where", "while", "as", "dynamicType", "is", "new", "super", "Self", "Type", "COLUMN", "FILE", "FUNCTION", "LINE", "associativity", "didSet", "get", "infix", "inout", "left", "mutating", "none", "nonmutating", "operator", "override", "postfix", "precedence", "prefix", "right", "set", "unowned", "unowned", "safe", "unowned", "unsafe", "weak", "willSet", "private", "public"

Automatic keyword mapping PascalCase or camelCase to snake_case

When creating objects from JSON EVReflection will automatically detect if snake_case (keys are all lowercase and words are separated by an underscore) should be converted to PascalCase or camelCase property names. See Conversion options for when this function will be called.

When exporting object to a dictionary or JSON string you will have an option to specify that you want a conversion to snake_case or not. The default is .DefaultDeserialize which will also convert to snake case.

let jsonString = myObject.toJsonString([.DefaultSerialize])
let dict = myObject.toDictionary([PropertyConverter, PropertyMapping, SkipPropertyValue])

Custom keyword mapping

It's also possible to create a custom property mapping. You can define if an import should be ignored, if an export should be ignored or you can map a property name to another key name (for the dictionary and json). For this you only need to implement the propertyMapping function in the object. See Conversion options for when this function will be called.

public class TestObject5: EVObject {
    var Name: String = "" // Using the default mapping
    var propertyInObject: String = "" // will be written to or read from keyInJson
    var ignoredProperty: String = "" // Will not be written or read to/from json 

    override public func propertyMapping() -> [(keyInObject: String?, keyInResource: String?)] {
        return [(keyInObject: "ignoredProperty",keyInResource: nil), (keyInObject: "propertyInObject",keyInResource: "keyInJson")]
    }
}

Custom property converters

You can also use your own property converters. For this you need to implement the propertyConverters function in your object. For each property you can create a custom getter and setter that will then be used by EVReflection. In the sample below the JSON texts 'Sure' and 'Nah' will be converted to true or false for the property isGreat. See Conversion options for when this function will be called.

public class TestObject6: EVObject {
    var isGreat: Bool = false

    override func propertyConverters() -> [(key: String, decodeConverter: ((Any?) -> ()), encodeConverter: (() -> Any?))] {
        return [
            ( // We want a custom converter for the field isGreat
              key: "isGreat"
              // isGreat will be true if the json says 'Sure'
              , decodeConverter: { self.isGreat = ($0 as? String == "Sure") }
              // The json will say 'Sure  if isGreat is true, otherwise it will say 'Nah'
              , encodeConverter: { return self.isGreat ? "Sure": "Nah"})
        ]
    }
}

Encoding and decoding

You can add generic cod to encode or decode multiple or all properties in an object. This can be used for instance for base64, unicode and encription. Here is a base64 sample:

class SimleEncodingDecodingObject : EVObject{
    var firstName: String?
    var lastName: String?
    var street: String?
    var city: String?

    override func decodePropertyValue(value: Any, key: String) -> Any? {
        return (value as? String)?.base64Decoded?.string ?? value
    }

    override func encodePropertyValue(value: Any, key: String) -> Any {
        return (value as? String)?.base64Encoded.string ?? value
    }
}


extension String {
var data:          Data  { return Data(utf8) }
var base64Encoded: Data  { return data.base64EncodedData() }
var base64Decoded: Data? { return Data(base64Encoded: self) }
}

extension Data {
var string: String? { return String(data: self, encoding: .utf8) }
}

Custom object converter

If you want to serialize an object to a dictionary or json but the structure should be different than the object itself, then instead of using propertyConverers, you can also convert the entire object by implementing the customConverter function. In the example below the entire object will be serialized to just a string. You could also return a dictionary that represents the custom structure or an array if the object should have been an array

override func customConverter() -> AnyObject? {
    return "Object not serialized"
}

Custom type converter

If you have a custom type that requires special conversion, then you can extend it with the EVCustomReflectable protocol. A good implementation for this can be found in the Realm subspec for the List type. The converter is implemented like this:

extension List : EVCustomReflectable {
    public func constructWith(value: Any?) -> EVCustomReflectable {
        if let array = value as? [NSDictionary] {
            self.removeAll()
            for dict in array {
                if let element: T = EVReflection.fromDictionary(dict, anyobjectTypeString: _rlmArray.objectClassName) as? T {
                    self.append(element)
                }
            }
        }
        return self
    }
    public func toCodableValue() -> Any {
        return self.enumerated().map { ($0.element as? EVReflectable)?.toDictionary() ?? NSDictionary() }
    }
}

For the usage, please have a look at the Realm unittest

Skip the serialization or deserialization of specific values

When there is a need to not (de)serialize specific values like nil NSNull or empty strings you can implement the skipPropertyValue function and return true if the value needs to be skipped. See Conversion options for when this function will be called.

class TestObjectSkipValues: EVObject {
   var value1: String? 
   var value2: [String]?
   var value3: NSNumber?

   override func skipPropertyValue(value: Any, key: String) -> Bool {
      if let value = value as? String where value.characters.count == 0 || value == "null" {
         print("Ignoring empty string for key \(key)")
         return true
      } else if let value = value as? NSArray where value.count == 0 {
         print("Ignoring empty NSArray for key\(key)")
         return true
      } else if value is NSNull {
         print("Ignoring NSNull for key \(key)")
         return true
      }
      return false
   }
}

Property validators

Before setting a value the value will always be validated using the standard validateValue KVO function. This means that for every property you can also create a validation function for that property. See the sample below where there is a validateName function for the name property.

enum MyValidationError: ErrorType {
   case TypeError,
   LengthError
}

public class GameUser: EVObject {
   var name: String?
   var memberSince: NSDate?
   var objectIsNotAValue: TestObject?

   func validateName(value:AutoreleasingUnsafeMutablePointer<AnyObject?>) throws {
      if let theValue = value.memory as? String {
         if theValue.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) < 3 {
            NSLog("Validating name is not long enough \(theValue)")
            throw MyValidationError.LengthError
         }
         NSLog("Validating name OK \(theValue)")
      } else {
         NSLog("Validating name is not a string: \(value.memory)")
         throw MyValidationError.TypeError
     }
   }
}

Print options

You should be able to solve all problems with parsing your json to an object. If you get warnings and you know they don't matter and you want to stop them from printin you can suppress all print warings by calling the followin line of code:

PrintOptions.Active = .None

If you then want to turn on the print output, then just call:

PrintOptions.Active = .All

It's also possible to enable printing for specific warning types. Here is the line of code that is equal to setting it to .All. Just leave out the type that you want to suppress.

PrintOptions.Active = [.UnknownKeypath, .IncorrectKey, .ShouldExtendNSObject, .IsInvalidJson, .MissingProtocol, .MissingKey, .InvalidType, .InvalidValue, .InvalidClass, .EnumWithoutAssociatedValue]

Deserialization class level validations

There is also support for class level validation when deserializing to an object. There are helper functions for making keys required or not allowed. You can also add custom messages. Here is some sample code about how you can implement such a validation

public class ValidateObject: EVObject {
   var requiredKey1: String?
   var requiredKey2: String?
   var optionalKey1: String?

   override public func initValidation(dict: NSDictionary) {
      self.initMayNotContainKeys(["error"], dict: dict)
      self.initMustContainKeys(["requiredKey1", "requiredKey2"], dict: dict)
      if dict.valueForKey("requiredKey1") as? String == dict.valueForKey("optionalKey1") as? String {
         // this could also be called in your property specific validators
         self.addStatusMessage(.Custom, message: "optionalKey1 should not be the same as requiredKey1")
      }
   }
}

You could then test this validation with code like:

func testValidation() {
   // Test missing required key
   let json = "{\"requiredKey1\": \"Value1\"}"
   let test = ValidateObject(json: json)
   XCTAssertNotEqual(test.evReflectionStatus(), .None, "We should have a not .None status")
   XCTAssertEqual(test.evReflectionStatuses.count, 1, "We should have 1 validation result")
   for (status, message) in test.evReflectionStatuses {
      print("Validation result: Status = \(status), Message = \(message)")
   }
}

What to do when you use object inheritance

You can deserialize json to an object that uses inheritance. When the properties are specified as the base class, then the correct specific object type will be returned by the function getSpecificType. See the sample code below or the unit test in EVReflectionInheritanceTests.swift

class Quz: EVObject {
    var fooArray: Array<Foo> = []
    var fooBar: Foo?
    var fooBaz: Foo?
}

class Foo: EVObject {
    var allFoo: String = "all Foo"

    // What you need to do to get the correct type for when you deserialize inherited classes
    override func getSpecificType(_ dict: NSDictionary) -> EVReflectable {
        if dict["justBar"] != nil {
            return Bar()
        } else if dict["justBaz"] != nil {
            return Baz()
        }
        return self
    }
}

class Bar : Foo {
    var justBar: String = "For bar only"
}

class Baz: Foo {
    var justBaz: String = "For baz only"
}

Known issues

EVReflection is trying to handle all types. With some types there are limitations in Swift. So far there is a workaround for any of these limitations. Here is an overview:

It's not possible in Swift to use .setObjectForKey for:

  • nullable type fields like Int?
  • properties based on an enum
  • an Array of nullable objects like [MyObject?]
  • a Set like Set
  • generic properties like var myVal:T = T()
  • structs like CGRect or CGPoint

For all these issues there are workarounds. The easiest workaround is just using a difrent type like:

  • Instead of an Int? you could use NSNumber?
  • Instead of [MyObject?] use [MyObject]
  • Instead of Set use [MyObject]
  • Instead of 'var status: StatysType' use 'var status:Int' and save the rawValue
  • Instead of a generic property use a specific property that can hold the data (a dictionary?)
  • Instead of using a struct, create your own object model for that struct

If you want to keep on using the same type, You can override the setValue forUndefinedKey in the object itself. See WorkaroundsTests.swift and WorkaroundSwiftGenericsTests.swift to see the workaround for all these types in action.

Generic properties

For generic properties the protocol EVGenericsKVC is required. see WorkaroundSwiftGenericsTests.swift

Arrays with nullable objects or Set's

For arrays with nullable objects or Set's like [MyObj?] or Set the protocol EVArrayConvertable is required. see WorkaroundsTests.swift

Swift Dictionaries

For Swift Dictionaries (and not NSDictionary) the protocol EVDictionaryConvertable is required. See WorkaroundsTests.swift

License

EVReflection is available under the MIT 3 license. See the LICENSE file for more info.

My other libraries:

Also see my other public source iOS libraries:

  • EVReflection - Reflection based (Dictionary, CKRecord, JSON and XML) object mapping with extensions for Alamofire and Moya with RxSwift or ReactiveSwift
  • EVCloudKitDao - Simplified access to Apple's CloudKit
  • EVFaceTracker - Calculate the distance and angle of your device with regards to your face in order to simulate a 3D effect
  • EVURLCache - a NSURLCache subclass for handling all web requests that use NSURLReques
  • AlamofireOauth2 - A swift implementation of OAuth2 using Alamofire
  • EVWordPressAPI - Swift Implementation of the WordPress (Jetpack) API using AlamofireOauth2, AlomofireJsonToObjects and EVReflection (work in progress)
  • PassportScanner - Scan the MRZ code of a passport and extract the firstname, lastname, passport number, nationality, date of birth, expiration date and personal numer.
  • AttributedTextView - Easiest way to create an attributed UITextView with support for multiple links (url, hashtags, mentions).

Evolution of EVReflection (Gource Visualization)

Evolution of EVReflection (Gource Visualization)

Download Details:

Author: Evermeer
Source Code: https://github.com/evermeer/EVReflection 
License: View license

#swift #json #reflection #xml 

Reflection Based Object Mapping with Extensions for Alamofire and Moya
Rupert  Beatty

Rupert Beatty

1673091086

Runtime: A Swift Runtime Library for Viewing Type info

Runtime

Runtime is a Swift library to give you more runtime abilities, including getting type metadata, setting properties via reflection, and type construction for native swift objects.

TypeInfo

TypeInfo exposes metadata about native Swift structs, protocols, classes, tuples and enums. It captures the properties, generic types, inheritance levels, and more.

Example

Lets say you have a User struct:

struct User {
  let id: Int
  let username: String
  let email: String
}

To get the TypeInfo of User, all that you have to do is:

let info = try typeInfo(of: User.self)

Property Info

Within the TypeInfo object, it contains a list of PropertyInfo which represents all properties for the type. PropertyInfo exposes the name and type of the property. It also allows the getting and setting of a value on an object.

Example

Using the same User object as before first we get the TypeInfo and the property we want.

let info = try typeInfo(of: User.self)
let property = try info.property(named: "username")

To get a value:

let username = try property.get(from: user)

To set a value:

try property.set(value: "newUsername", on: &user)

It's that easy! 🎉

Factory

Runtime also supports building an object from it's Type. Both structs and classes are supported.

To build a User object:

let user = try createInstance(type: User.self)

Function Info

FunctionInfo exposes metadata about functions. Including number of arguments, argument types, return types, and whether it can throw an error.

Example

func doSomething(a: Int, b: Bool) throws -> String { 
  return "" 
}

let info = functionInfo(of: doSomething)

FAQ

Q: When getting and setting a value does it work typeless? (i.e. object casted as Any)

A: Yes! The whole library was designed with working typeless in mind.

Q: When creating a new instance of a class is it still protected by ARC?

A: Yes! The retain counts are set properly so ARC can do its job.

Installation

Cocoapods

Runtime is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'Runtime'

Swift Package Manager

You can install Runtime via Swift Package Manager by adding the following line to your Package.swift:

import PackageDescription

let package = Package(
    [...]
    dependencies: [
        .Package(url: "https://github.com/wickwirew/Runtime.git", majorVersion: XYZ)
    ]
)

Contributions

Contributions are welcome and encouraged!

Learn

Want to know how it works? Here's an article on how it was implemented.

Want to learn about Swift memory layout? Mike Ash gave and awesome talk on just that.

Download Details:

Author: Wickwirew
Source Code: https://github.com/wickwirew/Runtime 
License: MIT license

#swift #ios #reflection #runtime 

Runtime: A Swift Runtime Library for Viewing Type info
Lawrence  Lesch

Lawrence Lesch

1672983975

Prototype for a Metadata Reflection API for ECMAScript

Metadata Reflection API

Installation

npm install reflect-metadata

Background

  • Decorators add the ability to augment a class and its members as the class is defined, through a declarative syntax.
  • Traceur attaches annotations to a static property on the class.
  • Languages like C# (.NET), and Java support attributes or annotations that add metadata to types, along with a reflective API for reading metadata.

Goals

  • A number of use cases (Composition/Dependency Injection, Runtime Type Assertions, Reflection/Mirroring, Testing) want the ability to add additional metadata to a class in a consistent manner.
  • A consistent approach is needed for various tools and libraries to be able to reason over metadata.
  • Metadata-producing decorators (nee. "Annotations") need to be generally composable with mutating decorators.
  • Metadata should be available not only on an object but also through a Proxy, with related traps.
  • Defining new metadata-producing decorators should not be arduous or over-complex for a developer.
  • Metadata should be consistent with other language and runtime features of ECMAScript.

Syntax

  • Declarative definition of metadata:
class C {
  @Reflect.metadata(metadataKey, metadataValue)
  method() {
  }
}
  • Imperative definition of metadata:
Reflect.defineMetadata(metadataKey, metadataValue, C.prototype, "method");
  • Imperative introspection of metadata:
let obj = new C();
let metadataValue = Reflect.getMetadata(metadataKey, obj, "method");

Semantics

  • Object has a new [[Metadata]] internal property that will contain a Map whose keys are property keys (or undefined) and whose values are Maps of metadata keys to metadata values.
  • Object will have a number of new internal methods for [[DefineOwnMetadata]], [[GetOwnMetadata]], [[HasOwnMetadata]], etc.
    • These internal methods can be overridden by a Proxy to support additional traps.
    • These internal methods will by default call a set of abstract operations to define and read metadata.
  • The Reflect object will expose the MOP operations to allow imperative access to metadata.
  • Metadata defined on class declaration C is stored in C.[[Metadata]], with undefined as the key.
  • Metadata defined on static members of class declaration C are stored in C.[[Metadata]], with the property key as the key.
  • Metadata defined on instance members of class declaration C are stored in C.prototype.[[Metadata]], with the property key as the key.

API

// define metadata on an object or property
Reflect.defineMetadata(metadataKey, metadataValue, target);
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey);

// check for presence of a metadata key on the prototype chain of an object or property
let result = Reflect.hasMetadata(metadataKey, target);
let result = Reflect.hasMetadata(metadataKey, target, propertyKey);

// check for presence of an own metadata key of an object or property
let result = Reflect.hasOwnMetadata(metadataKey, target);
let result = Reflect.hasOwnMetadata(metadataKey, target, propertyKey);

// get metadata value of a metadata key on the prototype chain of an object or property
let result = Reflect.getMetadata(metadataKey, target);
let result = Reflect.getMetadata(metadataKey, target, propertyKey);

// get metadata value of an own metadata key of an object or property
let result = Reflect.getOwnMetadata(metadataKey, target);
let result = Reflect.getOwnMetadata(metadataKey, target, propertyKey);

// get all metadata keys on the prototype chain of an object or property
let result = Reflect.getMetadataKeys(target);
let result = Reflect.getMetadataKeys(target, propertyKey);

// get all own metadata keys of an object or property
let result = Reflect.getOwnMetadataKeys(target);
let result = Reflect.getOwnMetadataKeys(target, propertyKey);

// delete metadata from an object or property
let result = Reflect.deleteMetadata(metadataKey, target);
let result = Reflect.deleteMetadata(metadataKey, target, propertyKey);

// apply metadata via a decorator to a constructor
@Reflect.metadata(metadataKey, metadataValue)
class C {
  // apply metadata via a decorator to a method (property)
  @Reflect.metadata(metadataKey, metadataValue)
  method() {
  }
}

Alternatives

  • Use properties rather than a separate API.
    • Obvious downside is that this can be a lot of code:
function ParamTypes(...types) {
  return (target, propertyKey) => {
    const symParamTypes = Symbol.for("design:paramtypes");
    if (propertyKey === undefined) {
      target[symParamTypes] = types;
    }
    else {
      const symProperties = Symbol.for("design:properties");
      let properties, property;
      if (Object.prototype.hasOwnProperty.call(target, symProperties)) {
        properties = target[symProperties];
      }
      else {
        properties = target[symProperties] = {};
      }
      if (Object.prototype.hasOwnProperty.call(properties, propertyKey)) {
        property = properties[propertyKey];
      }
      else {
        property = properties[propertyKey] = {};
      }
      property[symParamTypes] = types;
    }
  };
}

Notes

  • Though it may seem counterintuitive, the methods on Reflect place the parameters for the metadata key and metadata value before the target or property key. This is due to the fact that the property key is the only optional parameter in the argument list. This also makes the methods easier to curry with Function#bind. This also helps reduce the overall footprint and complexity of a metadata-producing decorator that could target both a class or a property:
function ParamTypes(...types) {
  // as propertyKey is effectively optional, its easier to use here
  return (target, propertyKey) => { Reflect.defineMetadata("design:paramtypes", types, target, propertyKey); }

  // vs. having multiple overloads with the target and key in the front:
  //
  // return (target, propertyKey) => {
  //    if (propertyKey === undefined) {
  //      Reflect.defineMetadata(target, "design:paramtypes", types);
  //    }
  //    else {
  //      Reflect.defineMetadata(target, propertyKey, "design:paramtypes", types);
  //    }
  // }
  //
  // vs. having a different methods for the class or a property:
  //
  // return (target, propertyKey) => {
  //    if (propertyKey === undefined) {
  //      Reflect.defineMetadata(target, "design:paramtypes", types);
  //    }
  //    else {
  //      Reflect.definePropertyMetadata(target, propertyKey, "design:paramtypes", types);
  //    }
  // }
}
  • To enable experimental support for metadata decorators in your TypeScript project, you must add "experimentalDecorators": true to your tsconfig.json file.
  • To enable experimental support for auto-generated type metadata in your TypeScript project, you must add "emitDecoratorMetadata": true to your tsconfig.json file.
    • Please note that auto-generated type metadata may have issues with circular or forward references for types.

Issues

  • A poorly written mutating decorator for a class constructor could cause metadata to become lost if the prototype chain is not maintained. Though, not maintaining the prototype chain in a mutating decorator for a class constructor would have other negative side effects as well. @rbuckton
    • This is mitigated if the mutating decorator returns a class expression that extends from the target, or returns a proxy for the decorator. @rbuckton
  • Metadata for a method is attached to the class (or prototype) via the property key. It would not then be available if trying to read metadata on the function of the method (e.g. "tearing-off" the method from the class). @rbuckton

Detailed proposal


Download Details:

Author: rbuckton
Source Code: https://github.com/rbuckton/reflect-metadata 
License: Apache-2.0 license

#typescript #javascript #metadata #reflection

Prototype for a Metadata Reflection API for ECMAScript
Desmond  Gerber

Desmond Gerber

1669013905

How What and How Reflection Works in Kotlin with This Tutorial

Learn how what and how reflection works in Kotlin with this tutorial

In programming, reflection is a programming language’s ability to inspect and interact with statically defined classes, functions, and properties during runtime.

The feature is particularly useful when you receive an object instance of an unknown class.

By using reflection, you can check if a particular object has a certain method, and call that method when it exists.

To use reflection in Kotlin, you need to include the kotlin-reflect library in your project:

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10")
}

The library contains the runtime component required for using Kotlin reflection features.

Next, let’s see how you can get class, function, and property references using Kotlin reflection feature.

Kotlin reflection - class reference

Suppose you have a Dog class with the following definitions:

class Dog(var name: String) {
    fun bark() {
        println("Bark!")
    }

    fun bark(sound: String) {
        println(sound)
    }

    private fun hello() {
        println("Hello! My name is $name")
    }
}

To get the class reference in Kotlin, you can use the class literal syntax ::class as shown below:

val classRef = Dog::class

Alternatively, you can get the class reference from an object instance by using the same ::class syntax on the instance:

val myDog = Dog("Puppy")

val classRef = myDog::class

Getting the class reference from an object is also known as a bounded class reference.

Once you have the class reference, you can access the properties of the reference to find out more about that class.

For example, you can find the name of the class and check if that class is a data class:

println(classRef.simpleName) // Dog
println(classRef.qualifiedName) // org.metapx.Dog
println(classRef.isData) // false

In Kotlin, the class reference is identified as the Kclass type which stands for Kotlin class.

You can check the Kclass documentation for all properties and methods you can access to find out about the class from its reference.

Aside from inspecting the class, the Kclass also has some interesting abilities. The createInstance() method, for example, allows you to create a new object from the class reference:

val secondDog = classRef.createInstance()

But keep in mind that the createInstance() method only works when the class has a constructor with optional or no parameter.

An error will be thrown when no constructor fulfills the criteria.

Accessing Kotlin class reference methods

You can also get access to the methods of the class reference regardless of their access modifier.

This means even private functions of a class can be accessed from its reference.

The memberFunctions property of Kclass stores all methods of the class as a Collection:

val myDog = Dog("Puppy")

val classRef = myDog::class

classRef.memberFunctions.forEach { 
    println(it.name) 
}

The output will be as follows:

bark
bark
hello
equals
hashCode
toString

Next, you can call the class function from its reference as follows:

val myDog = Dog("Puppy")

val classRef = myDog::class

val barkRef = classRef.memberFunctions.find { 
    it.name == "bark" 
}

barkRef?.call(myDog)

First, you need to use the find() function to retrieve the function reference.

Then, check if the function reference is found using the null-safe call.

When the reference is found, use the call() method from the function reference Kfunction type.

The first argument of the call() method must be an instance of the class reference, which is why myDog object is passed into the method.

When your function is private, you need to change the isAccessible property of the function reference as true first before calling the function:

val helloRef = classRef.memberFunctions.find { 
    it.name == "hello" 
}

helloRef?.isAccessible = true

helloRef?.call(myDog)

And that’s how you access the methods of a class using its reference.

Accessing Kotlin class reference properties

The properties of a Kotlin class reference can be accessed the same way you access its methods.

The properties of a class are stored in memberProperties as a Collection.

For example, you can get the name property value of the myDog instance as follows:

val myDog = Dog("Puppy")

val classRef = myDog::class

val nameRef = classRef.memberProperties.find {
    it.name == "name" 
}

println(nameRef?.getter?.call(myDog)) // Puppy

A property reference is an instance of KProperty type. The value of the property is retrieved by calling the getter() method.

To change the value of the name property, you need to cast the property into KMutableProperty first as shown below:

val myDog = Dog("Puppy")

val classRef = myDog::class

val nameRef = classRef.memberProperties.find {
    it.name == "name" 
} as KMutableProperty<*>?

nameRef?.setter?.call(myDog, "Jacob")

println(myDog.name) // Jacob

The KMutableProperty holds the setter() method, which you need to call to set the value of the property.

Now you’ve learned how to access methods and properties from a class reference.

Next, let’s look at how you can get a function reference with Kotlin reflection

Kotlin reflection - function reference

You can get a reference to a named Kotlin function by using the :: operator.

Here’s an example:

fun hello() {
    println("Hello World!")
}

val funRef = ::hello

funRef() // Hello World!

The funRef above will be an instance of Kfunction type, which represents a function with introspection capabilities.

Conclusion

Now you’ve learned what the Kotlin reflection feature is and how it works with some examples. Reflection is a powerful feature that’s only used for specific requirements.

Because of its ability to find inspect a source code, it’s frequently used when developing a framework or library for further development.

JUnit and Spring frameworks are notable for using reflection in their source code.

The library author won’t know the classes and functions created by the user. Reflection allows the framework to deal with classes and functions without knowing about them in advance.

Original article source at: https://sebhastian.com/

#kotlin #tutorial #reflection  

How What and How Reflection Works in Kotlin with This Tutorial
Maitri Sharma

Maitri Sharma

1667392749

Convex Lens - an overview | Physics Wallah

A lens is a transparent material that concentrates or disperses light rays when it passes through them by refraction. According to the shape and purpose of the lens, they are classified into two types convex lens and concave lens.
https://www.pw.live/physics-articles/convex-lens

 

#convexlens #lens #mirror #physics #reflection #physicsarticles

 

Convex Lens - an overview | Physics Wallah
Elliot  Bayer

Elliot Bayer

1647114840

How to Do A Primer Of Reflection in Swift and Xcode

In this video we will do a primer of reflection in Swift. Using the Mirror API we will learn about various use cases of this simple but powerful api. We will work in Xcode 13 and Swift 5.

💻 Source Code: https://patreon.com/iOSAcademy

#swift  #reflection  #iosdeveloper #ios 

How to Do A Primer Of Reflection in Swift and Xcode
Shana  Stehr

Shana Stehr

1637217540

How to Image Reflection using CSS Property -webkit-box-reflect

Image Reflection using CSS Property -webkit-box-reflect | Webkit Coding
Hello friend today in this tutorial you will learn about how you can create a image / object #reflection using CSS_property -webkit-box-reflect. I hope you will like this tutorial as our all other tutorials don't forget to subscribe and press the bell icon for never miss any new updates

Click on Time-Stamp to jump on
00:06 - Preview
00:32 - Totorial

#css 

How to Image Reflection using CSS Property -webkit-box-reflect

NotImplemented and Reflection Functions in Python

We know that a function or method will:

  • Return some result, or
  • Raise an exception if it cannot find the result

But there is a third thing a function can return and that is NotImplemented. The simple meaning of return NotImplemented by a function is that the function is declaring that it cannot find the result but instead of raising the exception, it will transfer the control to another function, hoping that the other function will get the result. The other function is known as Reflection Function.

Example case that can be solved using NotImplemented and Reflection Function:

We will explore the whole idea in context to Object Oriented Programming and associated Magic Methods (also known as special methods or dunder methods) which are used for different special functionalities and we will just see the ones used to define the support for different operator (e.g. +,-,* etc.) for objects of one class.

Let’s see this simple Point class defined for the points on XY plane:

class Point:
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def __str__(self):
        return f'({self.x},{self.y})'

p1=Point(3,4)
print(p1)

The __str__ method is defined for the proper representation of the point object and the last print statement will print the point as (3,4).

If we want to define a function for the addition of two point objects, it can be done as:

def addPoints(self,other):
        return Point(self.x+other.x,self.y+other.y)

And then we can use it as:

p1=Point(3,4)
p2=Point(1,1)
p3=p1.addPoints(p2)
print(p3)

This will display (4,5) as output.

But it will be better if instead of using a custom named function like addPoints, we could directly apply + operator like we do for simple numbers and a few other data types e.g. 4+5. At present if we use + operator on two point objects as:

p1=Point(3,4)
p2=Point(1,1)
p3=p1+p2

It will generate following error which is self-explanatory:

TypeError: unsupported operand type(s) for +: ‘Point’ and ‘Point’

If we change the name of the function addPoints to __add__ which is a magic method, the + operator applied between two point objects will call this method.
See the complete code here:

class Point:
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def __str__(self):
        return f'({self.x},{self.y})'
    def __add__(self,other):
        return Point(self.x+other.x,self.y+other.y)

p1=Point(3,4)
p2=Point(1,1)
p3=p1+p2
print(p3)

And the output will be (4,5).

We have special methods for other operators too e.g. __sub__ is for subtraction ( - ), __mul__ is for multiplication ( * ), __div__ is for division( / ) and a few more.

In fact, when we apply + operator between any data types, interpreter actually executes __add__ method on those e.g. for 3+4, interpreter will execute 3.__add__(4) and the method __add__ is defined in int class for addition of two integers. Similarly, if a and b are two lists, a+b will result into a.__add__(b) and __add__ is defined inside list class as concatenation of the lists.

Now let’s define __mul__ for the Point class but not for the multiplication of two point objects but to multiply the Point object with a number, resulting into a new point with scaled x and y components. It will be done by adding __mul__ method as shown here:

class Point:
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def __str__(self):
        return f'({self.x},{self.y})'
    def __add__(self,other):
        return Point(self.x+other.x,self.y+other.y)
    def __mul__(self,num):
        return Point(self.x*num,self.y*num)

p1=Point(3,4)
p2=p1*2
print(p2)

The output will be (6,8).

But instead of p1*2 if we execute 2*p1, then instead of getting the same result, we get an error as:

TypeError: unsupported operand type(s) for *: ‘int’ and ‘Point’

This is something we will resolve using the concept of NotImplemented and Reflection Function.

What happens when a function returns NotImplemented:

When a function returns NotImplemented, interpreter will run the reflection function associated with that function after flipping the input arguments. For example, if original function has input arguments as a and b, at returning NotImplemented, interpreter will run the associated reflection function on b and a.

Second important thing is that the reflection functions associated with different functions are predefined in Python and you cannot make some function as reflection of some other function by your own. The reflection function of __add__ is __radd__, reflection function of __mul__ is __rmul__ and so on for different magic methods.

So, lets see what happened when interpreter executed 2*p1 in above program.
As described earlier that 2*p1 will result into 2.__mul__(p1), so interpreter will apply __mul__ on 2 which is an integer. Therefore, interpreter will search for __mul__ method inside int class. Interpreter will find the method in int class but that method defines multiplication between two integers and may be between an integer and some other data type but not between an integer and the Point class object. And in such cases (unsupported datatype), the __mul__ of int class returns NotImplemented.
With NotImplemented returned, interpreter will run the reflection method i.e. __rmul__ on flipped input arguments as p1.__rmul__(2). And you can see that the method is applied on p1 which is Point class object and hence interpreter will search for this method (__rmul__) in Point class and will fail since this method is not defined inside Point class. So it will return back to the original function (of int class) and will generate this error:

TypeError: unsupported operand type(s) for *: ‘int’ and ‘Point’

The whole process is given here step by step for further clarification:

  1. 2*p1 will result into 2.__mul__(p1) and Interpreter searches for __mul__ in int class.
  2. __mul__ in int class returns NotImplemeted for unsupported types of operands.
  3. This results into execution of reflection function as p1.__rmul__(2).
  4. Interpreter will look for __rmul__ inside Point class because p1 is Point class object.
  5. When failed to find __rmul__ in Point class, interpreter will go back to int class and generate the error.

So if you have followed along these steps, you probably have figured out the solution which is that we must define __rmul__ in Point class, so that p1.__rmul__(2) should get executed.

What should be inside this function?

p1.__rmul__(2) means that self is p1 and second input argument is 2 and we need to return a new point with scaled xy coordinates. So, we should have __rmul__ defined as:

def __rmul__(self,num):
        return Point(self.x*num,self.y*num)

But this is exactly what __mul__ does, and hence we can also do as:

def __rmul__(self,num):
        return self*num

Above return statement with multiplication will call the __mul__ method.
Even a better approach will be to just declare:

__rmul__=__mul__

Because the function are also Objects and we are saying that __rmul__ is referring to same object as __mul__.
The complete code will be:

class Point:
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def __str__(self):
        return f'({self.x},{self.y})'
    def __add__(self,other):
        return Point(self.x+other.x,self.y+other.y)
    def __mul__(self,num):
        return Point(self.x*num,self.y*num)
    __rmul__=__mul__
p1=Point(3,4)
p2=2*p1
print(p2)

And now we will get the correct output as (6,8).

You can see that it is just the one last line added in Point class i.e. __rmul__=__mul__ and it resolved a big problem. And that is all because of the power of NotImplemented and Reflection Function support of Python.

Please don’t forget to subscribe: Learning Orbis

You can find further detail with more practice examples in this video:

If you need more detail on Magic Methods, you can find that in the following videos:

#notimplemented #reflection #python #programming #oop

NotImplemented and Reflection Functions in Python
Chelsie  Towne

Chelsie Towne

1596968220

Set Field Value With Reflection

1. Overview

In our previous article, we discussed how we could read the values of private fields from a different class in Java. However, there can be scenarios when we need to set the values of fields, such as in some libraries where we don’t have access to the fields.

In this quick tutorial, we’ll discuss how can we set the values of fields from a different class in Java by using the Reflection API.

Note that we’ll be using the same Person class for the examples here as we used in our previous article.

2. Setting Primitive Fields

We can** set the fields that are primitives by using the Field#setXxx methods**.

#java #reflection

Set Field Value With Reflection

Class.isInstance vs Class.isAssignableFrom

1. Introduction

In this quick tutorial, we’re going to take a look at the difference between Class.isInstance and Class.isAssignableFrom. We’ll learn how to use each method and what the differences are between them.

2. Setup

Let’s set up an interface and a couple of classes to use while we explore the Class.isInstance and Class.isAssignableFrom functionality.

First, let’s define an interface:

public interface Shape {}

Next, let’s define a class that implements Shape:

public class Triangle implements Shape {}

Now, we’ll create a class that extends Triangle:

public class IsoscelesTriangle extends Triangle {}

3. Class.isInstance

The isInstance method on the Class class is equivalent to the instanceof operator. The isInstance method was introduced in Java 1.1 because it can be used dynamically. This method will return true if the argument isn’t null and can be successfully cast to the reference type without raising a ClassCastException.

#java #reflection

Class.isInstance vs Class.isAssignableFrom

Object Change Tracking via Reflection in .NET

We have this big project we’re working on (which I have written about before) and one of the things we need to do on this project is automatic logging of changes made to model objects.  I’ve worked out a way to do this generically, for any object, and I think

#asp.net #reflection in .net #reflection #.net #programming

Object Change Tracking via Reflection in .NET