Reflect is an ActiveRecord framework, elegant and simple that use the SQLite in Swift.
- Easy configuration
- Simple syntax
- Pure Swift
Temporary
import CoreReflect
Reflect.configuration(.temporary, readonly: true)
let connTemporary = Reflect.settings.getConnection()
InMemory
import CoreReflect
Reflect.configuration(.inMemory, readonly: true)
let connInMemory = Reflect.settings.getConnection()In-memory databases are automatically deleted when the database connection is closed.
Path
import CoreReflect
let path = "\(NSTemporaryDirectory())Tests.db"
Reflect.configuration(.uri(path), readonly: false)
let connURI = Reflect.settings.getConnection()
App Group
import CoreReflect
Reflect.configuration("", baseNamed: "Tests.db")
let connDefault = Reflect.settings.getConnection() Add as inheritance class Reflect to your object.
import CoreReflect
class User: Reflect {
var firstName:String
var lastName :String?
var age:Int
var birthday:Date?
var gender:String?
var email:String
var registerNumber:Int
var address: Address
required init() {
firstName = ""
age = 0
email = ""
registerNumber = 0
address = Address()
}
}We can change table name, implementation and method static entityName.
override class func entityName() -> String {
return "My_Table_Name"
}
To ignore properties, we can implementation the method static ignoredProperties.
override class func ignoredProperties() -> Set<String> {
return ["status", "register", "value"]
}
Use register to create table.
Address.register()
User.register()
// CREATE TABLE IF NOT EXISTS Address (objectId INTEGER PRIMARY KEY AUTOINCREMENT, createdAt DATE, updatedAt DATE, street TEXT NOT NULL, number INTEGER NOT NULL, state TEXT NOT NULL, zip INTEGER NOT NULL)
//CREATE TABLE IF NOT EXISTS User (objectId INTEGER PRIMARY KEY AUTOINCREMENT, createdAt DATE, updatedAt DATE, firstName TEXT NOT NULL, lastName TEXT, age INTEGER NOT NULL, birthday DATE, gender TEXT, email TEXT NOT NULL, registerNumber INTEGER NOT NULL, Address_objectId INTEGER NOT NULL)Note: Reflect create automatically
objectId,createdAtandupdatedAt.The objectIdis an Integer auto increment and is primary key default.
Type optional Supported:
| Optional | [x] |
|---|---|
String |
[x] |
NSString |
[x] |
NSInteger |
[x] |
NSNumber |
[x] |
Date |
[x] |
Data |
[x] |
If object is an optional, automatically remove NOT NULL on Query
User.unRegister()
//DROP TABLE UserThe index name is generated automatically based on the table and column names
uniqueadds aUNIQUEconstraint to the index. Default:false.
User.index("registerNumber", unique: true)
User.index("firstName")
// CREATE UNIQUE INDEX IF NOT EXISTS index_User_on_registerNumber ON User (registerNumber)
// CREATE INDEX IF NOT EXISTS index_User_on_firstName ON User (firstName)We can insert rows into a table by calling a Reflect Object pin function.
let address = Address()
address.street = "Highland Drive Temple Hills"
address.number = 226
address.state = "MD"
address.zip = 20748
address.pin()
// INSERT INTO Address ( createdAt, updatedAt, street, number, state, zip ) VALUES ('2016-11-14 19:40:11', '2016-11-14 19:40:11', 'Highland Drive Temple Hills', 226, 'MD', 20748)If the object contains an object Reflect property, when executing the function pin, Reflect automatically creates a reference by adding the objectId of the property.
let user = User()
user.firstName = "Kanisha"
user.lastName = "Classen"
user.age = 69
user.birthday = '1947-01-23 21:46:23'.date
user.gender = "female"
user.email = "[email protected]"
user.registerNumber = 9798
user.address = address
//INSERT INTO User ( createdAt, updatedAt, firstName, lastName, age, birthday, gender, email, registerNumber, Address_objectId ) VALUES ('2016-11-14 19:44:23', '2016-11-14 19:44:23', 'Kanisha', 'Classen', 69, '1947-01-23 21:46:23', 'female', '[email protected]', 9798, 1)Note: If exist an value to objectId to object Reflect, when executing the function
pinthe Reflect going to change object usingupdate.
We can delete an row a table with unPin function.
let user = User()
user.objectId = 2
user.unPin()To remove all object, we can user the method clear
User.clean()Using the transaction function, we can run a series of statements in a transaction. If a single statement fails or the block throws an error, the changes will be rolled back.
let address = Address()
let user = User()
User.transaction {
address.number = 101
address.street = "Alpha Village"
address.state = "NY"
address.zip = 10203
address.pin()
user.firstName = "Bruno"
user.lastName = "Fernandes"
user.age = 29
user.gender = "male"
user.email = "[email protected]"
user.registerNumber = 987654
user.address = address
let cal = Calendar.current
user.birthday = cal.date(byAdding: .day, value: -Int(arc4random_uniform(30)), to: Date())
user.birthday = cal.date(byAdding: .month, value: -Int(arc4random_uniform(12)), to: user.birthday!)
user.birthday = cal.date(byAdding: .year, value: -user.age, to: user.birthday!)
user.pin()
}
// BEGIN DEFERRED TRANSACTION
// INSERT INTO Address ( createdAt, updatedAt, street, number, state, zip ) VALUES ('2016-11-14 21:17:15', '2016-11-14 21:17:15', 'Alpha Village', 101, 'NY', 10203)
// INSERT INTO User ( createdAt, updatedAt, firstName, lastName, age, birthday, gender, email, registerNumber, Address_objectId ) VALUES ('2016-11-14 21:17:15', '2016-11-14 21:17:15', 'Bruno', 'Fernandes', 29, '1986-12-26 21:17:15', 'male', '[email protected]', 987654, 21)
// COMMIT TRANSACTIONWe can find specific id with findById function.
let user = User.findById(2)
//SELECT * FROM User WHERE User.objectId = 2or if exist object instance we can use fetch function.
let user = User()
user.objectId = 2
user.fetch()
//SELECT * FROM User WHERE User.objectId = 2include another object type Reflect, this case the fetch add an inner as default to include object
user.fetch(include: Address.self)
//SELECT Address.objectId AS 'Address.objectId', Address.createdAt AS 'Address.createdAt', Address.updatedAt AS 'Address.updatedAt', Address.street AS 'Address.street', Address.number AS 'Address.number', Address.state AS 'Address.state', Address.zip AS 'Address.zip', User.* FROM User INNER JOIN Address ON User.Address_objectId = Address.objectId WHERE User.objectId = 2
Reflect filters rows using a Query with filter function.
Support operator:
| Operator | [x] |
|---|---|
Equals |
[x] |
NotEquals |
[x] |
GreaterThan |
[x] |
LessThan |
[x] |
In |
[x] |
NotInt |
[x] |
Is |
[x] |
Like |
[x] |
NotLike |
[x] |
-
equalsvar query = User.query() query.filter("age", .equals, value: 25) var users = query.findObject() //SELECT * FROM User WHERE age = 25
-
notEqualsvar query = User.query() query.filter("gender", .notEquals, value: "male") var users = query.findObject() //SELECT * FROM User WHERE gender != 'male'
-
greaterThanvar query = User.query() query.filter("registerNumber", .greaterThan, value: 5000) var users = query.findObject() //SELECT * FROM User WHERE registerNumber > 5000
-
lessThanvar query = User.query() query.filter("registerNumber", .lessThan, value: 4500) var users = query.findObject() //SELECT * FROM User WHERE registerNumber < 4500
-
invar query = Address.query() query.filter("state", .in, value: "MI", "GA", "LI") var addresses = query.findObject() //SELECT * FROM Address WHERE state IN ('MI' , 'GA' , 'LI')
-
notInvar query = Address.query() query.filter("number", .notIn, value: 105, 226, 760, 728) var addresses = query.findObject() //SELECT * FROM Address WHERE number NOT IN (105 , 226 , 760 , 728)
-
isvar query = Address.query() query.filter("updatedAt", .is, value: nil) var addresses = query.findObject() //SELECT * FROM Address WHERE updatedAt IS NULL
-
like//Ex: 'A%' '%A' '%a%' var query = query = User.query() query.filter("firstName", .like, value: "A%") users = query.findObject() //SELECT * FROM User WHERE firstName LIKE 'A%'
-
notLike//Ex: 'A%' '%A' '%a%' var query = query = User.query() query.filter("firstName", .notLike, value: "%mi%") users = query.findObject() //SELECT * FROM User WHERE firstName NOT LIKE '%mi%'
-
betweenvar query = User.query() query.filter("age", .between, value: 20, 30) users = query.findObject() //SELECT * FROM User WHERE age BETWEEN 20 AND 30
By default, Query select every column of the result set (using SELECT *). We can use the fields function to return specific columns instead.
var query = User.query()
query.fields("objectId", "firstName", "lastName", "age")
query.findObject()
//SELECT objectId, firstName, lastName, age FROM UserQuery come with a number of functions that quickly return aggregate scalar values from the table.
-
countvar query = User.query() let result = query.count() //SELECT COUNT(*) AS count FROM User
-
sumvar query = User.query() let result = query.sum("age") //SELECT SUM(age) AS value FROM User
-
averagevar query = User.query() let result = query.average("age") //SELECT AVG(age) AS average FROM User
-
maxvar query = User.query() let result = query.max("birthday") as! String //SELECT MAX(birthday) AS maximum FROM User
-
minvar query = User.query() let result = query.min("birthday") as! String //SELECT MIN(birthday) AS minimum FROM User
-
distinctvar query = User.query() users = query.fields("age").distinct().findObject() //SELECT DISTINCT age FROM User;
We can pre-sort returned rows using a Query with sort function.
Type Sort : Asc and Desc.
var query = User.query()
var users = query.sort("age", .asc).findObject()
//SELECT * FROM User ORDER BY age ASCWe can limit and offset returned rows using a Query, limit function and offset have parameter default is equal 1.
var query = User.query()
var users = query.filter("gender", .equals, value: "female")
.sort("age", .desc)
.limit(3)
.offset(2)
.findObject()
//SELECT * FROM User WHERE gender = 'female' ORDER BY age DESC LIMIT 3 OFFSET 2We can create an block to filter that need condition or or and. The Reflect create all content on block with key and or or depends of function.
var query = User.query()
query.filter("gender", .equals, value: "female").or { q in
q.filter("age", .greaterThan, value: 70)
.filter("age", .lessThan, value: 20)
}
users = query.findObject()
//SELECT * FROM User WHERE gender = 'female' AND (age > 70 OR age < 20)We can join tables using a Query join function.
The join function takes a Query object (for the table being joined on), a join condition (on), and is prefixed with an optional join type (default: .inner).
When joining tables, column names can become ambiguous and to fix this, Reflect adds a prefix with the table name.
var query = User.query()
query.join(Address.self)
query.or { q in
q.filter("gender", .equals, value: "female").filter("age", .greaterThan, value: 50)
}.and { q in
q.filter("Address.state", .in, value: "MI", "GA", "LI")
}
users = query.findObject()
//SELECT Address.objectId AS 'Address.objectId', Address.createdAt AS 'Address.createdAt', Address.updatedAt AS 'Address.updatedAt', Address.street AS 'Address.street', Address.number AS 'Address.number', Address.state AS 'Address.state', Address.zip AS 'Address.zip', User.* FROM User INNER JOIN Address ON User.Address_objectId = Address.objectId WHERE (gender = 'female' OR age > 50) AND (Address.state IN ('MI' , 'GA' , 'LI'))Adding this function, we can monitor all instruction sql in real-time
Reflect.settings.log { (SQL:String) in
print("\n Instruction sql -- ", SQL, "\n")
}(The MIT License)
Copyright (c) 2016 Bruno Fernandes ([email protected])
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.