diegomvh / angular-odata

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

Handle Guid's strings for OData v4 when used as Key #3

Closed kevindstanley1988 closed 4 years ago

kevindstanley1988 commented 4 years ago

Issue In Odata V4 if the key of a table is a Guid type the url that is being generated is incorrect. The filter function also is formed incorrectly.

The generated url that is being executed when using the fetchOne command comes out like this https://localhost:4400/odata/League('856f217a-8b40-4637-96a1-ff39da129316')

The generated url that is being executed when using filter and get command comes out like this. If I manually remove the single quotes( %27's ) the call works. https://localhost:44317/odata/League?$filter=Id%20eq%20%27856f217a-8b40-4637-96a1-ff39da129316%27

In OdataV4 server the guid doesn't get processed properly unless if the url is formed without the quotes around the guid.

Example I am using fetchCollection here to verify the odata source is exactly passing back the right guid data.

this.leagueService.fetchCollection().subscribe(observer => {
  console.log('result', observer[0]);
  const id = observer[0][0].Id;

  this.leagueService.fetchOne(id).subscribe(observer2 => {
    console.log(observer2);
  });

  const leagueEntities = this.leagueService.entities();
    leagueEntities.filter({ Id: id });
    leagueEntities.get().subscribe(observer2 => {
      console.log('filter', observer2);
    });
  });

Expectation The url that is generated for Guid's has no quotes around the key value for fetchOne. https://localhost:4400/odata/League(856f217a-8b40-4637-96a1-ff39da129316)

Potential Fix My proposal for a fix is 2 steps. 1) the ODataApiGen app would need updated to change the service models schema data to guid when it reads the $metadata. 2) During the generating url step it would be check the schema to see if it is of type guid and wrap it in nothing for Guid's, but keep single quotes for strings.

This code could be generated for the Id type to be guid instead of string.

export const LeagueSchema = {
  Id: { type: 'guid', key: true, ref: 'Id', nullable: false },
  Name: { type: 'string' },
};
kevindstanley1988 commented 4 years ago

Still testing this, but my note above for potential fix may have been overkill. The guid can still be represented as type 'string' in the schema, so update needed to ODataApiGen, but before the additional quotes are added in segment.ts it can be checked for guid type and then have quotes attached or not depending on if it is a guid or not.

this would change the default case in the path function inside of resources\segment.ts to

default:
  let key = segment.options[Options.key];
  if (typeof(key) === 'string' && /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(key)) {
    key = `${key}`;
  } else if (typeof(key) === 'string' && !(key.charAt(0) === key.charAt(key.length-1) && ['"', "'"].indexOf(key.charAt(0)) !== -1)) {
    key = `'${key}'`;
  } 
  return segment.name + (key ? buildQuery({key}) : "");
diegomvh commented 4 years ago

Hi @kevindstanley1988 and thanks for the fix, I will merge it soon. In the case of filters, the approaching of odata-query is to use type as an identifier, I think that would be the way to filter for now.

https://github.com/techniq/odata-query/tree/a67e7f7d74603439b7d87a7cc3a61c3939db69be#data-types

diegomvh commented 4 years ago

Again, thank you very much for giving the library a chance and for the help.

kevindstanley1988 commented 4 years ago

I have tried about 10 different OData libraries and metadata tools for typescript and none are as fully featured and functional as this one, thanks for writing this and the generator! I plan to use this for my future OData clients.

nikolay-filimonov commented 1 year ago

Hello! I don't know what I'm doing wrong, but I'm facing the same problem on library version 0.123.0 (I've checked also on a previous versions up to 0.100.1, and got the same result)

For some reason builder generates query string using ' even though my string matches the guid regexp: image This is the error message I'm receiving: "The type 'Edm.Guid' is not compatible to 'Edm.String'"

I've tried lots of things, but got the same result This is the code for fetching entities (including filtering, expanding, limiting and skipping):

this.staffService = this.factory.entitySet<Staff>('Staff');
let staffEntities = this.staffService.entities();
staffEntities
  .query((q) => {
    q.expand({
      role: { select: ["name", "id"] }
    });
    q.filter({
      role_id: '3e293245-8611-6400-be1b-d368526fac66'
    });
    q.top(this.pageSize);
    q.skip(this.skip);

    this.skip += this.pageSize;
  })
  .fetch()
  .subscribe({
    next: (a) => {
      console.log(a);
    }
  });

I appreciate any help, thanks!