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

Allow Pin of unsaved Parse.Object with an unsaved, but pinned, Parse.Object pointer #1118

Closed
BenApes opened this issue Mar 19, 2020 · 3 comments · Fixed by #1225
Closed

Allow Pin of unsaved Parse.Object with an unsaved, but pinned, Parse.Object pointer #1118

BenApes opened this issue Mar 19, 2020 · 3 comments · Fixed by #1225
Labels
type:bug Impaired feature or lacking behavior that is likely assumed

Comments

@BenApes
Copy link

BenApes commented Mar 19, 2020

Issue Description

When using my Parse JS SDK powered application offline, I can create a Parse Object and 'pin' it, allowing me to get the object from the local datastore when I want it, and save it later when I have connection. I cannot, however, create another object of a different class, assign the first object to a property of the second object and then pin the second object into the local datastore, as it results in the 'Cannot create a pointer to an unsaved ParseObject' error.

Steps to reproduce

  1. Initialise Parse application & enable the local datastore
Parse.initialize(environment.parseConfig.appId);
(Parse as any).serverURL = environment.parseConfig.serverUrl;
Parse.enableLocalDatastore();
  1. Define Two Classes, 'ClassA' and 'ClassB'
export class ClassA extends Parse.Object {

    constructor() {
        super('ClassA');
    }

    public get name(): string { return this.get('name'); }
    public set name(value: string) { this.set('name', value); }

}

Parse.Object.registerSubclass('ClassA', ClassA);

export class ClassB extends Parse.Object {

    constructor() {
        super('ClassB');
    }

    public get name(): string { return this.get('name'); }
    public set name(value: string) { this.set('name', value); }

    public get classA(): ClassA { return this.get('classA'); }
    public set classA(value: ClassA) { this.set('classA', value); }

}

Parse.Object.registerSubclass('ClassB', ClassB);
  1. Create instance of ClassA and pin to local datastore
const testClassA: ClassA = new ClassA();
testClassA.name = 'ABC';

await testClassA.pin();
  1. Query local datastore, find the unsaved but pinned instance of ClassA and assign to a variable
const localClassAQuery: Parse.Query<ClassA> = new Parse.Query(ClassA);
localClassAQuery.fromLocalDatastore();
localClassAQuery.equalTo('name', 'ABC');

const localClassA: ClassA = await localClassAQuery.first();
  1. Create an instance of ClassB, assign the local instance of classA to it, and attempt to pin to local datastore
    const testClassB: ClassB = new ClassB();
    testClassB.name = 'XYZ';
    testClassB.classA = localClassA;

    await testClassB.pin();

Expected Results

The instance of ClassB 'testClassB' pins to the local datastore without issue, and it's pointer to ClassA points to the local, unsaved, instance of ClassA.

Actual Outcome

The instance of ClassB does not pin to the local datastore, with the error 'Cannot create a pointer to an unsaved ParseObject'.

Environment Setup

  • Server

    • parse-server version: 4.1.0
    • Operating System: Windows 10
    • Hardware: Lenovo Laptop
    • Tested only on Localhost, but would like this to work when live on Heroku/Firebase for server/app, and when deployed using cordova to Android/iOS.
  • JS SDK

    • JS SDK version: 2.11.0
    • Application: Ionic (5+)/Angular(9+)/TypeScript(3.7.5) (front-end) && Node/TypeScript (server).

Logs/Trace

ERROR Error: "Uncaught (in promise): Error: Cannot create a pointer to an unsaved ParseObject

@BenApes BenApes changed the title Allow Pin of unsaved Parse.Object with an unsaved, but pinned, Parse.Object relation Allow Pin of unsaved Parse.Object with an unsaved, but pinned, Parse.Object pointer Mar 19, 2020
@dplewis dplewis added the type:bug Impaired feature or lacking behavior that is likely assumed label Apr 30, 2020
dplewis added a commit that referenced this issue Sep 12, 2020
Closes: #1118

Let me know if more tests are needed
dplewis added a commit that referenced this issue Sep 17, 2020
* fix(LocalDatastore): Allow Pin of unsaved Parse.Object

Closes: #1118

Let me know if more tests are needed

* Generate localId for subclasses

* Improve coverage
@Gabriel-Ramaldes
Copy link

Issue Description

After the ‘pin’ of the unsaved Parse.Object using fetchFromLocalDatastore() we get the error 'Error: Cannot create a pointer to an unsaved ParseObject'. If you refresh the browser and do the same you'll get the error 'Error:Uncaught (in promise): TypeError: object._getId is not a function'.

Steps to reproduce

Folowing @BenApes steps do the next step:

async recovery() {
    const qry  =  new Query(ClassB).fromLocalDatastore()
    const objs = await qry.find()
    for (const o of objs) {
      const obj = await o.fetchFromLocalDatastore()
      console.log(obj)
    }
  }

Expected Results

The recovered object instance of ClassB should be retrieved with all of the saved attributes and it's pointer to ClassA points to the local instance of ClassA.

Actual Outcome

The instance of ClassB cannot be retrieved with all of it's attributes using the fetchFromLocalDataStore() with the error 'Cannot create a pointer to an unsaved ParseObject'. If you refresh the browser and do the same you'll get the error 'Uncaught (in promise): TypeError: object._getId is not a function'.

Environment Setup

- Server

  • Operating System: Linux PopOS
  • Hardware: Avell Laptop
  • Tested only on Localhost.

- JS SDK

  • JS SDK version: 4.0.1
  • Application: Angular(15.1)/TypeScript(4.9.4) (front-end) && Node/TypeScript (server).

Logs/Trace

ERROR Error:Uncaught (in promise): TypeError: object._getId is not a function

ERROR Error: "Uncaught (in promise): Error: Cannot create a pointer to an unsaved ParseObject

@jcarloshorus
Copy link

I believe that the inclusion of the object._localId option in the function getKeyForObject of the LocalDataStore class
solve the problem, because the received object does not extend Parse.Object, it does not have the _getId() method

 getKeyForObject(object: any) {
    const objectId = object.objectId  **|| object._localId** || object._getId();
    return `${OBJECT_PREFIX}${object.className}_${objectId}`;
  },

@dplewis
Copy link
Member

dplewis commented Mar 2, 2023

@jcarloshorus @GabrielPR I believe this issue has been resolved in #1662

Please update to the latest alpha release to try it. If there is still a problem, please open a new issue so that we may track it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:bug Impaired feature or lacking behavior that is likely assumed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants