Skip to content

feat: add ParseSchema to SDK #370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 55 commits into from
May 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
56ed0a4
wip
cbaker6 May 21, 2022
fa3c29b
more updates
cbaker6 May 21, 2022
5ae88c3
more updates
cbaker6 May 21, 2022
f81fc16
addIndex and deleteIndex
cbaker6 May 22, 2022
c621cfe
read only fields and indexes
cbaker6 May 22, 2022
d4e3b8c
wip CLP
cbaker6 May 22, 2022
3e8d4d3
adding read checks
cbaker6 May 22, 2022
b28010d
finished CLP
cbaker6 May 22, 2022
f6c645b
add inits to CLP
cbaker6 May 22, 2022
f71fe16
add more inits
cbaker6 May 22, 2022
33d589c
doc nits
cbaker6 May 22, 2022
eda6213
add async/await methods
cbaker6 May 22, 2022
17a4aa6
add Combine methods
cbaker6 May 22, 2022
9c6750e
fixes
cbaker6 May 23, 2022
9fd246b
fix CLP
cbaker6 May 23, 2022
d15abe4
make all CLP methods public
cbaker6 May 23, 2022
45e386d
improve docs
cbaker6 May 23, 2022
7d02bd7
improve CLP
cbaker6 May 26, 2022
ee67532
CLP protocol start
cbaker6 May 27, 2022
874eced
Using CLP protocol
cbaker6 May 27, 2022
ae36cad
improve CLP signatures
cbaker6 May 27, 2022
94b6741
working ParseSchema
cbaker6 May 28, 2022
b4327f1
fix schema index
cbaker6 May 28, 2022
c831fab
docs
cbaker6 May 28, 2022
de6710e
allow SPI to build docs
cbaker6 May 28, 2022
66717c4
docs update
cbaker6 May 28, 2022
d7db46a
more docs
cbaker6 May 28, 2022
2b7bc35
Finish ParseCLP docs
cbaker6 May 28, 2022
5e149c4
nits
cbaker6 May 28, 2022
07a963f
doc schema nits
cbaker6 May 28, 2022
0764534
Finished docs and added changelog
cbaker6 May 28, 2022
9f33fb8
add deleteField to playgrounds
cbaker6 May 28, 2022
c775f65
fix pending indexes
cbaker6 May 28, 2022
6322479
improve protected fields
cbaker6 May 28, 2022
bce210a
test codecov
cbaker6 May 29, 2022
a75014e
revert codecov
cbaker6 May 29, 2022
1602139
add some CLP tests
cbaker6 May 29, 2022
78d2c05
refactor
cbaker6 May 29, 2022
5b729c4
more CLP tests
cbaker6 May 29, 2022
e6b6ee7
call sights
cbaker6 May 29, 2022
6f40c7e
more tests
cbaker6 May 29, 2022
77eb99b
finish CLP access tests
cbaker6 May 29, 2022
3516ef6
remove unnecessary code
cbaker6 May 29, 2022
86858b2
organize ParseCLP
cbaker6 May 29, 2022
e05854f
nit
cbaker6 May 29, 2022
b1e2c43
nit
cbaker6 May 29, 2022
f20b45c
set protectedFields internal set
cbaker6 May 29, 2022
70c570e
finish CLP tests
cbaker6 May 29, 2022
04ad43a
refactor ParseSchema
cbaker6 May 29, 2022
ff3f983
finish ParseSchema tests
cbaker6 May 30, 2022
cf29652
increase coverage
cbaker6 May 30, 2022
e746c0d
remove unused code
cbaker6 May 30, 2022
b0eafde
remove more code
cbaker6 May 30, 2022
cd9bbd0
fix combine tests
cbaker6 May 30, 2022
ae88e8e
add userField to CLP
cbaker6 May 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .spi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ builder:
configs:
- platform: ios
scheme: "ParseSwift (iOS)"
documentation_targets: ["ParseSwift (iOS)"]
- platform: macos-xcodebuild
scheme: "ParseSwift (macOS)"
- platform: macos-xcodebuild-arm
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.5.0...main)
* _Contributing to this repo? Add info about your change here to be included in the next release_

__New features__
- Add ParseSchema, ParseCLP, and ParseFieldOptions. Should only be used when using the Swift SDK on a secured server ([#370](https://github.com/parse-community/Parse-Swift/pull/370)), thanks to [Corey Baker](https://github.com/cbaker6).

### 4.5.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.4.0...4.5.0)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
//: [Previous](@previous)

import PlaygroundSupport
import Foundation
import ParseSwift

PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()

//: Youe specific _User value type.
struct User: ParseUser {
//: These are required by `ParseObject`.
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: These are required by `ParseUser`.
var username: String?
var email: String?
var emailVerified: Bool?
var password: String?
var authData: [String: [String: String]?]?

//: Your custom keys.
var customKey: String?

//: Implement your own version of merge
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.customKey,
original: object) {
updated.customKey = object.customKey
}
return updated
}
}

//: Create your own value typed `ParseObject`.
struct GameScore2: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?

//: Your own properties.
var points: Int?
var level: Int?
var data: ParseBytes?
var owner: User?
var rivals: [User]?

