1.4.4 • Published 4 years ago

c4codata v1.4.4

Weekly downloads
11
License
MIT
Repository
github
Last release
4 years ago

OData Javascript Library

CircleCI codecov Maintainability Rating unpkg

npm version Download Size

Technical Debt Vulnerabilities Duplicated Lines (%)

Lightweight OData Client for OData (v2) Service.

Installation

npm i -S c4codata

Alternative, in build-tool-less environment, just add unpkg umd link to your page, and OData object will be available in window.

<script src="https://unpkg.com/c4codata"></script>

Table of Contents

  1. Installation
  2. Table of Contents
  3. OData Version 2 concepts
    1. URI Format
    2. Pagination
    3. Filter
  4. OData Client
    1. ODataRequest interface
    2. ODataResponse interface
  5. ODataParam
    1. pagination
    2. filter
    3. inline count
    4. orderby
    5. navigation property
    6. fields select
    7. full text search (basic query)
  6. ODataFilter
    1. filter by single field value
    2. filter by multi fields
    3. filter by one field but multi values
    4. filter by date
  7. Batch requests
  8. Generator usage
  9. Others
  10. CHANGELOG
  11. LICENSE

OData Version 2 concepts

From OData.org

If you are already familiar with OData, please skip this section

URI Format

A URI used by an OData service has up to three significant parts: the service root URI, resource path and query string options. Additional URI constructs (such as a fragment) MAY be present in a URI used by an OData service; however, this specification applies no further meaning to such additional constructs.

Pagination

A data service URI with a $skip System Query Option identifies a subset of the Entries in the Collection of Entries identified by the Resource Path section of the URI. That subset is defined by seeking N Entries into the Collection and selecting only the remaining Entries (starting with Entry N+1). N is an integer greater than or equal to zero specified by this query option. If a value less than zero is specified, the URI should be considered malformed.

https://services.odata.org/OData/OData.svc/Products?$skip=2&$top=2&$orderby=Rating

The third and fourth Product Entry from the collection of all products when the collection is sorted by Rating (ascending).

Filter

A URI with a $filter System Query Option identifies a subset of the Entries from the Collection of Entries identified by the Resource Path section of the URI. The subset is determined by selecting only the Entries that satisfy the predicate expression specified by the query option.

OperatorDescriptionExample
EqEqual/Suppliers?$filter=Address/City eq 'Redmond'
NeNot equal/Suppliers?$filter=Address/City ne 'London'
GtGreater than/Products?$filter=Price gt 20
GeGreater than or equal/Products?$filter=Price ge 10
LtLess than/Products?$filter=Price lt 20
LeLess than or equal/Products?$filter=Price le 100
AndLogical and/Products?$filter=Price le 200 and Price gt 3.5
OrLogical or/Products?$filter=Price le 3.5 or Price gt 200

OData Client

Start with a simple query, following code start a GET http request, and asks the server to respond to all customers which phone number equals 030-0074321

import { OData } from "c4codata"

// odata.org sample odata service
const TestServiceURL = "https://services.odata.org/V2/Northwind/Northwind.svc/$metadata"
const odata = new OData(TestServiceURL)

// Query by filter
//
// GET /V2/Northwind/Northwind.svc/Customers?$format=json&$filter=Phone eq '030-0074321'
const filter = OData.newFilter().field("Phone").eqString("030-0074321");

const result = await odata.newRequest({ // ODataRequest object
  collection: "Customers", // collection name
  params: OData.newParam().filter(filter) // odata param
})

ODataRequest interface

interface ODataRequest<T> {
  collection: string, /** collection name */
  id?: any, /** object key in READ/UPDATE/DELETE, user could set this field with number/string/object type */
  params?: ODataQueryParam, /** params in QUERY */
  /**
   * GET for QUERY/READ; for QUERY, you can use params to control response data
   * PATCH for UPDATE (partial)
   * PUT for UPDATE (overwrite)
   * POST for CREATE
   * DELETE for DELETE
   */
  method?: HTTPMethod,
  entity?: T /** data object in CREATE/UPDATE */
}

