import XCTest import SQLite class QueryTests : XCTestCase { let users = Table("users") let id = Expression("id") let email = Expression("email") let age = Expression("age") let admin = Expression("admin") let optionalAdmin = Expression("admin") let posts = Table("posts") let userId = Expression("user_id") let categoryId = Expression("category_id") let published = Expression("published") let categories = Table("categories") let tag = Expression("tag") func test_select_withExpression_compilesSelectClause() { AssertSQL("SELECT \"email\" FROM \"users\"", users.select(email)) } func test_select_withStarExpression_compilesSelectClause() { AssertSQL("SELECT * FROM \"users\"", users.select(*)) } func test_select_withNamespacedStarExpression_compilesSelectClause() { AssertSQL("SELECT \"users\".* FROM \"users\"", users.select(users[*])) } func test_select_withVariadicExpressions_compilesSelectClause() { AssertSQL("SELECT \"email\", count(*) FROM \"users\"", users.select(email, count(*))) } func test_select_withExpressions_compilesSelectClause() { AssertSQL("SELECT \"email\", count(*) FROM \"users\"", users.select([email, count(*)])) } func test_selectDistinct_withExpression_compilesSelectClause() { AssertSQL("SELECT DISTINCT \"age\" FROM \"users\"", users.select(distinct: age)) } func test_selectDistinct_withExpressions_compilesSelectClause() { AssertSQL("SELECT DISTINCT \"age\", \"admin\" FROM \"users\"", users.select(distinct: [age, admin])) } func test_selectDistinct_withStar_compilesSelectClause() { AssertSQL("SELECT DISTINCT * FROM \"users\"", users.select(distinct: *)) } func test_join_compilesJoinClause() { AssertSQL( "SELECT * FROM \"users\" INNER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")", users.join(posts, on: posts[userId] == users[id]) ) } func test_join_withExplicitType_compilesJoinClauseWithType() { AssertSQL( "SELECT * FROM \"users\" LEFT OUTER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")", users.join(.leftOuter, posts, on: posts[userId] == users[id]) ) AssertSQL( "SELECT * FROM \"users\" CROSS JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")", users.join(.cross, posts, on: posts[userId] == users[id]) ) } func test_join_withTableCondition_compilesJoinClauseWithTableCondition() { AssertSQL( "SELECT * FROM \"users\" INNER JOIN \"posts\" ON ((\"posts\".\"user_id\" = \"users\".\"id\") AND \"published\")", users.join(posts.filter(published), on: posts[userId] == users[id]) ) } func test_join_whenChained_compilesAggregateJoinClause() { AssertSQL( "SELECT * FROM \"users\" " + "INNER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\") " + "INNER JOIN \"categories\" ON (\"categories\".\"id\" = \"posts\".\"category_id\")", users.join(posts, on: posts[userId] == users[id]).join(categories, on: categories[id] == posts[categoryId]) ) } func test_filter_compilesWhereClause() { AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.filter(admin == true)) } func test_filter_compilesWhereClause_false() { AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.filter(admin == false)) } func test_filter_compilesWhereClause_optional() { AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.filter(optionalAdmin == true)) } func test_filter_compilesWhereClause_optional_false() { AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.filter(optionalAdmin == false)) } func test_where_compilesWhereClause() { AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.where(admin == true)) } func test_where_compilesWhereClause_false() { AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.where(admin == false)) } func test_where_compilesWhereClause_optional() { AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.where(optionalAdmin == true)) } func test_where_compilesWhereClause_optional_false() { AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.where(optionalAdmin == false)) } func test_filter_whenChained_compilesAggregateWhereClause() { AssertSQL( "SELECT * FROM \"users\" WHERE ((\"age\" >= 35) AND \"admin\")", users.filter(age >= 35).filter(admin) ) } func test_group_withSingleExpressionName_compilesGroupClause() { AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\"", users.group(age)) } func test_group_withVariadicExpressionNames_compilesGroupClause() { AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\", \"admin\"", users.group(age, admin)) } func test_group_withExpressionNameAndHavingBindings_compilesGroupClause() { AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\" HAVING \"admin\"", users.group(age, having: admin)) AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\" HAVING (\"age\" >= 30)", users.group(age, having: age >= 30)) } func test_group_withExpressionNamesAndHavingBindings_compilesGroupClause() { AssertSQL( "SELECT * FROM \"users\" GROUP BY \"age\", \"admin\" HAVING \"admin\"", users.group([age, admin], having: admin) ) AssertSQL( "SELECT * FROM \"users\" GROUP BY \"age\", \"admin\" HAVING (\"age\" >= 30)", users.group([age, admin], having: age >= 30) ) } func test_order_withSingleExpressionName_compilesOrderClause() { AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\"", users.order(age)) } func test_order_withVariadicExpressionNames_compilesOrderClause() { AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\", \"email\"", users.order(age, email)) } func test_order_withArrayExpressionNames_compilesOrderClause() { AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\", \"email\"", users.order([age, email])) } func test_order_withExpressionAndSortDirection_compilesOrderClause() { // AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\" DESC, \"email\" ASC", users.order(age.desc, email.asc)) } func test_order_whenChained_resetsOrderClause() { AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\"", users.order(email).order(age)) } func test_reverse_withoutOrder_ordersByRowIdDescending() { // AssertSQL("SELECT * FROM \"users\" ORDER BY \"ROWID\" DESC", users.reverse()) } func test_reverse_withOrder_reversesOrder() { // AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\" DESC, \"email\" ASC", users.order(age, email.desc).reverse()) } func test_limit_compilesLimitClause() { AssertSQL("SELECT * FROM \"users\" LIMIT 5", users.limit(5)) } func test_limit_withOffset_compilesOffsetClause() { AssertSQL("SELECT * FROM \"users\" LIMIT 5 OFFSET 5", users.limit(5, offset: 5)) } func test_limit_whenChained_overridesLimit() { let query = users.limit(5) AssertSQL("SELECT * FROM \"users\" LIMIT 10", query.limit(10)) AssertSQL("SELECT * FROM \"users\"", query.limit(nil)) } func test_limit_whenChained_withOffset_overridesOffset() { let query = users.limit(5, offset: 5) AssertSQL("SELECT * FROM \"users\" LIMIT 10 OFFSET 20", query.limit(10, offset: 20)) AssertSQL("SELECT * FROM \"users\"", query.limit(nil)) } func test_alias_aliasesTable() { let managerId = Expression("manager_id") let managers = users.alias("managers") AssertSQL( "SELECT * FROM \"users\" " + "INNER JOIN \"users\" AS \"managers\" ON (\"managers\".\"id\" = \"users\".\"manager_id\")", users.join(managers, on: managers[id] == users[managerId]) ) } func test_insert_compilesInsertExpression() { AssertSQL( "INSERT INTO \"users\" (\"email\", \"age\") VALUES ('alice@example.com', 30)", users.insert(email <- "alice@example.com", age <- 30) ) } func test_insert_withOnConflict_compilesInsertOrOnConflictExpression() { AssertSQL( "INSERT OR REPLACE INTO \"users\" (\"email\", \"age\") VALUES ('alice@example.com', 30)", users.insert(or: .replace, email <- "alice@example.com", age <- 30) ) } func test_insert_compilesInsertExpressionWithDefaultValues() { AssertSQL("INSERT INTO \"users\" DEFAULT VALUES", users.insert()) } func test_insert_withQuery_compilesInsertExpressionWithSelectStatement() { let emails = Table("emails") AssertSQL( "INSERT INTO \"emails\" SELECT \"email\" FROM \"users\" WHERE \"admin\"", emails.insert(users.select(email).filter(admin)) ) } func test_update_compilesUpdateExpression() { AssertSQL( "UPDATE \"users\" SET \"age\" = 30, \"admin\" = 1 WHERE (\"id\" = 1)", users.filter(id == 1).update(age <- 30, admin <- true) ) } func test_delete_compilesDeleteExpression() { AssertSQL( "DELETE FROM \"users\" WHERE (\"id\" = 1)", users.filter(id == 1).delete() ) } func test_delete_compilesExistsExpression() { AssertSQL( "SELECT EXISTS (SELECT * FROM \"users\")", users.exists ) } func test_count_returnsCountExpression() { AssertSQL("SELECT count(*) FROM \"users\"", users.count) } func test_scalar_returnsScalarExpression() { AssertSQL("SELECT \"int\" FROM \"table\"", table.select(int) as ScalarQuery) AssertSQL("SELECT \"intOptional\" FROM \"table\"", table.select(intOptional) as ScalarQuery) AssertSQL("SELECT DISTINCT \"int\" FROM \"table\"", table.select(distinct: int) as ScalarQuery) AssertSQL("SELECT DISTINCT \"intOptional\" FROM \"table\"", table.select(distinct: intOptional) as ScalarQuery) } func test_subscript_withExpression_returnsNamespacedExpression() { let query = Table("query") AssertSQL("\"query\".\"blob\"", query[data]) AssertSQL("\"query\".\"blobOptional\"", query[dataOptional]) AssertSQL("\"query\".\"bool\"", query[bool]) AssertSQL("\"query\".\"boolOptional\"", query[boolOptional]) AssertSQL("\"query\".\"date\"", query[date]) AssertSQL("\"query\".\"dateOptional\"", query[dateOptional]) AssertSQL("\"query\".\"double\"", query[double]) AssertSQL("\"query\".\"doubleOptional\"", query[doubleOptional]) AssertSQL("\"query\".\"int\"", query[int]) AssertSQL("\"query\".\"intOptional\"", query[intOptional]) AssertSQL("\"query\".\"int64\"", query[int64]) AssertSQL("\"query\".\"int64Optional\"", query[int64Optional]) AssertSQL("\"query\".\"string\"", query[string]) AssertSQL("\"query\".\"stringOptional\"", query[stringOptional]) AssertSQL("\"query\".*", query[*]) } func test_tableNamespacedByDatabase() { let table = Table("table", database: "attached") AssertSQL("SELECT * FROM \"attached\".\"table\"", table) } } class QueryIntegrationTests : SQLiteTestCase { let id = Expression("id") let email = Expression("email") override func setUp() { super.setUp() CreateUsersTable() } // MARK: - func test_select() { for _ in try! db.prepare(users) { // FIXME } let managerId = Expression("manager_id") let managers = users.alias("managers") let alice = try! db.run(users.insert(email <- "alice@example.com")) _ = try! db.run(users.insert(email <- "betsy@example.com", managerId <- alice)) for user in try! db.prepare(users.join(managers, on: managers[id] == users[managerId])) { _ = user[users[managerId]] } } func test_scalar() { XCTAssertEqual(0, try! db.scalar(users.count)) XCTAssertEqual(false, try! db.scalar(users.exists)) try! InsertUsers("alice") XCTAssertEqual(1, try! db.scalar(users.select(id.average))) } func test_pluck() { let rowid = try! db.run(users.insert(email <- "alice@example.com")) XCTAssertEqual(rowid, try! db.pluck(users)![id]) } func test_insert() { let id = try! db.run(users.insert(email <- "alice@example.com")) XCTAssertEqual(1, id) } func test_update() { let changes = try! db.run(users.update(email <- "alice@example.com")) XCTAssertEqual(0, changes) } func test_delete() { let changes = try! db.run(users.delete()) XCTAssertEqual(0, changes) } }