mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-15 06:06:35 +08:00
188 lines
7.7 KiB
CoffeeScript
188 lines
7.7 KiB
CoffeeScript
ModelQuery = require '../../src/flux/models/query'
|
|
{Matcher} = require '../../src/flux/attributes'
|
|
Message = require '../../src/flux/models/message'
|
|
Thread = require '../../src/flux/models/thread'
|
|
Account = require '../../src/flux/models/account'
|
|
|
|
describe "ModelQuery", ->
|
|
beforeEach ->
|
|
@db = {}
|
|
|
|
describe "where", ->
|
|
beforeEach ->
|
|
@q = new ModelQuery(Thread, @db)
|
|
@m1 = Thread.attributes.id.equal(4)
|
|
@m2 = Thread.attributes.categories.contains('category-id')
|
|
|
|
it "should accept an array of Matcher objects", ->
|
|
@q.where([@m1,@m2])
|
|
expect(@q._matchers.length).toBe(2)
|
|
expect(@q._matchers[0]).toBe(@m1)
|
|
expect(@q._matchers[1]).toBe(@m2)
|
|
|
|
it "should accept a single Matcher object", ->
|
|
@q.where(@m1)
|
|
expect(@q._matchers.length).toBe(1)
|
|
expect(@q._matchers[0]).toBe(@m1)
|
|
|
|
it "should append to any existing where clauses", ->
|
|
@q.where(@m1)
|
|
@q.where(@m2)
|
|
expect(@q._matchers.length).toBe(2)
|
|
expect(@q._matchers[0]).toBe(@m1)
|
|
expect(@q._matchers[1]).toBe(@m2)
|
|
|
|
it "should accept a shorthand format", ->
|
|
@q.where({id: 4, lastMessageReceivedTimestamp: 1234})
|
|
expect(@q._matchers.length).toBe(2)
|
|
expect(@q._matchers[0].attr.modelKey).toBe('id')
|
|
expect(@q._matchers[0].comparator).toBe('=')
|
|
expect(@q._matchers[0].val).toBe(4)
|
|
|
|
it "should return the query so it can be chained", ->
|
|
expect(@q.where({id: 4})).toBe(@q)
|
|
|
|
it "should immediately raise an exception if an un-queryable attribute is specified", ->
|
|
expect(-> @q.where({snippet: 'My Snippet'})).toThrow()
|
|
|
|
it "should immediately raise an exception if a non-existent attribute is specified", ->
|
|
expect(-> @q.where({looksLikeADuck: 'of course'})).toThrow()
|
|
|
|
describe "order", ->
|
|
beforeEach ->
|
|
@q = new ModelQuery(Thread, @db)
|
|
@o1 = Thread.attributes.lastMessageReceivedTimestamp.descending()
|
|
@o2 = Thread.attributes.subject.descending()
|
|
|
|
it "should accept an array of SortOrders", ->
|
|
@q.order([@o1,@o2])
|
|
expect(@q._orders.length).toBe(2)
|
|
|
|
it "should accept a single SortOrder object", ->
|
|
@q.order(@o2)
|
|
expect(@q._orders.length).toBe(1)
|
|
|
|
it "should extend any existing ordering", ->
|
|
@q.order(@o1)
|
|
@q.order(@o2)
|
|
expect(@q._orders.length).toBe(2)
|
|
expect(@q._orders[0]).toBe(@o1)
|
|
expect(@q._orders[1]).toBe(@o2)
|
|
|
|
it "should return the query so it can be chained", ->
|
|
expect(@q.order(@o2)).toBe(@q)
|
|
|
|
describe "include", ->
|
|
beforeEach ->
|
|
@q = new ModelQuery(Message, @db)
|
|
|
|
it "should throw an exception if the attribute is not a joined data attribute", ->
|
|
expect( =>
|
|
@q.include(Message.attributes.unread)
|
|
).toThrow()
|
|
|
|
it "should add the provided property to the list of joined properties", ->
|
|
expect(@q._includeJoinedData).toEqual([])
|
|
@q.include(Message.attributes.body)
|
|
expect(@q._includeJoinedData).toEqual([Message.attributes.body])
|
|
|
|
describe "includeAll", ->
|
|
beforeEach ->
|
|
@q = new ModelQuery(Message, @db)
|
|
|
|
it "should add all the JoinedData attributes of the class", ->
|
|
expect(@q._includeJoinedData).toEqual([])
|
|
@q.includeAll()
|
|
expect(@q._includeJoinedData).toEqual([Message.attributes.body])
|
|
|
|
describe "response formatting", ->
|
|
it "should always return a Number for counts", ->
|
|
q = new ModelQuery(Message, @db)
|
|
q.where({accountId: 'abcd'}).count()
|
|
|
|
raw = [{count:"12"}]
|
|
expect(q.formatResult(q.inflateResult(raw))).toBe(12)
|
|
|
|
describe "sql", ->
|
|
beforeEach ->
|
|
@runScenario = (klass, scenario) ->
|
|
q = new ModelQuery(klass, @db)
|
|
Matcher.muid = 1
|
|
scenario.builder(q)
|
|
expect(q.sql().trim()).toBe(scenario.sql.trim())
|
|
|
|
it "should finalize the query so no further changes can be made", ->
|
|
q = new ModelQuery(Account, @db)
|
|
spyOn(q, 'finalize')
|
|
q.sql()
|
|
expect(q.finalize).toHaveBeenCalled()
|
|
|
|
it "should correctly generate queries with multiple where clauses", ->
|
|
@runScenario Account,
|
|
builder: (q) -> q.where({emailAddress: 'ben@nylas.com'}).where({id: 2})
|
|
sql: "SELECT `Account`.`data` FROM `Account` \
|
|
WHERE `Account`.`email_address` = 'ben@nylas.com' AND `Account`.`id` = 2"
|
|
|
|
it "should correctly escape single quotes with more double single quotes (LIKE)", ->
|
|
@runScenario Account,
|
|
builder: (q) -> q.where(Account.attributes.emailAddress.like("you're"))
|
|
sql: "SELECT `Account`.`data` FROM `Account` WHERE `Account`.`email_address` like '%you''re%'"
|
|
|
|
it "should correctly escape single quotes with more double single quotes (equal)", ->
|
|
@runScenario Account,
|
|
builder: (q) -> q.where(Account.attributes.emailAddress.equal("you're"))
|
|
sql: "SELECT `Account`.`data` FROM `Account` WHERE `Account`.`email_address` = 'you''re'"
|
|
|
|
it "should correctly generate COUNT queries", ->
|
|
@runScenario Thread,
|
|
builder: (q) -> q.where({accountId: 'abcd'}).count()
|
|
sql: "SELECT COUNT(*) as count FROM `Thread` \
|
|
WHERE `Thread`.`account_id` = 'abcd' "
|
|
|
|
it "should correctly generate LIMIT 1 queries for single items", ->
|
|
@runScenario Thread,
|
|
builder: (q) -> q.where({accountId: 'abcd'}).one()
|
|
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
|
WHERE `Thread`.`account_id` = 'abcd' \
|
|
ORDER BY `Thread`.`last_message_received_timestamp` DESC LIMIT 1"
|
|
|
|
it "should correctly generate `contains` queries using JOINS", ->
|
|
@runScenario Thread,
|
|
builder: (q) -> q.where(Thread.attributes.categories.contains('category-id')).where({id: '1234'})
|
|
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
|
INNER JOIN `Thread-Category` AS `M1` ON `M1`.`id` = `Thread`.`id` \
|
|
WHERE `M1`.`value` = 'category-id' AND `Thread`.`id` = '1234' \
|
|
ORDER BY `Thread`.`last_message_received_timestamp` DESC"
|
|
|
|
@runScenario Thread,
|
|
builder: (q) -> q.where([Thread.attributes.categories.contains('l-1'), Thread.attributes.categories.contains('l-2')])
|
|
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
|
INNER JOIN `Thread-Category` AS `M1` ON `M1`.`id` = `Thread`.`id` \
|
|
INNER JOIN `Thread-Category` AS `M2` ON `M2`.`id` = `Thread`.`id` \
|
|
WHERE `M1`.`value` = 'l-1' AND `M2`.`value` = 'l-2' \
|
|
ORDER BY `Thread`.`last_message_received_timestamp` DESC"
|
|
|
|
it "should correctly generate queries with the class's naturalSortOrder when one is available and no other orders are provided", ->
|
|
@runScenario Thread,
|
|
builder: (q) -> q.where({accountId: 'abcd'})
|
|
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
|
WHERE `Thread`.`account_id` = 'abcd' \
|
|
ORDER BY `Thread`.`last_message_received_timestamp` DESC"
|
|
|
|
@runScenario Thread,
|
|
builder: (q) -> q.where({accountId: 'abcd'}).order(Thread.attributes.lastMessageReceivedTimestamp.ascending())
|
|
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
|
WHERE `Thread`.`account_id` = 'abcd' \
|
|
ORDER BY `Thread`.`last_message_received_timestamp` ASC"
|
|
|
|
@runScenario Account,
|
|
builder: (q) -> q.where({id: 'abcd'})
|
|
sql: "SELECT `Account`.`data` FROM `Account` \
|
|
WHERE `Account`.`id` = 'abcd' "
|
|
|
|
it "should correctly generate queries requesting joined data attributes", ->
|
|
@runScenario Message,
|
|
builder: (q) -> q.where({id: '1234'}).include(Message.attributes.body)
|
|
sql: "SELECT `Message`.`data`, IFNULL(`MessageBody`.`value`, '!NULLVALUE!') AS `body` \
|
|
FROM `Message` LEFT OUTER JOIN `MessageBody` ON `MessageBody`.`id` = `Message`.`id` \
|
|
WHERE `Message`.`id` = '1234' ORDER BY `Message`.`date` ASC"
|