-
Notifications
You must be signed in to change notification settings - Fork 205
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
model associations: refactor + missing use cases #153
Conversation
**Notes:** - still work in progess - new DSL for configuring associations: `belongsTo`, `hasManny` and `hasOne` - custom collection for lazy loading in progress
**Notes:** - create a custom `Collection` that is capable of loading a model association on demand
**Notes:** - this is still work in progress, but enables basic cases of lazy loading of one-to-many associations - more cleanup, documentation and tests coming soon
**Notes:** - temporarily set the iOS platform to 13.0 until we make Combine an optional/weak dependency
**Notes:** - change the mutability strategy for model types. Make the properties that can be mutated to `var` and rely on `struct` value type to keep references unique
**Notes:** - after saving, return the recently stored model so users can consume a fresh instance with lazy associations correctly bound
**Notes:** - made `DataStoreResult` compatible with the platform standard `Result<Success, Failure>` - added integration layer between `List<ModelType>` and Combine - added small layer to integrate `DataStoreResult` and Combine
**Notes:** - SQL statements with multiple tables require columns aliases so column names from different tables don't collide - main table in a SQL statement is always aliases to "root" - this strategy might need some refactoring for more complex queries
case .belongsTo(let associatedKey), | ||
.hasOne(let associatedKey), | ||
.hasMany(let associatedKey): | ||
let key = associatedKey?.stringValue ?? associatedModel.modelName |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note to self: add camelCase
handling to modelName
@@ -17,7 +17,7 @@ Pod::Spec.new do |s| | |||
s.homepage = 'http://aws.amazon.com/mobile/sdk' | |||
s.license = 'Apache License, Version 2.0' | |||
s.author = { 'Amazon Web Services' => 'amazonwebservices' } | |||
s.platform = :ios, '11.0' | |||
s.platform = :ios, '13.0' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is meant to be temporary: right now apps won't compile because our code that consumes Combine is not fully protected by platform constraints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry about that--I've got it on my list to fix :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no worries. I just changed it for now so I can build it on the sample app
if tokens.count == 1 { | ||
tokens.insert("root", at: 0) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right now root
is added to top-level columns of a SQL statement. We need a more resilient and flexible aliasing logic. Both Hibernate and RoR ActiveRecord generate random names so they don't collapse with user named properties, we should look into that.
let keyName = (propertyPrefix ?? "") + schema.primaryKey.sqlName | ||
let indexOfId = columns.firstIndex(of: keyName) | ||
if let index = indexOfId, let id = row[index] as? String, let cached = cache[id] { | ||
return cached | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this gave a huge performance boost to SQL result set -> model conversion. I believe this is still need more testing and most likely there are more performance improvements to be made, but I would say that so far so good. A query of 1300 rows, including a joint table with 50 rows took less than 80ms to de-serialize (as opposed to 200ms of the previous implementation).
That said, I'm not 100% happy with this logic, readability and caching strategy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#157 created to track it
case error(_ error: DataStoreError) | ||
} | ||
/// - seealso: [DataStoreCallback](#DataStoreCallback) | ||
public typealias DataStoreResult<Success> = Result<Success, DataStoreError> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for simplifying this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
np, I didn't know about Result
when I created this. Luckily DataStoreResult
always had the same semantics as Result<Success, Failure>
, so the change was straightforward. The only impact was changing the enum cases everywhere.
|
||
// MARK: - ExpressibleByArrayLiteral | ||
|
||
required convenience public init(arrayLiteral elements: Element...) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does it mean to instantiate a list from an array? I assume it's for the use case of creating a model with associations in memory, and persisting it after creation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It means the List<Model>
holds no reference to an association. The idea is that even though it has no reference to an association, therefore it looks like an ordinary array, it will hold pagination information (like limit
, offset
and totalCount
). However, we haven't defined the pagination API on DataStore.query
yet. Also, in the future it can have "cascading" capabilities.
That said, I need to finalize documentation for this and update the PR.
@@ -57,7 +57,7 @@ extension ModelField: SQLColumn { | |||
} | |||
|
|||
var isForeignKey: Bool { | |||
isRelationshipOwner | |||
isAssociationOwner |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this mean for a many-many association?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it means it's the association table. Detecting many-to-many right now is not perfect. We don't support "implicit" many-to-many (i.e. association table/model is defined by us for the user implicitly). Right now users have to create their own association model (like PostEditor
defined in the docs here https://aws-amplify.github.io/docs/cli-toolchain/graphql#usage-2)
**Notes:** - moved some test bootstrap logic to a common parent class - added docs to the `List<ModelType>` - added tests for difference usage (async vs sync) of `List<ModelType>`
// Inc. or its affiliates. All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import CoreGraphics |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: the lack of this import currently breaks the build. I suppose this is a known issue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kneekey23, @royjit are you aware of this?
* master: API Predicate to GraphQL filter variables (#150) model associations: refactor + missing use cases (#153) Basic unit tests for comprehend and translate (#160) CoreML logic to Detect faces (#155) API Category - Updates to APIError and GraphQLResponse (#133) Initial commit for unit test for translate service behavior (#158) bug fix change (#152)
* feat(Auth): Adding List WebAuthn API * feat(Auth): Adding associate and delete WebAuthn credentials APIs * Addding missing transports array in the credentials payload * Adding friendlyName to AuthWebAuthnCredential * Adding excludedCredentials to avoid multiple PassKeys for the same device * Adding pagination support in the list API * Renaming CredentialPayload to CredentialRegistrationPayload * Addressing PR comments
* feat(auth): adding support for email mfa (#3892) * feat(auth): adding support for email mfa * fix swift lint warning * worked on a review comment * adding integration tests wave 1 * integration tests wave 2 * integration tests wave 3 * Add test setup instructions wave 4 * Add edge case * update readme to include graphQL details * chore: initial commit to add sdk with passwordless models * chore: model update * feat(Auth): Adding WebAuthn APIs (#153) * feat(Auth): Adding List WebAuthn API * feat(Auth): Adding associate and delete WebAuthn credentials APIs * Addding missing transports array in the credentials payload * Adding friendlyName to AuthWebAuthnCredential * Adding excludedCredentials to avoid multiple PassKeys for the same device * Adding pagination support in the list API * Renaming CredentialPayload to CredentialRegistrationPayload * Addressing PR comments * feat(auth): add passwordless sign with otp (#151) * feat(auth): add passwordless OTP implementation * add fallback password and password srp flows * add web auth n states * modifying states * feat(Auth): Adding WebAuthn support to signIn and confirmSignIn APIs (#155) * feat(auth): add passwordless OTP implementation * add fallback password and password srp flows * add web auth n states * modifying states * feat(Auth): Implementing signIn with WebAuthn * Adding support for a presentation anchor in sign in and confirm sign in options * Fixing errors * Addressing PR comments * fix build error --------- Co-authored-by: Harshdeep Singh <6162866+harsh62@users.noreply.github.com> * fix: Fixing build issue when iOS 18/macOS 15 are not installed * feat(WebAuthn): Adding support for retrying a confirmSignIn with WebAuthn request, if the first one fails (#158) * feat(auth): add support for passwordless sign up and auto sign in (#160) * add autoSignIn() category API definitions (#152) * add autoSignIn() category API definitions * add sign up step for auto sign in * add state machine changes for autoSignIn() and signUp() (#154) * add autoSignIn() category API definitions * add sign up step for auto sign in * add state machine changes * add events and update resolvers * update sign up events and resolvers * add updates to resolver for auto sign in * update confirm sign up flow and debug code * Address review comments --------- Co-authored-by: Harsh <6162866+harsh62@users.noreply.github.com> * update auto sign state machine events and resolver (#157) * update auto sign state machine events and resolver * Address review comments * update sign up and auto sign in unit tests (#159) * update sign up and auto sign in unit tests * add auto sign in tests and refactor existing tests * Add more service error tests * Address review changes --------- Co-authored-by: Harsh <6162866+harsh62@users.noreply.github.com> * chore: fix building of unit tests after sign up rebase * feat(auth): adding passwordless sign in preferred flows (#162) * feat(auth): add passwordless preferred flow * adding confirm device and device srp flows to user auth * update message * worked on review comments * update * chore(auth): add more auto sign in and sign up state machine/e2e unit tests (#161) * chore(auth): add more auto sign in and sign up state machine/e2e unit tests * Address review comments * chore: updated SDK and models * chore: update integration test host app * fix: Fixing build errors in watchOS/tvOS due to missing prechecks. * feat(auth): adding an initial passwordless integration test with resources defined (#163) * chore: update no-auth API's in the resolver * chore: Updating to the renamed WebAuthn APIs (#164) * chore: Updating to the renamed WebAuthn APIs * Fixing unit tests * chore: Adding unit tests for the WebAuthn APIs Tasks (#165) * test: Adding AssociateWebAuthn unit tests * test: Adding ListWebAuthnCredentials unit tests * test: Adding DeleteWebAuthnCredential unit tests * chore: simplifying how webauthn errors are handled * adressing PR comments * chore(auth): add integration tests for passwordless signup and auto sign in (#166) * chore(auth): add integration tests for passwordless signup and auto sign in * remove unused code * refactor code * chore: add integration tests for sign in flows (#168) * chore: add integration tests for sign in flows * Update AuthSignInWithPasswordUsingUserAuthTests.swift * Add more integration tests * update * chore: update sdk to use the latest models * test: Adding integration tests for WebAuthn APIs (#169) * test: Adding integration tests for WebAuthn APIs * chore: Adding webauthn integration workflow * Refactoring the code to remove unnecesary waits and make it more easy to read * fix: Fixing service errors being reported as .unknown when sign in fails (#170) * fix: Fixing service errors being reported as .unknown when sign in fails. Also adding proper WebAuthn cases to the AWSCognitoAuthError enum. * addressing PR comment * fix(auth): fix resolvers and tasks for auto sign in when state machine is in signing in state (#172) * fix(auth): fix resolvers and tasks for auto sign in when state machine is in signin in state * fix indentation * feat: Adding visionOS support to the WebAuthn APIs (#171) * chore: using the latest version aws sdk * chore: update changes needed for the sdk updated * chore: fix swiftlint errors (#3921) * chore: running passwordless integration tests on GEN2 backend * chore: update test target for watchOS * chore: fix OTP integration tests * chore: update more integration tests --------- Co-authored-by: Sebastian Villena <97059974+ruisebas@users.noreply.github.com> Co-authored-by: Abhash Kumar Singh <thisisabhash@gmail.com>
refactor model association logic
some cleanup and documentation added
Notes:
lazy collection capable of loading model associations
Notes:
Collection
that is capable of loading a model association on demandNotes:
belongsTo
,hasManny
andhasOne
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.