dipscope / JsonApiEntityProvider.TS

Json api entity provider implementation for entity store.
Apache License 2.0
7 stars 4 forks source link

Improved Debugging Options #8

Closed DellanX closed 1 year ago

DellanX commented 1 year ago

Is your feature request related to a problem? Please describe.

I am implementing this library for my application; however, am running into an error. Which I am struggling to debug, and am hoping for either some troubleshooting tips or improved debugging tools. Oddly enough, I was able to prototype with the codebase fine, but now that I am migrating over, I run into the following error:

chunk-D4BW42UH.js?v=7f7ff6e2:161  Uncaught (in promise) Error: Documentb: cannot define json api resource metadata of a type. This is usually caused by invalid configuration.
    at JsonApiResourceMetadataNotFoundError2.EntityStoreError2 [as constructor] (chunk-D4BW42UH.js?v=7f7ff6e2:161:24)
    at new JsonApiResourceMetadataNotFoundError2 (json-api-resource-metadata-not-found-error.ts:26:9)
    at JsonApiAdapter2.extractJsonApiResourceMetadataOrFail (json-api-adapter.ts:96:19)
    at JsonApiEntityProvider2.createResourceLinkObject (json-api-entity-provider.ts:379:61)
    at JsonApiEntityProvider2.createResourceBrowseLinkObject (json-api-entity-provider.ts:459:31)
    at JsonApiEntityProvider2.<anonymous> (json-api-entity-provider.ts:306:33)
    at step (chunk-N2KBZTTK.js?v=7f7ff6e2:5625:19)
    at Object.next (chunk-N2KBZTTK.js?v=7f7ff6e2:5572:14)
    at chunk-N2KBZTTK.js?v=7f7ff6e2:5558:67
    at new Promise (<anonymous>)
EntityStoreError2 @ chunk-D4BW42UH.js?v=7f7ff6e2:161
JsonApiResourceMetadataNotFoundError2 @ json-api-resource-metadata-not-found-error.ts:26
JsonApiAdapter2.extractJsonApiResourceMetadataOrFail @ json-api-adapter.ts:96
JsonApiEntityProvider2.createResourceLinkObject @ json-api-entity-provider.ts:379
JsonApiEntityProvider2.createResourceBrowseLinkObject @ json-api-entity-provider.ts:459
(anonymous) @ json-api-entity-provider.ts:306
step @ chunk-N2KBZTTK.js?v=7f7ff6e2:5625
(anonymous) @ chunk-N2KBZTTK.js?v=7f7ff6e2:5572
(anonymous) @ chunk-N2KBZTTK.js?v=7f7ff6e2:5558
__awaiter @ chunk-N2KBZTTK.js?v=7f7ff6e2:5540
JsonApiEntityProvider2.executeBulkQueryCommand @ json-api-entity-provider.ts:303
BulkQueryCommand2.delegate @ chunk-QT4TKYTM.js?v=7f7ff6e2:134
(anonymous) @ chunk-QT4TKYTM.js?v=7f7ff6e2:920
step @ chunk-UZKLBU5R.js?v=7f7ff6e2:5625
(anonymous) @ chunk-UZKLBU5R.js?v=7f7ff6e2:5572
(anonymous) @ chunk-UZKLBU5R.js?v=7f7ff6e2:5558
__awaiter @ chunk-UZKLBU5R.js?v=7f7ff6e2:5540
BrowseCommandBuilder2.findAll @ chunk-QT4TKYTM.js?v=7f7ff6e2:915
EntitySet2.findAll @ chunk-QT4TKYTM.js?v=7f7ff6e2:1602

Describe the solution you'd like

I don't expect this issue to be debugged here. (Though I am happy to post the root cause when I get it figured out). It looks like this is probably caused by some configuration on my end, if I knew what was misconfigured, I could probably use the existing documentation to get it configured properly.

Describe alternatives you've considered

I've poked around, and completely rewritten my model code, and am at a complete loss. I figure there is some kind of definition conflict somewhere.

Additional context Here is my model definition My Prototype model documentb.ts

import type IModel from '../interfaces/imodel';
import { Type, Property } from '@dipscope/type-manager';
import { JsonApiResource } from '@dipscope/json-api-entity-provider';

@Type()
@JsonApiResource({ type: 'documentb' })
export class Documentb implements IModel {
  @Property(String) public type: string = 'documents';
  @Property(String) public id?: string;

  @Property(String) public slug?: string;
  @Property(String) public title?: string;
  @Property(String) public file?: string;