ODataResponse interface

interface PlainODataResponse {
  d?: {
    __count?: string; /** $inlinecount values */
    results: any | Array<any>; /** result list/object */
    [key: string]: any;
  };
  error?: { /** if error occurred, node error will have value */
    code: string;
    message: {
      lang: string, 
      value: string /** server error message */
    }
  }
}

ODataParam

use ODataParam to control data size, involved fields and order

pagination

skip first 30 records and top 10 records

// equal to $format=json&$skip=30&$top=10
OData.newParam().skip(30).top(10)

filter

filter data by fields value

// $format=json&$filter=A eq 'test'
OData.newParam().filter(OData.newFilter().field("A").eqString("test"))

inline count

response with all records count, usefully.

also could set with filter, and response with filtered records count.

// equal to $format=json&$inlinecount=allpages
OData.newParam().inlinecount(true).top(1).select("ObjectID")

orderby

sort response data

// result is $format=json&$orderby=CreationDateTime desc
OData.newParam().orderby("CreationDateTime")

// result is $format=json&$orderby=A desc,B asc
OData.newParam().orderby([{ field: "A" }, { field: "B", order: "asc" }])

navigation property

expand association data

// $expand=Customers
OData.newParam().expand("Customers")
// $expand=Customers,Employees
OData.newParam().expand(["Customers", "Employees"])

fields select

remove unused fields from response

// $format=json&$select=ObjectID,Name
OData.newParam().select("ObjectID").select("Name");

full text search (basic query)

search all supported fields with text

SAP systems feature

LOW PERFORMANCE

// fuzzy
// $format=json&$search=%any word%
OData.newParam().search("any word");
// not fuzzy
// $format=json&$search=any word
OData.newParam().search("any word", false);

ODataFilter

Use the ODataFilter to filter data

Most SAP systems only support AND operator between different fields, and OR operator in a same field. (it depends on SAP Netweaver implementation)

So you don't need to specify AND/OR operator between fields, c4codata will auto process it.

Though C4C only support AND operator in different fields, but for gt/lt/ge/le, you can use AND for filtering period data.

just ref following examples

filter by single field value

// Name eq 'test string'
OData.newFilter().field("Name").eqString("test string")

// ID lt '1024'
OData.newFilter().field("ID").lt("'1024'")

// also support eq/ne/le/lt/gt/ge ...

filter by multi fields

// Name eq 'test string1' and Name2 eq 'test string2'
OData
  .newFilter()
  .field("Name").eq("'test string1'")
  .field("Name2").eqString("test string2")

filter by one field but multi values

// Name eq 'test string1' and (Name2 eq 'test string1' or Name2 eq 'test string2')
OData.newFilter()
  .field("Name").eq("'test string1'")
  .field("Name2").in(["test string3", "test string2"])

filter by date

Depends on field type, use betweenDateTime or betweenDateTimeOffset to filter date。

Please provide Date object in this api.

// Name eq 'test string1' and (CreationDateTime gt datetime'2018-01-24T12:43:31.839Z' and CreationDateTime lt datetime'2018-05-24T12:43:31.839Z')
OData
  .newFilter()
  .field("Name").eq("'test string1'")
  .field("CreationDateTime").betweenDateTime(
    new Date("2018-01-24T12:43:31.839Z"),
    new Date("2018-05-24T12:43:31.839Z"),
    false
  )
  .build()

// > include boundary value

// (CreationDateTime ge datetime'2018-01-24T12:43:31.839Z' and CreationDateTime le datetime'2018-05-24T12:43:31.839Z')
OData
  .newFilter()
  .field("CreationDateTime").betweenDateTime(
    new Date("2018-01-24T12:43:31.839Z"),
    new Date("2018-05-24T12:43:31.839Z")
  )
  .build()

Batch requests

use odata $batch api for operating multi entities in single HTTP request, it will save a lot of time between client & server (In the case of processing a large number of requests).

const odata = OData.New({
  metadataUri: `https://services.odata.org/V2/(S(${v4()}))/OData/OData.svc/$metadata`,
  processCsrfToken: false, // set false if you dont need process csrf token
})
const testDesc1 = v4(); // a generated uuid
const testDesc2 = v4();

