Skip to content
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

Merged
merged 15 commits into from
Nov 26, 2019

Conversation

drochetti
Copy link
Contributor

@drochetti drochetti commented Nov 24, 2019

refactor model association logic


some cleanup and documentation added

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

lazy collection capable of loading model associations

Notes:

  • create a custom Collection that is capable of loading a model association on demand
  • these changes are needed in order for codegen to generate the correct Swift code

Notes:

  • still work in progress
  • new DSL for configuring associations: belongsTo, hasManny and hasOne
  • custom collection for lazy loading in progress

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

**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
@drochetti drochetti self-assigned this Nov 24, 2019
@drochetti drochetti added the datastore Issues related to the DataStore category label Nov 24, 2019
drochetti and others added 8 commits November 24, 2019 23:12
**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
Copy link
Contributor Author

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'
Copy link
Contributor Author

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.

Copy link
Member

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 :(

Copy link
Contributor Author

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

Comment on lines +37 to +39
if tokens.count == 1 {
tokens.insert("root", at: 0)
}
Copy link
Contributor Author

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.

Comment on lines +77 to +81
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
}
Copy link
Contributor Author

@drochetti drochetti Nov 25, 2019

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

Copy link
Contributor Author

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>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for simplifying this

Copy link
Contributor Author

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...) {
Copy link
Member

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?

Copy link
Contributor Author

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
Copy link
Member

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?

Copy link
Contributor Author

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
Copy link
Contributor Author

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

Copy link
Member

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?

@drochetti drochetti merged commit 18e9c10 into master Nov 26, 2019
palpatim added a commit that referenced this pull request Nov 26, 2019
* 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)
@palpatim palpatim deleted the feature/model-associations branch December 3, 2019 17:21
waleedbutt pushed a commit to hassan31/amplify-swift that referenced this pull request Sep 18, 2024
harsh62 pushed a commit that referenced this pull request Nov 22, 2024
* 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
harsh62 added a commit that referenced this pull request Nov 25, 2024
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
datastore Issues related to the DataStore category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants