Skip to content

Commit 072943c

Browse files
Merge pull request #94 from Azure/feature/93-create-empty-child-directories
Create empty child directory for offline resources
2 parents 4bf2817 + ec084f1 commit 072943c

5 files changed

Lines changed: 149 additions & 7 deletions

File tree

AzureData/Source/ResourceCache.swift

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,20 @@ extension FileManager {
252252

253253
fileprivate func fileUrl(for path: (directory:String, file:String)) throws -> URL {
254254

255-
let directory = try cacheFileUrl(for: path.directory)
256-
257-
if !self.fileExists(atPath: directory.path) {
258-
try self.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil)
255+
let directoryUrl = try cacheFileUrl(for: path.directory)
256+
257+
// Create the directory for the resource if it does not exist.
258+
if !self.fileExists(atPath: directoryUrl.path) {
259+
try self.createDirectory(at: directoryUrl, withIntermediateDirectories: true, attributes: nil)
259260
}
260-
261+
262+
// Create empty child directories for the resource if they don't exist.
263+
try path.directory.resourceType?
264+
.children
265+
.map { directoryUrl.appendingPathComponent($0.rawValue) }
266+
.filter { !fileExists(atPath: $0.path) }
267+
.forEach { try createDirectory(at: $0, withIntermediateDirectories: true, attributes: nil) }
268+
261269
return try cacheFileUrl(for: path.file)
262270
}
263271

AzureData/Source/ResourceType.swift

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public enum ResourceType : String {
1919
case document = "docs"
2020
case attachment = "attachments"
2121
case offer = "offers"
22-
22+
2323
var path: String {
2424
return self.rawValue
2525
}
@@ -49,7 +49,22 @@ public enum ResourceType : String {
4949
case .collection, .document, .storedProcedure, .trigger, .udf, .attachment: return true
5050
}
5151
}
52-
52+
53+
var children: [ResourceType] {
54+
switch self {
55+
case .database: return [.collection, .user]
56+
case .user: return [.permission]
57+
case .permission: return []
58+
case .collection: return [.document, .storedProcedure, .trigger, .udf]
59+
case .document: return [.attachment]
60+
case .storedProcedure: return []
61+
case .trigger: return []
62+
case .udf: return []
63+
case .attachment: return []
64+
case .offer: return []
65+
}
66+
}
67+
5368
static var ancestors: [ResourceType] {
5469
return [ .database, .user, .collection, .document ]
5570
}

AzureData/Source/UtilityExtensions.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ extension String {
108108
return (ResourceType(rawValue: String(components[count - 4])), String(components[count - 3]))
109109
}
110110

111+
var resourceType: ResourceType? {
112+
guard let (directory, _) = self.path else { return nil }
113+
return ResourceType(rawValue: directory.lastPathComponent)
114+
}
115+
111116
/// "dbs/TC1AAA==/colls/TC1AAMDvwgA=".path = ("dbs/TC1AAA==/colls", "TC1AAMDvwgA=")
112117
var path: (directory: String, file: String)? {
113118
let components = self.split(separator: "/")

AzureData/Tests/OfflineReadTests.swift

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,110 @@ class OfflineReadTests: _AzureDataTests {
281281
wait(for: [deleteExpectation], timeout: timeout)
282282
}
283283

284+
func testEmptyChildDirectoriesAreCreatedWhenANewDatabaseIsCachedOffline() {
285+
let createExpectation = self.expectation(description: "empty child directories are created when a new database is cached offline.")
286+
287+
ensureDatabaseExists { database in
288+
AzureData.get(databaseWithId: database.id) { r in
289+
XCTAssertTrue(r.result.isSuccess)
290+
291+
self.wait {
292+
let databaseDirectoryUrl = URL(string: "dbs/\(database.resourceId)/", relativeTo: self.cachesDirectoryURL)!
293+
let collectionsDirectoryUrl = URL(string: "colls/", relativeTo: databaseDirectoryUrl)!
294+
let usersDirectoryUrl = URL(string: "users/", relativeTo: databaseDirectoryUrl)!
295+
296+
XCTAssertTrue(FileManager.default.fileExists(atPath: databaseDirectoryUrl.path))
297+
XCTAssertTrue(FileManager.default.fileExists(atPath: collectionsDirectoryUrl.path))
298+
XCTAssertTrue(FileManager.default.fileExists(atPath: usersDirectoryUrl.path))
299+
300+
createExpectation.fulfill()
301+
}
302+
}
303+
}
304+
305+
wait(for: [createExpectation], timeout: timeout)
306+
}
307+
308+
func testEmptyChildDirectoriesAreCreatedWhenANewCollectionIsCachedOffline() {
309+
let createExpectation = self.expectation(description: "empty child directories are created when a new collection is cached offline.")
310+
311+
ensureDatabaseExists { database in
312+
self.ensureCollectionExists { collection in
313+
AzureData.get(collectionWithId: collection.id, inDatabase: database.id) { r in
314+
XCTAssertTrue(r.result.isSuccess)
315+
316+
self.wait {
317+
let collectionDirectoryUrl = URL(string: "dbs/\(database.resourceId)/colls/\(collection.resourceId)/", relativeTo: self.cachesDirectoryURL)!
318+
let documentsDirectoryUrl = URL(string: "docs/", relativeTo: collectionDirectoryUrl)!
319+
let sprocsDirectoryUrl = URL(string: "sprocs/", relativeTo: collectionDirectoryUrl)!
320+
let triggersDirectoryUrl = URL(string: "triggers/", relativeTo: collectionDirectoryUrl)!
321+
let udfsDirectoryUrl = URL(string: "udfs/", relativeTo: collectionDirectoryUrl)!
322+
323+
XCTAssertTrue(FileManager.default.fileExists(atPath: collectionDirectoryUrl.path))
324+
XCTAssertTrue(FileManager.default.fileExists(atPath: documentsDirectoryUrl.path))
325+
XCTAssertTrue(FileManager.default.fileExists(atPath: sprocsDirectoryUrl.path))
326+
XCTAssertTrue(FileManager.default.fileExists(atPath: triggersDirectoryUrl.path))
327+
XCTAssertTrue(FileManager.default.fileExists(atPath: udfsDirectoryUrl.path))
328+
329+
createExpectation.fulfill()
330+
}
331+
}
332+
}
333+
}
334+
335+
wait(for: [createExpectation], timeout: timeout)
336+
}
337+
338+
func testEmptyChildDirectoriesAreCreatedWhenANewDocumentIsCachedOffline() {
339+
let createExpectation = self.expectation(description: "empty child directories are created when a new document is cached offline.")
340+
341+
ensureDatabaseExists { database in
342+
self.ensureCollectionExists { collection in
343+
self.ensureDocumentExists { document in
344+
AzureData.get(documentWithId: document.id, as: Document.self, inCollection: collection.id, inDatabase: database.id) { r in
345+
XCTAssertTrue(r.result.isSuccess)
346+
347+
self.wait {
348+
let documentDirectoryUrl = URL(string: "dbs/\(database.resourceId)/colls/\(collection.resourceId)/docs/\(document.resourceId)/", relativeTo: self.cachesDirectoryURL)!
349+
let attachments = URL(string: "attachments/", relativeTo: documentDirectoryUrl)!
350+
351+
XCTAssertTrue(FileManager.default.fileExists(atPath: documentDirectoryUrl.path))
352+
XCTAssertTrue(FileManager.default.fileExists(atPath: attachments.path))
353+
354+
createExpectation.fulfill()
355+
}
356+
}
357+
}
358+
}
359+
}
360+
361+
wait(for: [createExpectation], timeout: timeout)
362+
}
363+
364+
func testEmptyChildDirectoriesAreCreatedWhenANewUserIsCachedOffline() {
365+
let createExpectation = self.expectation(description: "empty child directories are created when a new user is cached offline.")
366+
367+
ensureDatabaseExists { database in
368+
self.ensureUserExists { user in
369+
AzureData.get(userWithId: user.id, inDatabase: database.id) { r in
370+
XCTAssertTrue(r.result.isSuccess)
371+
372+
self.wait {
373+
let userDirectoryUrl = URL(string: "dbs/\(database.resourceId)/users/\(user.resourceId)/", relativeTo: self.cachesDirectoryURL)!
374+
let permissionsDirectoryUrl = URL(string: "permissions/", relativeTo: userDirectoryUrl)!
375+
376+
XCTAssertTrue(FileManager.default.fileExists(atPath: userDirectoryUrl.path))
377+
XCTAssertTrue(FileManager.default.fileExists(atPath: permissionsDirectoryUrl.path))
378+
379+
createExpectation.fulfill()
380+
}
381+
}
382+
}
383+
}
384+
385+
wait(for: [createExpectation], timeout: timeout)
386+
}
387+
284388
// MARK: - Private helpers
285389

286390
private func ensureResourcesAreCachedLocallyWhenNetworkIsReachable<T: CodableResource>(

AzureData/Tests/_AzureDataTests.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ class _AzureDataTests: XCTestCase {
8080
)
8181
}
8282

83+
func ensureUserExists(completion: ((User) -> ())? = nil) {
84+
ensureDatabaseExists()
85+
ensureResourceExists(
86+
type: User.self,
87+
get: { AzureData.get(userWithId: self.userId, inDatabase: self.databaseId, callback: $0) },
88+
create: { AzureData.create(userWithId: self.userId, inDatabase: self.databaseId, callback: $0) },
89+
completion: completion
90+
)
91+
}
92+
8393
func ensureDatabaseIsDeleted() {
8494
ensureResourceIsDeleted(Database.self, delete: { AzureData.delete(databaseWithId: self.databaseId, callback: $0) })
8595
}

0 commit comments

Comments
 (0)