{"id":13708987,"url":"https://github.com/devnixs/ODataAngularResources","last_synced_at":"2025-05-06T15:31:49.180Z","repository":{"id":32060185,"uuid":"35631966","full_name":"devnixs/ODataAngularResources","owner":"devnixs","description":"Fluent OData queries from Angular's Resources","archived":false,"fork":false,"pushed_at":"2019-09-02T13:06:02.000Z","size":708,"stargazers_count":141,"open_issues_count":24,"forks_count":38,"subscribers_count":21,"default_branch":"master","last_synced_at":"2025-05-01T06:05:07.428Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devnixs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-14T19:24:40.000Z","updated_at":"2025-02-24T22:24:23.000Z","dependencies_parsed_at":"2022-09-09T19:00:28.778Z","dependency_job_id":null,"html_url":"https://github.com/devnixs/ODataAngularResources","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devnixs%2FODataAngularResources","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devnixs%2FODataAngularResources/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devnixs%2FODataAngularResources/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devnixs%2FODataAngularResources/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devnixs","download_url":"https://codeload.github.com/devnixs/ODataAngularResources/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252712974,"owners_count":21792402,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T23:00:34.818Z","updated_at":"2025-05-06T15:31:44.171Z","avatar_url":"https://github.com/devnixs.png","language":"JavaScript","readme":"[![Build Status](https://travis-ci.org/devnixs/ODataAngularResources.svg?branch=master)](https://travis-ci.org/devnixs/ODataAngularResources)\n[![Coverage Status](https://coveralls.io/repos/devnixs/ODataAngularResources/badge.svg?branch=master\u002615)](https://coveralls.io/r/devnixs/ODataAngularResources?branch=master)\n[![CDNJS](https://img.shields.io/cdnjs/v/ODataResources.svg)](https://cdnjs.com/libraries/ODataResources)\n\n\n# \u003ca name=\"odataangularresource\"\u003e\u003c/a\u003eODataAngularResources\n\nODataAngularResources is a fork of Angular's $resource that allows to make OData queries in a fluent way.\nIt does everything Angular Resources does but add some features:\n\n  - Fluent API\n  - Generate proper OData queries without worrying about escaping the right characters\n  - Allows filtering, skipping, ordering, expanding, and selecting only N elements (with top)\n  - Able to generate complex queries with OR, AND and method calls\n\n[Simple JSFiddle Demo](http://jsfiddle.net/h22f7596/)\n\n\n# Table of Contents\n* [How to install](#how-to-install)\n* [How to use](#how-to-use)\n * [Simple query](#simple-query)\n * [Retrieving a single element](#retrieving-a-single-element)\n * [Query with top, orderBy and skip](#query-with-top-orderby-and-skip)\n * [Count and InlineCount](#count-and-inlinecount)\n * [Including related models (Expanding)](#expanding)\n * [Pick a subset of the properties (Selecting)](#selecting)\n * [Specifying a custom url and method](#custom-url)\n * [Specifying the response format](#format)\n* [Advanced queries](#advanced-queries)\n * [Predicates](#predicates)\n * [Overriding default Predicate or Filter behavior](#override-default-predicate-or-filter-behavior)\n * [Specifying the type of the data](#specifying-data-types)\n * [Function calls](#function-calls)\n  * [Function calls definition](#function-calls-definition)\n  * [List of available functions](#function-calls-available-list)\n * [Lambda Operators](#lambda-operators)\n* [OData V4 support](#odata-v4)\n * [Updating entries with OData v4](#odata-v4-action-methods)\n * [Expand and Odata v4](#odata-v4-expand)\n * [InlineCount with OData v4](#odata-v4-inlinecount)\n * [Transform the final query url](#odata-v4-transform-url)\n* [The Promise Chain](#promise-chain)\n * [Interceptors](#promise-chain-interceptors)\n * [Callbacks](#promise-chain-callbacks)\n * [Error Correction](#promise-chain-error-correction)\n* [Refreshing Responses \u0026 Odata Query Persistence](#saving-query-settings)\n * [Persistence](#persistence)\n * [$refresh](#refresh-data)\n* [Build from the source](#build-from-source)\n* [Run the tests](#unit-testing)\n* [Contribute](#contribute)\n \n## \u003ca name=\"how-to-install\"\u003e\u003c/a\u003eHow to install\n\n1. Download the repository or install the **bower package** : \n```Shell\nbower install angular-odata-resources --save\n```\nor\n```Shell\nnpm install angular-odata-resources --save\n```\n2. Include the file **build/odataresources.js** into your project\n3. Be sure to register the module \"ODataResources\" in your module definition : \n```javascript\nvar myModule = angular.module('myModule',['ODataResources']);\n```\n4. Then replace your dependency to \"$resource\" by \"$odataresource\"\n```javascript\nmyModule.controller('MyController', ['$scope','$odataresource',function($scope,$odataresource){}]);\n```\n\n## \u003ca name=\"how-to-use\"\u003e\u003c/a\u003eHow to use\n\n### \u003ca name=\"simple-query\"\u003e\u003c/a\u003eSimple query\n* Call the odata() method on your resource.\n```javascript\nvar User = $odataresource('/user/:userId', {userId:'@id'});\nvar myUsers =   User.odata()\n                    .filter(\"Name\",\"John\")\n                    .query(); \n//Queries /user?$filter=Name eq 'John'\n```\n* The first parameter of the filter method is assumed to be the property and the second to be the value. But that behavior can be overriden by passing special parameters. See advanced queries for more informations.\n\n* Returned objects from the query() method are regular Resource object which can be used for saving, updating etc...\n```javascript\nmyUsers[0].$save();\n```\n\n* Like regular Resource requests you can pass callback that will be called on success and on error\n```javascript\nvar myUsers =   User.odata()\n                    .query(function(){\n                        console.log(\"Everything went ok!\")\n                    },function(){\n                        console.log(\"Oops, something wrong happened!\")\n                    }); \n```\n\n### \u003ca name=\"retrieving-a-single-element\"\u003e\u003c/a\u003eRetrieving a single element\n* Simply call the get method with the entity key\n```javascript\nvar userId = 10;\nvar myUsers =   User.odata().get(userId);\n//Queries /user(10)\n```\n* You can also provide callbacks\n```javascript\nvar userId = 10;\nvar myUsers =   User.odata().get(userId,\n                          function(){\n                            console.log(\"Everything went ok!\")\n                        },function(){\n                            console.log(\"Oops, something wrong happened!\")\n                        });\n```\nIf you want to retrieve a single element after a query you can use the single() method which will take the first elements of the response. This method will throw if the reponse returns an empty array.\n```javascript\nvar User = $odataresource('/user/:userId', {userId:'@id'});\nvar myUser =   User.odata()\n                    .filter(\"Name\",\"John\")\n                    .single(); \n//Queries /user?$filter=Name eq 'John' and put the first element into myUser\n\n```\n\n\n### \u003ca name=\"query-with-top-orderby-and-skip\"\u003e\u003c/a\u003eQuery with top, orderBy and skip\n```javascript\nvar User = $odataresource('/user/:userId', {userId:'@id'});\nvar myUsers =   User.odata()\n    \t\t\t\t.filter(\"Name\", \"John\")\n    \t\t\t\t.filter(\"Age\",\"\u003e\",20)\n    \t\t\t\t.skip(10)\n    \t\t\t\t.take(20)\n    \t\t\t\t.orderBy(\"Name\",\"desc\")\n    \t\t\t\t.query();\n                    \n//Queries /user?$filter=(Name eq 'John') and (Age gt 20)\u0026$orderby=Name desc\u0026$top=20\u0026$skip=10\n```\n- Multiple chained filters are executed with **and** between.\n- orderBy assumes the order to be asc if the second parameter is not specified.\n\n### \u003ca name=\"count-and-inlinecount\"\u003e\u003c/a\u003eCount and InlineCount\n- It's possible to query the number of elements\n```javascript\n                var data = User.odata().filter('name','bob').count();\n                    \n//Queries /user/$count/?$filter=name eq 'bob'\n// data.result == 25\n```\n- You can also ask for an inline count to have the count aside with the data\n```javascript\n                var users = User.odata().withInlineCount().query();\n                \n//Queries /user?$inlinecount=allpages\n// users is an array but also contains the count property\n// The server may reply by\n// {\n//     \"@odata.context\": \"http://host/service/$metadata#Collection(Edm.String)\",\n//     \"value\": [{\n//         name: 'Test',\n//         id: 1,\n//     }, {\n//         name: 'Foo',\n//         id: 2,\n//     }],\n//     'count': 10\n// }\n// And then, the count will be defined as followed\n// users.count == 10\n```\n\n### \u003ca name=\"expanding\"\u003e\u003c/a\u003eIncluding related models (Expanding)\n* You can easily include related models by calling the expand method\n```javascript\nvar User = $odataresource('/user/:userId', {userId:'@id'});\nvar myUsers =   User.odata()\n                    .expand(\"City\")\n                    .query();\n                    \n//Queries /user?$expand=City\n```\n* You can also expand nested related models like the Country of the City of the User\n```javascript\nvar User = $odataresource('/user/:userId', {userId:'@id'});\nvar myUsers =   User.odata()\n                    .expand(\"City\",\"Country\")\n                    .query();\n                    \n//Queries /user?$expand=City/Country\n```\n\n* You can also include multiple related models into your query\n\n```javascript\nvar myUsers =   User.odata()\n                    .expand(\"City\")\n                    .expand(\"Orders\")\n                    .query();\n                    \n//Queries /user?$expand=City,Orders\n```\n### \u003ca name=\"selecting\"\u003e\u003c/a\u003ePick a subset of the properties (Selecting)\n* You can use the select method to retrieve only some properties of the entities.\n```javascript\nvar User = $odataresource('/user/:userId', {\n        userId: '@id'\n    });\n    \n    var users = User.odata().select(['name','userId']).query();\n    //OR\n    var users = User.odata().select('name','userId').query();                    \n\n//Queries /user?$select=userId,name\n```\n\n### \u003ca name=\"custom-url\"\u003e\u003c/a\u003eSpecifying a custom url and method\n* Want a custom url for your odata queries? easy! It works just like angular resources:\n```javascript\nUser = $odataresource('/user/:userId',\n                     { userId: '@id'},\n                \t {\n                \t\todata: {\n                \t\t\tmethod: 'POST',\n                \t\t\turl: '/myCustomUrl'\n                \t\t}\n                \t }\n\t);\n```\n\n### \u003ca name=\"format\"\u003e\u003c/a\u003eSpecifying the response format\n```javascript\nvar myUsers =   User.odata()\n\t\t\t\t\t.format(\"json\")\n                    .expand(\"City\")\n                    .expand(\"Orders\")\n                    .query();\n                    \n//Queries /user?$format=json\u0026$expand=City,Orders\n```\n\t\n\n## \u003ca name=\"advanced-queries\"\u003e\u003c/a\u003eAdvanced queries\n\n### \u003ca name=\"predicates\"\u003e\u003c/a\u003ePredicates\n* If you need to write or statements in your queries, you need to use the Predicate class.\nFirst, be sure to reference the **$odata** dependency.\n```javascript\nmyModule.controller('MyController', ['$scope','$odataresource','$odata',function($scope,$odataresource,$odata){}]);\n```\n* Now you can use the **$odata.Predicate** class wich allow advanced filtering.\n```javascript\nvar predicate1 = new $odata.Predicate(\"FirstName\", \"John\");\nvar predicate2 = new $odata.Predicate(\"LastName\", '!=', \"Doe\");\n//\ncombination = $odata.Predicate.or([predicate1,predicate2]);\nUser.odata().filter(combination).query();\n//Queries /user?$filter=(FirstName eq 'John') or (LastName ne 'Doe');\n```\n\n* You can even combine predicates with predicates\n```javascript\nvar predicate1 = new $odata.Predicate(\"FirstName\", \"John\");\nvar predicate2 = new $odata.Predicate(\"LastName\", '!=', \"Doe\");\nvar predicate3 = new $odata.Predicate(\"Age\", '\u003e', 10);\n//\ncombination1 = $odata.Predicate.or([predicate1,predicate2]);\ncombination2 = $odata.Predicate.and([combination1,predicate2]);\nUser.odata().filter(combination).query();\n//Queries /user?$filter=((FirstName eq 'John') or (LastName ne 'Doe')) and Age gt 10\n```\n\n\n* You can also achieve the same results with the fluent api\n```javascript\nvar predicate = new $odata.Predicate(\"FirstName\", \"John\")\n                            .or(new $odata.Predicate(\"LastName\", '!=', \"Doe\"))\n                            .and(new $odata.Predicate(\"Age\", '\u003e', 10));\n//\nUser.odata().filter(predicate).query();\n//Queries /user?$filter=((FirstName eq 'John') or (LastName ne 'Doe')) and Age gt 10\n```\n\n### \u003ca name=\"override-default-predicate-or-filter-behavior\"\u003e\u003c/a\u003eOverriding default Predicate or Filter behavior\nIt is sometime necessary to compare two properties or two values in a query.\nTo do so, you can use the $odata.Value or $odata.Property classes\n```javascript\nvar predicate = new $odata.Predicate(\n                            new $odata.Value('Foo'),\n                            new $odata.Value('Bar')\n                            );\n//\nUser.odata().filter(predicate).query();\n//Queries /user?$filter='Foo' eq 'Bar'\n```\nOr with two properties : \n```javascript\nUser.odata().filter(\n                    new $odata.Property('Name'),\n                    new $odata.Property('Surname')\n                    ).query();\n//Queries /user?$filter=Name eq Surname\n```\n\n### \u003ca name=\"specifying-data-types\"\u003e\u003c/a\u003eSpecifying the type of the data\n\nThis library is clever enough to figure out the types from the data passed and format them accordingly.\nBut sometimes you may need to have a specific output type. In this case you can pass a second argument to the $odata.Value() constructor : \n```javascript\nUser.odata().filter(\n                    'Latitude',\n                    new $odata.Value(40.765150,\"Decimal\")\n                    ).query();\n//Queries /user?$filter=Latitude eq 40.765150M\n\nUser.odata().filter(\n                    'Latitude',\n                    new $odata.Value(\"75.42\",\"Int32\")\n                    ).query();\n//Queries /user?$filter=Latitude eq 75\n\n\nUser.odata().filter(\n                    'Latitude',\n                    new $odata.Value(\"true\",\"Boolean\")\n                    ).query();\n//Queries /user?$filter=Latitude eq true\n\n\nUser.odata().filter(\n                    'Latitude',\n                    new $odata.Value(10,\"Boolean\")\n                    ).query();\n//Queries /user?$filter=Latitude eq true\n\n```\n\nHere is the complete list of supported types :\n\nType Name       | Output example\n----------------|---------------\nBoolean         | true \nByte            | FE\nDateTime        | datetime'2000-12-12T12:00'\nDecimal         | 2.345M\nDouble          | 2.0d\nSingle          | 2.0f\nGuid            | guid'12345678-aaaa-bbbb-cccc-ddddeeeeffff'\nInt32           | 51358\nString          | 'Hello OData'\n\n\n### \u003ca name=\"function-calls\"\u003e\u003c/a\u003eFunction calls\n* You can call functions like endswith or length on an OData query.\nTo do so, use the **$odata.Func** class.\n```javascript\nvar users = User.odata()\n              .filter(new $odata.Func(\"endswith\",\"FullName\",\"Doe\"), true)\n              .query();\n//Queries /user?$filter=endswith(FullName, 'Doe') eq true\n```\n\n#### \u003ca name=\"function-calls-definition\"\u003e\u003c/a\u003eDefinition\n\nnew $odata.Func(**MethodName**, **PropertyName**, **Value1**, **Value2**,...)\n\n\nThe parameters are assumed to be first, a property and then a value.\nThis behavior can be overriden by specifying explicit values or properties : \n```javascript\nnew $odata.Func('substringof',\n                  new $odata.Value('Alfreds'),\n                  new $odata.Property('CompanyName'));\n```\n\n#### \u003ca name=\"function-calls-available-list\"\u003e\u003c/a\u003eList of available functions\n\nFunction | Example | Example value\n--------- | --------- | -----------\n**String Functions** |  |  \nbool substringof(string po, string p1) | new $odata.Func('substringof',new $odata.Value('Alfreds'), new $odata.Property(CompanyName)) | true\nbool endswith(string p0, string p1) | new $odata.Func('endswith','CompanyName', 'Futterkiste') | true\nbool startswith(string p0, string p1) | new $odata.Func('startswith','CompanyName', 'Alfr') | true\nint length(string p0) | new $odata.Func('length','CompanyName') | 19\nint indexof(string p0, string p1) | new $odata.Func('indexof','CompanyName', 'lfreds') | 1\nstring replace(string p0, string find, string replace) | new $odata.Func('replace','CompanyName', ' ', '') | AlfredsFutterkiste\nstring substring(string p0, int pos) | new $odata.Func('substring','CompanyName', 1) | lfreds Futterkiste\nstring substring(string p0, int pos, int length) | new $odata.Func('substring','CompanyName', 1, 2) | lf\nstring tolower(string p0) | new $odata.Func('tolower','CompanyName') | alfreds futterkiste\nstring toupper(string p0) | new $odata.Func('toupper','CompanyName') | ALFREDS FUTTERKISTE\nstring trim(string p0) | new $odata.Func('trim','CompanyName') | Alfreds Futterkiste \nstring concat(string p0, string p1) | new $odata.Func('concat','City', new $odata.Property('Country')) | Berlin Germany\n**Date Functions** |  | \nint day(DateTime p0) | new $odata.Func('day','BirthDate')  | 8\nint hour(DateTime p0) | new $odata.Func('hour','BirthDate')  | 0\nint minute(DateTime p0) | new $odata.Func('minute','BirthDate')  | 0\nint month(DateTime p0) | new $odata.Func('month','BirthDate')  | 12\nint second(DateTime p0) | new $odata.Func('second','BirthDate')  | 0\nint year(DateTime p0) | new $odata.Func('year','BirthDate')  | 1948\n**Math Functions** | | \ndouble round(double p0) | new $odata.Func('round','Freight')  | 32d\ndecimal round(decimal p0) | new $odata.Func('round','Freight')  | 32\ndouble floor(double p0) | new $odata.Func('round','Freight')  | 32d\ndecimal floor(decimal p0) | new $odata.Func('floor','Freight')  | 32\ndouble ceiling(double p0) | new $odata.Func('ceiling','Freight')  | 33d\ndecimal ceiling(decimal p0) | new $odata.Func('floor','Freight')  | 33\n**Type Functions** | | \nbool IsOf(expression p0, type p1) | new $odata.Func('isof','ShipCountry', 'Edm.String') | true\n\n### \u003ca name=\"lambda-operators\"\u003e\u003c/a\u003eLambda Operators\nThe **$odata.Func** class also supports the lambda operators **any** and **all**\n\nnew $odata.Func(**LambdaOperator**, **PropertyName**, **LambdaVariable**, **Expression**)\n\nThe parameters are assumed to be first, a lambda operator, a property name, a lambda variable, and a boolean expression.\nThe boolean expression must use the lambda variable to refer to properties of the related entities identified by the navigation path.\n\n```javascript\nvar predicate1 = new $odata.Predicate(\"c/FirstName\", \"Bobby\");\nvar predicate2 = new $odata.Predicate(\"c/LastName\", \"McGee\");\n//\nvar combination = $odata.Predicate.and([predicate1,predicate2]);\n//\nvar func = new $odata.Func('any', 'clients', 'c', combination);\n//\nJobs.odata().filter(func).query();\n//Queries /Jobs?$filter=clients/any(c:((c/FirstName eq 'Bobby') and (c/LastName eq 'McGee')))\n```\n\n\n## \u003ca name=\"odata-v4\"\u003e\u003c/a\u003eOData V4 support\nThis project supports basic odata v4 queries and responses.\nIf the server responds with an array wrapped inside an object :\n```json\n{\n  \"@odata.context\":\"http://local.testsite.com/odata/$metadata#TestData\",\n   \"value\":[\n    {\n      \"TestId\":1,\"name\":\"test 1\"\n    },{\n      \"TestId\":2,\"name\":\"test 2\"\n    }\n  ],\n\"totalCount\":10\n}\n```\n\nThe api will still return the array provided in the **value** property and everything else will be set as properties of the array.\n```javascript\nvar User = $odataresource('/user/:userId', {userId:'@id'});\nvar myUsers =   User.odata()\n                    .filter(\"Name\",\"John\")\n                    .query(); \n\n//... later\n\nconsole.log(myUsers[0].name);\nconsole.log(myUsers.totalCount);\n\n```\n\n### \u003ca name=\"odata-v4-action-methods\"\u003e\u003c/a\u003eUpdating entries with OData v4\n You can use the $update method on an object.\n But for that you need to specify what is the property that contains the key.\n\n There is two way of doing so :\n\n * Provide the key property as a second argument.\n```javascript\nUser = $odataresource('/user', 'id');\nvar myUsers = User.odata.query();\n\n//... later\nmyUsers[0].$update();\n//Will issue a PUT /user(1)\n```\n * Or provide it as a property of the 4th argument.\n```javascript\nUser = $odataresource('/user', {},{},{odatakey : 'id'});\nvar myUser = new User();\n\nmyUser.$save();\n//Will issue a POST /user\n\nmyUser.$update();\n//Will issue a PUT /user(1)\n\nmyUser.$delete();\n//Will issue a DELETE /user(1)\n```\n * You can provide a comma seperated list of id's for complex key tables.\n```javascript\nUser = $odataresoure('/userroles', {},{},{odatakey: 'id,roleid'});\nvar myUser = new User();\n\nmyUser.$update();\n//will issue a POST /user(id=1,roleid=2)\n```\n\n### \u003ca name=\"odata-v4-expand\"\u003e\u003c/a\u003eExpand and Odata v4\n\nWith odatav4 expanding nested entities is done with a different query\n```\n/user?$expand=Order/Items\n```\nbecomes\n```\n/user?$expand=Order($expand=Items)\n```\nTo enable this behavior set the isodatav4 property to true when invoking the $odataresource method:\n```javascript\nUser = $odataresource('/user', {}, {}, {\n    odatakey: 'id',\n    isodatav4: true\n});\n\nvar result = User.odata().expand(\"roles\", \"role\").query();\n//  /user?$expand=roles($expand=role)\n```\nYou can use the expand predicate for complex expand scenarios (such as parsing your metadata and applying a default schema to a query):\n```javascript\nvar result = User.odata().expandPredicate(\"roles\").select(\"name\").finish().query();\n// /user?$expand=roles($select=name)\n```\nExpandPredicate returns the Expand context and finish returns the base OdataProvider context, so make sure to finish the expandPredicate.\n\nYou can nest expands as well:\n```javascript\n// grab odata context\nvar query = User.odata();\n// add expand roles table and select roles.name\nquery.expandPredicate(\"roles\").select(\"name\").finish();\n// add and save the context for the provider table and select provider.name, also expand provider -\u003e settings (automatically calls finish())\nvar providertype = query.expandPredicate(\"provider\").select(\"name\").expand(\"settings\");\n// add provider type table and finish out both the provider type and provider expandPredicate contexts\nprovidertype.expandPredicate(\"providertype\").finish().finish();\n// run the query\nquery.query();\n\n// or inline\n\nvar query = User.odata().expandPredicate(\"roles\").select(\"name\").finish().expandPredicate(\"provider\").select(\"name\").expand(\"settings\")\n  .expandPredicate(\"providertype\").finish().finish().query();\n\n// /user?$expand=roles($select=name),provider($select=name;expand=settings,providertype)\n```\n\n### \u003ca name=\"odata-v4-inlinecount\"\u003e\u003c/a\u003eInlineCount with OData v4\n\n- With OData v4 inlinecount issues a $count=true parameter\n```javascript\n                var users = User.odata().withInlineCount().query();\n                \n//Queries /user?$count=true\n// users is an array but also contains the count property\n// The server may reply by\n// {\n//     \"@odata.context\": \"http://host/service/$metadata#Collection(Edm.String)\",\n//     \"@odata.count\":10,\n//     \"value\": [{\n//         name: 'Test',\n//         id: 1,\n//     }, {\n//         name: 'Foo',\n//         id: 2,\n//     }]\n// }\n// And then, the count will be defined as followed\n// users.count == 10\n```\n### \u003ca name=\"odata-v4-transform-url\"\u003e\u003c/a\u003eTransform the final query url\n\n- It is possible to transform the query that will be made to the server by calling the method transformUrl\n```javascript\n\nUser.odata()\n    .filter(\"Name\", \"Raphael\")\n    .transformUrl(function(url){\n        return url+'\u0026foo=bar';\n    })\n    .query();\n\n// queries /user?$filter=Name eq 'Raphael'\u0026foo=bar                    \n```\n\n## \u003ca name=\"promise-chain\"\u003e\u003c/a\u003eThe Promise Chain\nWhen you retrieve a resource from the API, you are returned a Resource object or Array of Resources with the $http call being appended to the\n$promise property.  This promise has already been chained through two phases.  A intereptor phase for $http request success or errors. These\nare not to be confused with $http request and response interceptors, but follow the same ceonepts with argumets and return values.  After the\ninterceptor phase is the callback phase for per request success or error handling.\n\n### \u003ca name=\"promise-chain-interceptors\"\u003e\u003c/a\u003eInterceptors\nInterceptor handlers can be defined for each action you define for the actions object argument to $odataresource.  Both succes and error\ninterceptor handlers get called withe the $http response object passed as their single argument.  There is a default handler defined for the\nsuccess interceptor phase on each action defined with $odataresource that returns argument.resource.  To maintain continuous support from\n$odataresource prototype methods (save, update, delete, etc), you should return this object from you success interceptor if you override the\ndefault one.\n```javascript\nUser = $odataresource('/user', {}, {\n    odata: {\n      interceptor: {\n        response: function(response) {\n          // response is the returned $http result with the parsed Resource object on response.resource.\n          apiLog.logSuccess(response);\n          return response.resource;\n        },\n        responseError: function(response) {\n          // response is the returned $http result\n          apiLog.logError(response, response.headers());\n        },\n      },\n    },\n  }, {});\n```\n\n### \u003ca name=\"promise-chain-callbacks\"\u003e\u003c/a\u003eCallbacks\nCallbacks can be provided to each API call by passing a method reference in the parameters to the $odataresource api call.  The success callback\nis provided if you want a convient way to inject into the promise chain when calling the api query.  Both the final Resource object and the $http\nresponse headers are provided as parameters an available success callback handler.  The error callback handler will provide you with any error\nmessage that might get thrown during parsing the $http response and building the Resource object.\n```javascript\nvar User = $odataresource(\"/user\", {}, {}, {});\nvar user = User.odata().select(\"FirstName\",\"LastName\").query(function(resource, headers) {\n    resource.Name = resource.FirstName + ' ' + resource.LasstName;\n  }, function(error) {\n    apiLog.logError(error);\n  });\n```\n\n### \u003ca name=\"promise-chain-error-correction\"\u003e\u003c/a\u003eError Correction\nThe error interceptor and callback handling has been enhanced to provide an opportunity for error handling and correction measures to be applied\nto the original $odataresource settings.  The response from both the error interceptor and the error callback can provide corrected data back to\nthe promise chain to merge into the final Resource object.  The correction can be in the form of a new Resource object, a new Resource object\npromise, an $http promise, or an object with a property named $correction containing new arguments for the $oataresource object (url, defaultParams,\nactions, options).  If the new promise, or correction results in another error, the error correction attempt will stop and reject, preventing\nan infinate loop.\n```javascript\nUser = $odataresource('/user', {}, {\n    odata: {\n      interceptor: {\n        response: function(response) {\n          // response is the returned $http result with the parsed Resource object on response.resource.\n          apiLog.logSuccess(response);\n          return response.resource;\n        },\n        responseError: function(response) {\n          // response is the returned $http result\n          apiLog.logError(response, response.headers());\n          return { $correction: { url: 'https://fixedUrl.com/' } };\n        },\n      },\n    },\n  }, {});\n```\n\n## \u003ca name=\"saving-query-settings\"\u003e\u003c/a\u003eRefreshing Responses \u0026 Odata Query Persistence\nSupport has been added to keep track of queries used to retrieve entities.  You can call the $refresh method on a returned array of resources,\nor an individual resource object itself to get an updated entity from the API.  The odata query applied to the refresh GET will depend on how\nthe object you're calling the $refresh method on was retrieved.  There are two types of persisted queries, full and limited.  Full will store\nthe entire list of odata arguments you supplied to reproduce the same result set.  Limited will limit the query to selects, expands, and\nformat.  Limited assumes you're getting a single entity from a larger query, and want to keep the response equal to the initial object, ie\nsame selects, expands, but dont need the filter/take/skip/etc odata arguments.\n\n### \u003ca name=\"persistence\"\u003e\u003c/a\u003ePersistence\n\nTo apply persisted query arguments to the provider manually call the 're' method.\n```javascript\nvar newUser = userResource.$odata().re().query();\n```\n\nOr you can enable this behavior by default.\n```javascript\nvar User = $odataresource(\"/user\", {}, {}, { isodatav4: true, odatakey: \"id\", persistence: true } );\nvar user = User.odata().select(\"name\").query();\nvar newUser = user.$odata().query();\n```\n\n### \u003ca name=\"refresh-data\"\u003e\u003c/a\u003e$refresh\n\nPersistence is applied automatically with or without the persistence options flag when using $refresh.\n\nUse the following table to determine the query that will be appllied to the refresh:\n\nInitial OdataProvider Call              | Target                            | Persistence \n:---------------------------------------|:----------------------------------|------------:\nvar array = resource.odata().query();   | var array = array.$refresh();     | full   \nvar array = resource.odata().query();   | var entity = array[0].$refresh(); | limited\nvar entity = resource.odata().get(1);   | var entity = entity.$refresh();   | limited\nvar entity = resource.odata().single(); | var entity = entity.$refresh();   | full   \nvar count = resource.odata().count();   | var count = count.$refresh();     | full   \n\n\n\n## \u003ca name=\"build-from-source\"\u003e\u003c/a\u003eBuild from the source\n\n1. You need Grunt installed globally:\n```sh\n\u003e npm install -g grunt\n```\n2. Then run\n```sh\n\u003e npm install\n\u003e grunt build\n```\n\n## \u003ca name=\"unit-testing\"\u003e\u003c/a\u003eRun the tests\n* Simply run\n```sh\n\u003e grunt test\n```\n\n## \u003ca name=\"contribute\"\u003e\u003c/a\u003eContribute\n\nWant to contribute? Great!\nBe sure to write tests before submitting your pull request.\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevnixs%2FODataAngularResources","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevnixs%2FODataAngularResources","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevnixs%2FODataAngularResources/lists"}