  @Property(String) public alias?: string;
  @Property(String) public imageUrl?: string;
  @Property(Date) public createdAt?: Date;
  @Property(Date) public updatedAt?: Date;
}

export default Documentb;

My EntityStore definition file entity-store.ts

import { EntityStore } from '@dipscope/entity-store';
import { JsonApiEntityProvider } from '@dipscope/json-api-entity-provider';
import {
  JsonApiNetFilterExpressionVisitor,
  JsonApiNetPaginateExpressionVisitor,
} from '@dipscope/json-api-entity-provider';

const baseUrl = `${import.meta.env.VITE_APP_URL}/api/web/v2`;
console.log(baseUrl);
// Create entity provider.
const jsonApiEntityProvider = new JsonApiEntityProvider({
  baseUrl, // Url to you backend endpoint.
  jsonApiRequestInterceptor: (request: Request) => request, // You might intercept requests by adding headers.
  jsonApiResponseInterceptor: (response: Response) => response, // You might intercept requests by adding headers.
  jsonApiFilterExpressionVisitor: new JsonApiNetFilterExpressionVisitor(), // You might override filtering strategy used by a server.
  jsonApiPaginateExpressionVisitor: new JsonApiNetPaginateExpressionVisitor(), // You might override pagination strategy used by a server.
});
// Create entity store.
export const entityStore = new EntityStore(jsonApiEntityProvider);
export default entityStore;

My local method for grabbing data fetch-many.ts

import type IModel from '../interfaces/imodel';
import { QueryClient } from '@tanstack/vue-query';
import { getType } from '../helpers/get-type';
import { getEntitySet } from '../store/get-entity-set';
import { wrapByRef } from '../helpers/wrap-by-ref';
import type { Nullable } from '../types/nullable';
import { entityStore } from '../store';
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: Infinity,
    },
  },
});
/**
 * This function requests a set of models given a query.
 * @param ctor The expected model type
 */
export async function fetchManyAsync<M extends IModel>(ctor: new () => M): Promise<Nullable<M[]> | readonly M[]> {
  const queryKey = [getType(ctor)];
  const entitySet = entityStore.createEntitySet(ctor);

  return entitySet.findAll().then(x => x.toArray())//.then(x => console.log(x));
  // return queryClient.fetchQuery({
  //   queryKey,
  //   queryFn: () => entitySet.findAll().then(x => x.toArray()),
  // });
}

Finally, my Vue Script below should execute the query

import { Documentb, fetchManyAsync } from '@core/services/v2/data';

const documents = await fetchManyAsync(Documentb);

I've tried many things, even copying over the example model from the README.md. My Prototype no longer works either, so I figure I misconfigured something disasterously wrong.

dpimonov commented 1 year ago

Hi DellanX, your configuration is correct. The error states that is cannot find config but you declared one as I see. As you are working in a static type manager context - you can try to extract metadata from your type directly and see if it in general present. Maybe there are some incorrect exports somewhere. You can check it by calling:

const typeMetadata = TypeManager.extractTypeMetadata(Documentb);

This will return you the whole type information declared for your class. Then check if your properties are registered and JsonApiResource metadata is present in customContext property. If it is not present then it is lost somehow or code organization might create a duplicate of your model.

DellanX commented 1 year ago

Ahh, I figure it is an issue with exports, but will take time to dive into that.

I was able to run that command successfully but struggle to navigate the object. It seems like it populated a type map successfully; however, maybe the 'findAll' command refers to an instance of the type on a different Chunk.

image
dpimonov commented 1 year ago

You should to check customOptions of TypeMetadata. Not TypeManager. TypeManager contains custom options for all types but resource metadata defined per type.

image

JsonApiAdapter simply tries to extract this config from a type. If it is not found - then error is thrown.

DellanX commented 1 year ago

Okay, got it root caused!

As I was Migrating over, I had duplicated all of my types in my 'v1' directory into a 'v2' directory. Since my prototype was in V1, it was creating conflicting type definitions.

Removing the declarations from the v1 directory resolved the issue.

Being able to probe around and see that the TypeManager didn't match the modified TypeMetadata (I was deleting members), made it much easier to debug.

I doubt many will run into this issue, as it's unlikely they'll migrate in the same manner I am. Maybe some debug tools would be nice, but I think the main thing was the process of calling the following, and remembering that TypeManager is static:

const typeMetadata = TypeManager.extractTypeMetadata(Documentb);

This issue can probably be closed out now