// execute reqeusts and return mocked responses
const result = await odata.execBatchRequests([
  odata.newBatchRequest({
    collection: "Products",
    entity: {
      ID: 100009,
      Description: testDesc1,
    },
    method: "POST",
    // withContentLength: true, for SAP OData, please set this flag as true
  }),
  odata.newBatchRequest({
    collection: "Products",
    entity: {
      ID: 100012,
      Description: testDesc2,
    },
    method: "POST",
    // withContentLength: true, for SAP OData, please set this flag as true
  })
])


result.map(r => expect(r.status).toEqual(201)) // Created

Generator usage

This library provide a JS generator, provide ES6 static function declaration, but I dont want to write too much about this.

If you really need that, just contact me.

install it global firstly

npm i -g c4codata # type defination generator

c4codata includes a type defination generator to help developer invoke odata api.

Usage:
  odata-js-generator [OPTIONS] [ARGS]

Options:
  -m, --uri STRING       metadata uri
  -u, --user STRING      c4c username
  -p, --pass STRING      c4c password
  -o, --out [STRING]     out file (Default is c4codata.js)
  -d, --debug BOOLEAN    debug mode
  -s, --separate STRING  out with separate files in directory
  -r, --odatajs BOOLEAN  seperate generator without odata.js
  -h, --help             Display help and usage details

sample command (generate single js file)

use following command to generate declaration

odata-js-generator -m "https://host/sap/c4c/odata/v1/c4codata/$metadata?sap-label=true" -u c4c-username -p c4c-password 

then, you could use the c4codata.js to operation OData

some SAP OData implementations have some different param in url, like sap-label, it will response the label value in the UI interface.

Others

Use markdown-toc to generate table of contents, with following commands:

markdown-toc --replace --inline --header "## Table of Contents" --skip-headers=1  README.md

CHANGELOG

CHANGELOG

LICENSE

MIT License

Copyright (c) 2018 Theo Sun

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

1.4.4

4 years ago

1.4.3

5 years ago

1.4.2

5 years ago

1.4.1

5 years ago

1.4.0

5 years ago

1.3.8

5 years ago

1.3.7

6 years ago

1.3.6

6 years ago

1.3.5

6 years ago

1.3.4

6 years ago

1.3.3

6 years ago

1.3.2

6 years ago

1.3.1

6 years ago

1.3.0

6 years ago

1.2.1

6 years ago

1.1.3

6 years ago

1.1.2

6 years ago

1.1.1

6 years ago

1.0.60

6 years ago

1.0.59

6 years ago

1.0.58

6 years ago

1.0.57

6 years ago

1.0.56

6 years ago

1.0.55

6 years ago

1.0.54

6 years ago

1.0.53

6 years ago

1.0.52

6 years ago

1.0.50

6 years ago

1.0.49

6 years ago

1.0.48

6 years ago

1.0.47

6 years ago

1.0.46

6 years ago

1.0.42

6 years ago

1.0.41

6 years ago

1.0.40

6 years ago

1.0.39

6 years ago

1.0.38

6 years ago

1.0.37

6 years ago

1.0.36

6 years ago

1.0.35

6 years ago

1.0.33

6 years ago

1.0.31

6 years ago

1.0.30

6 years ago

1.0.29

6 years ago

1.0.28

6 years ago

1.0.27

6 years ago

1.0.26

6 years ago

1.0.25

6 years ago

1.0.24

6 years ago

1.0.23

6 years ago

1.0.22

6 years ago

1.0.20

6 years ago

1.0.19

6 years ago

1.0.18

6 years ago

1.0.17

6 years ago

1.0.16

6 years ago

1.0.15

6 years ago

1.0.14

6 years ago

1.0.13

6 years ago

1.0.11

6 years ago

1.0.9

6 years ago

1.0.8

6 years ago

1.0.7

6 years ago

1.0.6

6 years ago

1.0.5

6 years ago

1.0.4

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago