diegomvh / angular-odata

Client side OData typescript library for Angular
https://www.npmjs.com/package/angular-odata
MIT License
46 stars 14 forks source link

How expensive is creating an oDataServiceFactory. Can it be stored in a singelton? #46

Closed TheWrightDev closed 2 years ago

TheWrightDev commented 2 years ago

Very cool library! But I'm looking over the examples here and in the entity project and they both tend to just pile everything in a single method. Are there some things that can be created once in a service and reused (like the ODataEntityService)

That is, should it be:

@Injectable({ providedIn: 'root' })
export class ContactService extends ApiService {
  private contactsODataService: ODataEntitySetService<Contact>;

  constructor(private http: HttpClient, private oDataServiceFactory: ODataServiceFactory) {
    super();
    this.contactsODataService = oDataServiceFactory.entitySet<Contact>('contacts');
  }

  public getInactiveContacts() {
    const contacts = this.contactsODataService.entities();
    return contacts
      .fetchAll();
  }

  public getContact(id: number) {
    const contacts = this.contactsODataService.entities();
    return contacts
      .entity(id)
      .expand({
        messageHistory: {
          select: ['message'] as (keyof ContactMessage)[]
        }
      }).get();
  }
}

or

@Injectable({ providedIn: 'root' })
export class ContactService extends ApiService {
  constructor(private http: HttpClient, private oDataServiceFactory: ODataServiceFactory) {
    super();
  }

  public getInactiveContacts() {
    const contactsODataService = this.oDataServiceFactory.entitySet<Contact>('contacts');
    const contacts = contactsODataService.entities();
    return contacts
      .fetchAll();
  }

  public getContact(id: number) {
    const contactsODataService = this.oDataServiceFactory.entitySet<Contact>('contacts');
    const contacts = contactsODataService.entities();
    return contacts
      .entity(id)
      .expand({
        messageHistory: {
          select: ['message'] as (keyof ContactMessage)[]
        }
      }).get();
  }
}

Are there any other things that can be safely preserved? entities() seemed like it was sometimes immutable but sometimes not from the example in your repo, so I wasn't sure if it was safe to keep that collection in the service.

Also, our serviceRootUrl for the module config depends on the deployment. All other urls in our application are actually resolved via a service. Are there any plans in the future for allowing more configuration of the serviceRootUrl. Being able to register and provide our own ODATA_CONFIGURATIONS that we can setup a factory (with deps) for would be perfect.

diegomvh commented 2 years ago

Hi @TheWrightDev

https://github.com/diegomvh/AngularODataEntity/blob/main/src/app/trippin/Microsoft/OData/SampleService/Models/TripPin/airlines.service.ts

TheWrightDev commented 2 years ago

I appreciate the reply @diegomvh - so I'm guessing you mean that ODataEntitySetService is fine to reuse since you're extending your own services from it. Thanks!

One other thing I'm having issues with, when trying to use the 'guid' type from the odata-query library it's not coming out correctly: https://github.com/techniq/odata-query/tree/d7ffac4a54c8c4dc0da73f364efb9841bd774019#data-types

The expected filter is : "$filter: someProp eq cd5977c2-4a64-42de-b2fc-7fe4707c65cd" but I'm getting: $filter: someProp eq type='guid',value='cd5977c2-4a64-42de-b2fc-7fe4707c65cd' which is throwing a syntax error on the server.

Leaving the type off sends it with quotes ($filter: someProp eq 'cd5977c2-4a64-42de-b2fc-7fe4707c65cd') which also results in an error from the server A binary operator with incompatible types was detected. Found operand types 'Edm.Guid' and 'Edm.String' for operator kind 'Equal'

My code:

contacts.query.filter().push({someProp: { eq: { type: 'guid', value: 'cd5977c2-4a64-42de-b2fc-7fe4707c65cd' } }});

Are guids not supported with angular-odata?

diegomvh commented 2 years ago

Hi @TheWrightDev

Apologies for the short answer, but yes, it is possible to create your own services inheriting from ODataEntitySetService and injecting ODataClient. These services along with other constructions such as types and configurations present in example are generated automatically by the code generation tool.

Regarding the guid there are some differences with the original library, at some point I changed the use of the types for the most basic ones, in this case it would be to use the raw type

https://github.com/diegomvh/angular-odata/blob/a4b5127de2576f19c8128610c374662e4181b91f/projects/angular-odata/src/lib/resources/builder.ts#L74

Although in order not to be using "cryptic stuff" in the filters, there is a way to encode parameters on demand using the parser for the data type. Receiving these functions to encode I see that there are annoying details to use them so I prepared an example for the next version (0.76.0) of the library

https://github.com/diegomvh/AngularODataEntity/blob/3eea8c2679add68221066ee8bc3989554cb52478/src/app/app.component.ts#L57

I hope this helps and thanks for giving the library a try.

Regards Diego

TheWrightDev commented 2 years ago

Thanks for the quick response, while maybe not the optimal solution that guid parser does solve the issue in a clear way.

Looking at the parsers, is there a way to use a the enum encoder without having used the angular generator? Looks like it's digging through the api that'd be setup via the generated config. Otherwise I just seem to get No Enum for name X was found