//: Implement your own version of merge
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
if updated.shouldRestoreKey(\.level,
original: object) {
updated.level = object.level
}
if updated.shouldRestoreKey(\.data,
original: object) {
updated.data = object.data
}
if updated.shouldRestoreKey(\.owner,
original: object) {
updated.owner = object.owner
}
if updated.shouldRestoreKey(\.rivals,
original: object) {
updated.rivals = object.rivals
}
return updated
}
}

//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameScore2 {

init(points: Int) {
self.points = points
}

init(objectId: String?) {
self.objectId = objectId
}
}

//: First lets create a new CLP for the new schema.
let clp = ParseCLP(requiresAuthentication: true, publicAccess: false)
.setAccessPublic(true, on: .get)
.setAccessPublic(true, on: .find)

//: Next we use the CLP to create the new schema and add fields to it.
var gameScoreSchema = ParseSchema<GameScore2>(classLevelPermissions: clp)
.addField("points",
type: .number,
options: ParseFieldOptions<Int>(required: false, defauleValue: nil))
.addField("level",
type: .number,
options: ParseFieldOptions<Int>(required: false, defauleValue: nil))
.addField("data",
type: .bytes,
options: ParseFieldOptions<String>(required: false, defauleValue: nil))

do {
gameScoreSchema = try gameScoreSchema
.addField("owner",
type: .pointer,
options: ParseFieldOptions<User>(required: false, defauleValue: nil))
.addField("rivals",
type: .array,
options: ParseFieldOptions<[User]>(required: false, defauleValue: nil))
} catch {
print("Can't add field: \(gameScoreSchema)")
}

//: Now lets create the schema on the server.
gameScoreSchema.create { result in
switch result {
case .success(let savedSchema):
print("Check GameScore2 in Dashboard. \nThe created schema: \(savedSchema)")
case .failure(let error):
print("Couldn't save schema: \(error)")
}
}

//: We can update the CLP to only allow access to users specified in the "owner" field.
let clp2 = clp.setPointerFields(Set(["owner"]), on: .get)
gameScoreSchema.classLevelPermissions = clp2

//: In addition, we can add an index.
gameScoreSchema = gameScoreSchema.addIndex("myIndex", field: "level", index: 1)

//: Next, we need to update the schema on the server with the changes.
gameScoreSchema.update { result in
switch result {
case .success(let updatedSchema):
print("Check GameScore2 in Dashboard. \nThe updated schema: \(updatedSchema)")
/*:
Updated the current gameScoreSchema with the newest.
*/
gameScoreSchema = updatedSchema
case .failure(let error):
print("Couldn't update schema: \(error)")
}
}

//: Indexes can also be deleted.
gameScoreSchema = gameScoreSchema.deleteIndex("myIndex")

//: Next, we need to update the schema on the server with the changes.
gameScoreSchema.update { result in
switch result {
case .success(let updatedSchema):
print("Check GameScore2 in Dashboard. \nThe updated schema: \(updatedSchema)")
/*:
Updated the current gameScoreSchema with the newest.
*/
gameScoreSchema = updatedSchema
case .failure(let error):
print("Couldn't update schema: \(error)")
}
}

/*:
Fields can also be deleted on a schema. Lets remove
the **data** field since it's not going being used.
*/
gameScoreSchema = gameScoreSchema.deleteField("data")

//: Next, we need to update the schema on the server with the changes.
gameScoreSchema.update { result in
switch result {
case .success(let updatedSchema):
print("Check GameScore2 in Dashboard. \nThe updated schema: \(updatedSchema)")
/*:
Updated the current gameScoreSchema with the newest.
*/
gameScoreSchema = updatedSchema
case .failure(let error):
print("Couldn't update schema: \(error)")
}
}

/*:
Sets of fields can also be protected from access. Lets protect
some fields from access.
*/
var clp3 = gameScoreSchema.classLevelPermissions
clp3 = clp3?
.setProtectedFieldsPublic(["owner"])
.setProtectedFields(["level"], userField: "rivals")
gameScoreSchema.classLevelPermissions = clp3

//: Next, we need to update the schema on the server with the changes.
gameScoreSchema.update { result in
switch result {
case .success(let updatedSchema):
print("Check GameScore2 in Dashboard. \nThe updated schema: \(updatedSchema)")
/*:
Updated the current gameScoreSchema with the newest.
*/
gameScoreSchema = updatedSchema
case .failure(let error):
print("Couldn't update schema: \(error)")
}
}

//: Now lets save a new object to the new schema.
var gameScore = GameScore2()
gameScore.points = 120
gameScore.owner = User.current

gameScore.save { result in
switch result {
case .success(let savedGameScore):
print("The saved GameScore is: \(savedGameScore)")
case .failure(let error):
print("Couldn't save schema: \(error)")
}
}

//: You can delete all objects your schema by purging them.
gameScoreSchema.purge { result in
switch result {
case .success:
print("All objects have been purged from this schema.")
case .failure(let error):
print("Couldn't purge schema: \(error)")
}
}

/*:
As long as there's no data in your `ParseSchema` you can
delete the schema.
*/
gameScoreSchema.delete { result in
switch result {
case .success:
print("The schema has been deleted.")
case .failure(let error):
print("Couldn't delete the schema: \(error)")
}
}

//: [Next](@next)
Loading