├── .editorconfig
├── .github
├── FUNDING.yml
└── workflows
│ ├── codeql-analysis.yml
│ └── node.js.yml
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
└── tasks.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── angular.json
├── docs
├── README.md
├── api
│ ├── changelog.html
│ ├── classes
│ │ ├── Aggregate.html
│ │ ├── ApiConfig.html
│ │ ├── ApplyExpression.html
│ │ ├── ArithmeticFunctions.html
│ │ ├── ArithmeticOperators.html
│ │ ├── Base.html
│ │ ├── Callable.html
│ │ ├── CollectionFunctions.html
│ │ ├── ComputeExpression.html
│ │ ├── ConditionalFunctions.html
│ │ ├── CountExpression.html
│ │ ├── CountField.html
│ │ ├── CsdlAction-1.html
│ │ ├── CsdlAction.html
│ │ ├── CsdlActionImport-1.html
│ │ ├── CsdlActionImport.html
│ │ ├── CsdlAnnotable-1.html
│ │ ├── CsdlAnnotable.html
│ │ ├── CsdlAnnotation-1.html
│ │ ├── CsdlAnnotation.html
│ │ ├── CsdlAnnotations-1.html
│ │ ├── CsdlAnnotations.html
│ │ ├── CsdlCallable-1.html
│ │ ├── CsdlCallable.html
│ │ ├── CsdlCollection-1.html
│ │ ├── CsdlCollection.html
│ │ ├── CsdlComplexType-1.html
│ │ ├── CsdlComplexType.html
│ │ ├── CsdlEntityContainer-1.html
│ │ ├── CsdlEntityContainer.html
│ │ ├── CsdlEntitySet-1.html
│ │ ├── CsdlEntitySet.html
│ │ ├── CsdlEntityType-1.html
│ │ ├── CsdlEntityType.html
│ │ ├── CsdlEnumMember-1.html
│ │ ├── CsdlEnumMember.html
│ │ ├── CsdlEnumType-1.html
│ │ ├── CsdlEnumType.html
│ │ ├── CsdlFunction-1.html
│ │ ├── CsdlFunction.html
│ │ ├── CsdlFunctionImport-1.html
│ │ ├── CsdlFunctionImport.html
│ │ ├── CsdlInclude-1.html
│ │ ├── CsdlInclude.html
│ │ ├── CsdlIncludeAnnotations-1.html
│ │ ├── CsdlIncludeAnnotations.html
│ │ ├── CsdlKey-1.html
│ │ ├── CsdlKey.html
│ │ ├── CsdlMember-1.html
│ │ ├── CsdlMember.html
│ │ ├── CsdlNavigationProperty-1.html
│ │ ├── CsdlNavigationProperty.html
│ │ ├── CsdlNavigationPropertyBinding-1.html
│ │ ├── CsdlNavigationPropertyBinding.html
│ │ ├── CsdlNavigationPropertyPath-1.html
│ │ ├── CsdlNavigationPropertyPath.html
│ │ ├── CsdlOnDelete-1.html
│ │ ├── CsdlOnDelete.html
│ │ ├── CsdlParameter-1.html
│ │ ├── CsdlParameter.html
│ │ ├── CsdlProperty-1.html
│ │ ├── CsdlProperty.html
│ │ ├── CsdlPropertyPath-1.html
│ │ ├── CsdlPropertyPath.html
│ │ ├── CsdlPropertyRef-1.html
│ │ ├── CsdlPropertyRef.html
│ │ ├── CsdlPropertyValue-1.html
│ │ ├── CsdlPropertyValue.html
│ │ ├── CsdlRecord-1.html
│ │ ├── CsdlRecord.html
│ │ ├── CsdlReference-1.html
│ │ ├── CsdlReference.html
│ │ ├── CsdlReferentialConstraint-1.html
│ │ ├── CsdlReferentialConstraint.html
│ │ ├── CsdlReturnType-1.html
│ │ ├── CsdlReturnType.html
│ │ ├── CsdlSchema-1.html
│ │ ├── CsdlSchema.html
│ │ ├── CsdlSingleton-1.html
│ │ ├── CsdlSingleton.html
│ │ ├── CsdlString-1.html
│ │ ├── CsdlString.html
│ │ ├── CsdlStructuralProperty-1.html
│ │ ├── CsdlStructuralProperty.html
│ │ ├── CsdlStructuredType-1.html
│ │ ├── CsdlStructuredType.html
│ │ ├── CsdlTerm-1.html
│ │ ├── CsdlTerm.html
│ │ ├── CsdlTypeDefinition-1.html
│ │ ├── CsdlTypeDefinition.html
│ │ ├── DateAndTimeFunctions.html
│ │ ├── Entity.html
│ │ ├── EntityProperty.html
│ │ ├── Enum.html
│ │ ├── EnumValue.html
│ │ ├── ExpandExpression.html
│ │ ├── ExpandField.html
│ │ ├── Expression.html
│ │ ├── Field-1.html
│ │ ├── Field.html
│ │ ├── FilterExpression.html
│ │ ├── Function.html
│ │ ├── GeoFunctions.html
│ │ ├── GroupBy.html
│ │ ├── GroupByTransformations.html
│ │ ├── Grouping.html
│ │ ├── GroupingOperators.html
│ │ ├── Import.html
│ │ ├── Index.html
│ │ ├── Lambda.html
│ │ ├── LambdaOperators.html
│ │ ├── LogicalOperators.html
│ │ ├── Metadata.html
│ │ ├── Module.html
│ │ ├── ODataActionResource.html
│ │ ├── ODataAnnotatable.html
│ │ ├── ODataAnnotation.html
│ │ ├── ODataAnnotations.html
│ │ ├── ODataApi.html
│ │ ├── ODataApiOptions.html
│ │ ├── ODataBaseCache.html
│ │ ├── ODataBaseService.html
│ │ ├── ODataBatchRequest.html
│ │ ├── ODataBatchResource.html
│ │ ├── ODataCallable.html
│ │ ├── ODataCallableParser.html
│ │ ├── ODataCollection.html
│ │ ├── ODataConfigAsyncLoader.html
│ │ ├── ODataConfigLoader.html
│ │ ├── ODataConfigSyncLoader.html
│ │ ├── ODataCountResource.html
│ │ ├── ODataEntitiesAnnotations.html
│ │ ├── ODataEntityAnnotations.html
│ │ ├── ODataEntityContainer.html
│ │ ├── ODataEntityResource.html
│ │ ├── ODataEntityService.html
│ │ ├── ODataEntitySet.html
│ │ ├── ODataEntitySetResource.html
│ │ ├── ODataEntitySetService.html
│ │ ├── ODataEntityTypeKey.html
│ │ ├── ODataEnumType.html
│ │ ├── ODataEnumTypeFieldParser.html
│ │ ├── ODataEnumTypeParser.html
│ │ ├── ODataFunctionResource.html
│ │ ├── ODataInMemoryCache.html
│ │ ├── ODataInStorageCache.html
│ │ ├── ODataMediaResource.html
│ │ ├── ODataMetadata-1.html
│ │ ├── ODataMetadata.html
│ │ ├── ODataMetadataLoader.html
│ │ ├── ODataMetadataParser-1.html
│ │ ├── ODataMetadataParser.html
│ │ ├── ODataMetadataResource.html
│ │ ├── ODataModel.html
│ │ ├── ODataModelAttribute.html
│ │ ├── ODataModelEvent.html
│ │ ├── ODataModelEventEmitter.html
│ │ ├── ODataModelField.html
│ │ ├── ODataModelOptions.html
│ │ ├── ODataNavigationPropertyResource.html
│ │ ├── ODataParameterParser.html
│ │ ├── ODataParserSchemaElement.html
│ │ ├── ODataPathSegments.html
│ │ ├── ODataPathSegmentsHandler.html
│ │ ├── ODataPropertyAnnotations.html
│ │ ├── ODataPropertyResource.html
│ │ ├── ODataQueryOptionHandler.html
│ │ ├── ODataQueryOptions.html
│ │ ├── ODataQueryOptionsHandler.html
│ │ ├── ODataReferenceResource.html
│ │ ├── ODataReferential.html
│ │ ├── ODataRequest.html
│ │ ├── ODataResource.html
│ │ ├── ODataResponse.html
│ │ ├── ODataResponseOptions.html
│ │ ├── ODataSchema.html
│ │ ├── ODataSchemaElement.html
│ │ ├── ODataSettings.html
│ │ ├── ODataSingleton.html
│ │ ├── ODataSingletonResource.html
│ │ ├── ODataSingletonService.html
│ │ ├── ODataStructuredType.html
│ │ ├── ODataStructuredTypeFieldParser.html
│ │ ├── ODataStructuredTypeParser.html
│ │ ├── ODataValueResource.html
│ │ ├── Operator.html
│ │ ├── OrderByExpression.html
│ │ ├── OrderByField.html
│ │ ├── SearchExpression.html
│ │ ├── SearchTerm.html
│ │ ├── SegmentHandler.html
│ │ ├── SelectExpression.html
│ │ ├── Service.html
│ │ ├── StringAndCollectionFunctions.html
│ │ ├── StringFunctions.html
│ │ ├── Transformations.html
│ │ ├── Type.html
│ │ └── TypeFunctions.html
│ ├── contributing.html
│ ├── dependencies.html
│ ├── fonts
│ │ ├── ionicons.eot
│ │ ├── ionicons.svg
│ │ ├── ionicons.ttf
│ │ ├── ionicons.woff
│ │ ├── ionicons.woff2
│ │ ├── roboto-v15-latin-300.eot
│ │ ├── roboto-v15-latin-300.svg
│ │ ├── roboto-v15-latin-300.ttf
│ │ ├── roboto-v15-latin-300.woff
│ │ ├── roboto-v15-latin-300.woff2
│ │ ├── roboto-v15-latin-700.eot
│ │ ├── roboto-v15-latin-700.svg
│ │ ├── roboto-v15-latin-700.ttf
│ │ ├── roboto-v15-latin-700.woff
│ │ ├── roboto-v15-latin-700.woff2
│ │ ├── roboto-v15-latin-italic.eot
│ │ ├── roboto-v15-latin-italic.svg
│ │ ├── roboto-v15-latin-italic.ttf
│ │ ├── roboto-v15-latin-italic.woff
│ │ ├── roboto-v15-latin-italic.woff2
│ │ ├── roboto-v15-latin-regular.eot
│ │ ├── roboto-v15-latin-regular.svg
│ │ ├── roboto-v15-latin-regular.ttf
│ │ ├── roboto-v15-latin-regular.woff
│ │ └── roboto-v15-latin-regular.woff2
│ ├── images
│ │ ├── compodoc-vectorise-inverted.png
│ │ ├── compodoc-vectorise-inverted.svg
│ │ ├── compodoc-vectorise.png
│ │ ├── compodoc-vectorise.svg
│ │ └── favicon.ico
│ ├── index.html
│ ├── injectables
│ │ ├── ODataClient.html
│ │ └── ODataServiceFactory.html
│ ├── interfaces
│ │ ├── FieldParser.html
│ │ ├── ODataApiConfigOptions.html
│ │ ├── ODataCache.html
│ │ ├── ODataCacheEntry.html
│ │ ├── ODataVersionHelper.html
│ │ ├── Parser.html
│ │ ├── ParserOptions.html
│ │ ├── PassedInitialConfig.html
│ │ ├── Renderable.html
│ │ ├── ResponseJson.html
│ │ ├── ResponseOptions.html
│ │ ├── Schema.html
│ │ └── StructuredTypeFieldOptions.html
│ ├── js
│ │ ├── compodoc.js
│ │ ├── lazy-load-graphs.js
│ │ ├── libs
│ │ │ ├── EventDispatcher.js
│ │ │ ├── bootstrap-native.js
│ │ │ ├── clipboard.min.js
│ │ │ ├── custom-elements-es5-adapter.js
│ │ │ ├── custom-elements.min.js
│ │ │ ├── d3.v3.min.js
│ │ │ ├── deep-iterator.js
│ │ │ ├── es6-shim.min.js
│ │ │ ├── htmlparser.js
│ │ │ ├── innersvg.js
│ │ │ ├── lit-html.js
│ │ │ ├── prism.js
│ │ │ ├── promise.min.js
│ │ │ ├── svg-pan-zoom.min.js
│ │ │ ├── tablesort.min.js
│ │ │ ├── tablesort.number.min.js
│ │ │ ├── vis.min.js
│ │ │ └── zepto.min.js
│ │ ├── menu-wc.js
│ │ ├── menu-wc_es5.js
│ │ ├── menu.js
│ │ ├── routes.js
│ │ ├── search
│ │ │ ├── lunr.min.js
│ │ │ ├── search-lunr.js
│ │ │ ├── search.js
│ │ │ └── search_index.js
│ │ ├── sourceCode.js
│ │ ├── svg-pan-zoom.controls.js
│ │ ├── tabs.js
│ │ └── tree.js
│ ├── license.html
│ ├── miscellaneous
│ │ ├── enumerations.html
│ │ ├── functions.html
│ │ ├── typealiases.html
│ │ └── variables.html
│ ├── modules.html
│ ├── modules
│ │ └── ODataModule.html
│ ├── overview.html
│ ├── properties.html
│ └── styles
│ │ ├── bootstrap-card.css
│ │ ├── bootstrap.min.css
│ │ ├── compodoc.css
│ │ ├── dark.css
│ │ ├── ionicons.min.css
│ │ ├── laravel.css
│ │ ├── material.css
│ │ ├── original.css
│ │ ├── postmark.css
│ │ ├── prism.css
│ │ ├── readthedocs.css
│ │ ├── reset.css
│ │ ├── stripe.css
│ │ ├── style.css
│ │ ├── tablesort.css
│ │ └── vagrant.css
├── apigentool.md
├── models.md
├── queries.md
├── schema.md
├── schemaless.md
└── schematics.md
├── package-lock.json
├── package.json
├── projects
└── angular-odata
│ ├── README.md
│ ├── karma.config.js
│ ├── ng-package.json
│ ├── package-lock.json
│ ├── package.json
│ ├── schematics
│ ├── apigen
│ │ ├── angular
│ │ │ ├── api-config.ts
│ │ │ ├── base.ts
│ │ │ ├── entity.ts
│ │ │ ├── enum.ts
│ │ │ ├── import.ts
│ │ │ ├── module.ts
│ │ │ └── service.ts
│ │ ├── files
│ │ │ ├── api-config
│ │ │ │ └── __fileName__.ts
│ │ │ ├── entity
│ │ │ │ └── __fileName__.ts
│ │ │ ├── entitycontainer-service
│ │ │ │ └── __fileName__.ts
│ │ │ ├── entityset-service
│ │ │ │ └── __fileName__.ts
│ │ │ ├── enum
│ │ │ │ └── __fileName__.ts
│ │ │ ├── index
│ │ │ │ └── __fileName__.ts
│ │ │ ├── metadata
│ │ │ │ └── metadata.json
│ │ │ ├── module
│ │ │ │ └── __fileName__.ts
│ │ │ └── singleton-service
│ │ │ │ └── __fileName__.ts
│ │ ├── index.ts
│ │ ├── metadata
│ │ │ ├── csdl
│ │ │ │ ├── csdl-annotation.ts
│ │ │ │ ├── csdl-entity-container.ts
│ │ │ │ ├── csdl-entity-set.ts
│ │ │ │ ├── csdl-enum-type.ts
│ │ │ │ ├── csdl-function-action.ts
│ │ │ │ ├── csdl-navigation-property-binding.ts
│ │ │ │ ├── csdl-reference.ts
│ │ │ │ ├── csdl-schema.ts
│ │ │ │ ├── csdl-singleton.ts
│ │ │ │ ├── csdl-structural-property.ts
│ │ │ │ ├── csdl-structured-type.ts
│ │ │ │ └── csdl-type-definition.ts
│ │ │ ├── index.ts
│ │ │ ├── metadata.ts
│ │ │ └── parser.ts
│ │ ├── schema.json
│ │ ├── schema.ts
│ │ └── utils.ts
│ ├── collection.json
│ ├── ng-add
│ │ └── index.ts
│ └── random.ts
│ ├── src
│ ├── lib
│ │ ├── annotations.spec.ts
│ │ ├── annotations.ts
│ │ ├── api.ts
│ │ ├── cache
│ │ │ ├── cache.ts
│ │ │ ├── index.ts
│ │ │ ├── memory.ts
│ │ │ └── storage.ts
│ │ ├── client.spec.ts
│ │ ├── client.ts
│ │ ├── constants.ts
│ │ ├── helper.ts
│ │ ├── index.ts
│ │ ├── loaders.ts
│ │ ├── metadata
│ │ │ ├── csdl
│ │ │ │ ├── csdl-annotation.ts
│ │ │ │ ├── csdl-entity-container.ts
│ │ │ │ ├── csdl-entity-set.ts
│ │ │ │ ├── csdl-enum-type.ts
│ │ │ │ ├── csdl-function-action.ts
│ │ │ │ ├── csdl-navigation-property-binding.ts
│ │ │ │ ├── csdl-reference.ts
│ │ │ │ ├── csdl-schema.ts
│ │ │ │ ├── csdl-singleton.ts
│ │ │ │ ├── csdl-structural-property.ts
│ │ │ │ ├── csdl-structured-type.ts
│ │ │ │ └── csdl-type-definition.ts
│ │ │ ├── index.ts
│ │ │ ├── metadata.ts
│ │ │ └── parser.ts
│ │ ├── models
│ │ │ ├── collection.ts
│ │ │ ├── index.ts
│ │ │ ├── model.ts
│ │ │ └── options.ts
│ │ ├── module.ts
│ │ ├── options.ts
│ │ ├── resources
│ │ │ ├── index.ts
│ │ │ ├── options.ts
│ │ │ ├── path
│ │ │ │ ├── handlers.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── segments.spec.ts
│ │ │ │ └── segments.ts
│ │ │ ├── query
│ │ │ │ ├── builder.spec.ts
│ │ │ │ ├── builder.ts
│ │ │ │ ├── expressions
│ │ │ │ │ ├── apply.ts
│ │ │ │ │ ├── base.ts
│ │ │ │ │ ├── compute.spec.ts
│ │ │ │ │ ├── compute.ts
│ │ │ │ │ ├── count.spec.ts
│ │ │ │ │ ├── count.ts
│ │ │ │ │ ├── expand.spec.ts
│ │ │ │ │ ├── expand.ts
│ │ │ │ │ ├── filter.spec.ts
│ │ │ │ │ ├── filter.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── orderby.spec.ts
│ │ │ │ │ ├── orderby.ts
│ │ │ │ │ ├── search.spec.ts
│ │ │ │ │ ├── search.ts
│ │ │ │ │ ├── select.spec.ts
│ │ │ │ │ ├── select.ts
│ │ │ │ │ └── syntax.ts
│ │ │ │ ├── handlers.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── options.spec.ts
│ │ │ │ └── options.ts
│ │ │ ├── request.ts
│ │ │ ├── resource.spec.ts
│ │ │ ├── resource.ts
│ │ │ ├── response.ts
│ │ │ └── types
│ │ │ │ ├── action.ts
│ │ │ │ ├── batch.ts
│ │ │ │ ├── count.ts
│ │ │ │ ├── entity-set.ts
│ │ │ │ ├── entity.ts
│ │ │ │ ├── function.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── media.ts
│ │ │ │ ├── metadata.ts
│ │ │ │ ├── navigation-property.ts
│ │ │ │ ├── options.ts
│ │ │ │ ├── property.ts
│ │ │ │ ├── reference.ts
│ │ │ │ ├── singleton.ts
│ │ │ │ └── value.ts
│ │ ├── schema
│ │ │ ├── annotation.ts
│ │ │ ├── callable.ts
│ │ │ ├── element.ts
│ │ │ ├── entity-container.ts
│ │ │ ├── entity-set.ts
│ │ │ ├── enum-type.ts
│ │ │ ├── index.ts
│ │ │ ├── parsers
│ │ │ │ ├── callable.ts
│ │ │ │ ├── edm.ts
│ │ │ │ ├── enum-type.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── parser.spec.ts
│ │ │ │ └── structured-type.ts
│ │ │ ├── schema.ts
│ │ │ ├── singleton.ts
│ │ │ └── structured-type.ts
│ │ ├── services
│ │ │ ├── base.ts
│ │ │ ├── entity-set.ts
│ │ │ ├── entity.ts
│ │ │ ├── factory.ts
│ │ │ ├── index.ts
│ │ │ └── singleton.ts
│ │ ├── settings.ts
│ │ ├── trippin.spec.ts
│ │ ├── types.ts
│ │ └── utils
│ │ │ ├── arraybuffers.ts
│ │ │ ├── arrays.spec.ts
│ │ │ ├── arrays.ts
│ │ │ ├── dates.ts
│ │ │ ├── durations.ts
│ │ │ ├── enums.spec.ts
│ │ │ ├── enums.ts
│ │ │ ├── http.spec.ts
│ │ │ ├── http.ts
│ │ │ ├── index.ts
│ │ │ ├── objects.ts
│ │ │ ├── odata.ts
│ │ │ ├── strings.spec.ts
│ │ │ ├── strings.ts
│ │ │ ├── types.ts
│ │ │ └── urls.ts
│ └── public-api.ts
│ ├── tsconfig.lib.json
│ ├── tsconfig.lib.prod.json
│ ├── tsconfig.schematics.json
│ └── tsconfig.spec.json
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 | ij_typescript_use_double_quotes = false
14 |
15 | [*.md]
16 | max_line_length = off
17 | trim_trailing_whitespace = false
18 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [diegomvh] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ main ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ main ]
20 | schedule:
21 | - cron: '23 19 * * 0'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'javascript' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
37 | # Learn more:
38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
39 |
40 | steps:
41 | - name: Checkout repository
42 | uses: actions/checkout@v2
43 |
44 | # Initializes the CodeQL tools for scanning.
45 | - name: Initialize CodeQL
46 | uses: github/codeql-action/init@v1
47 | with:
48 | languages: ${{ matrix.language }}
49 | # If you wish to specify custom queries, you can do so here or in a config file.
50 | # By default, queries listed here will override any specified in a config file.
51 | # Prefix the list here with "+" to use these queries and those in the config file.
52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
53 |
54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
55 | # If this step fails, then you should remove it and run the build manually (see below)
56 | - name: Autobuild
57 | uses: github/codeql-action/autobuild@v1
58 |
59 | # ℹ️ Command-line programs to run using the OS shell.
60 | # 📚 https://git.io/JvXDl
61 |
62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
63 | # and modify them (or add more) to build your code if your project
64 | # uses a compiled language
65 |
66 | #- run: |
67 | # make bootstrap
68 | # make release
69 |
70 | - name: Perform CodeQL Analysis
71 | uses: github/codeql-action/analyze@v1
72 |
--------------------------------------------------------------------------------
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [main]
9 | pull_request:
10 | branches: [main]
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 |
16 | strategy:
17 | matrix:
18 | node-version: [18.x, 20.x]
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 | - name: Use Node.js ${{ matrix.node-version }}
23 | uses: actions/setup-node@v1
24 | with:
25 | node-version: ${{ matrix.node-version }}
26 | - run: npm ci
27 | - run: npm run build --if-present
28 | - run: npm test
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
2 |
3 | # Compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 | /bazel-out
8 |
9 | # Node
10 | /node_modules
11 | npm-debug.log
12 | yarn-error.log
13 |
14 | # IDEs and editors
15 | .idea/
16 | .project
17 | .classpath
18 | .c9/
19 | *.launch
20 | .settings/
21 | *.sublime-workspace
22 |
23 | # Visual Studio Code
24 | .vscode/*
25 | !.vscode/settings.json
26 | !.vscode/tasks.json
27 | !.vscode/launch.json
28 | !.vscode/extensions.json
29 | .history/*
30 |
31 | # Miscellaneous
32 | /.angular/cache
33 | .sass-cache/
34 | /connect.lock
35 | /coverage
36 | /libpeerconnection.log
37 | testem.log
38 | /typings
39 |
40 | # System files
41 | .DS_Store
42 | Thumbs.db
43 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
3 | "version": "0.2.0",
4 | "configurations": [
5 | {
6 | "name": "ng serve",
7 | "type": "chrome",
8 | "request": "launch",
9 | "preLaunchTask": "npm: start",
10 | "url": "http://localhost:4200/"
11 | },
12 | {
13 | "name": "ng test",
14 | "type": "chrome",
15 | "request": "launch",
16 | "preLaunchTask": "npm: test",
17 | "url": "http://localhost:9876/debug.html"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
3 | "version": "2.0.0",
4 | "tasks": [
5 | {
6 | "type": "npm",
7 | "script": "start",
8 | "isBackground": true,
9 | "problemMatcher": {
10 | "owner": "typescript",
11 | "pattern": "$tsc",
12 | "background": {
13 | "activeOnStart": true,
14 | "beginsPattern": {
15 | "regexp": "(.*?)"
16 | },
17 | "endsPattern": {
18 | "regexp": "bundle generation complete"
19 | }
20 | }
21 | }
22 | },
23 | {
24 | "type": "npm",
25 | "script": "test",
26 | "isBackground": true,
27 | "problemMatcher": {
28 | "owner": "typescript",
29 | "pattern": "$tsc",
30 | "background": {
31 | "activeOnStart": true,
32 | "beginsPattern": {
33 | "regexp": "(.*?)"
34 | },
35 | "endsPattern": {
36 | "regexp": "bundle generation complete"
37 | }
38 | }
39 | }
40 | }
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [Unreleased]
9 |
10 | ### Added
11 |
12 | ### Changed
13 |
14 | ### Removed
15 |
16 | ## [0.128.0] - 2024-06-03
17 |
18 | ### Added
19 |
20 | ### Fixed
21 |
22 | ### Changed
23 |
24 | ### Removed
25 |
26 | [unreleased]: https://github.com/diegomvh/angular-odata/compare/v0.128.0...main
27 | [0.128.0]: https://github.com/diegomvh/angular-odata/compare/v0.127.0...v0.128.0
28 | [0.127.0]: https://github.com/diegomvh/angular-odata/compare/v0.126.0...v0.127.0
29 | [0.126.0]: https://github.com/diegomvh/angular-odata/compare/v0.125.0...v0.126.0
30 | [0.125.0]: https://github.com/diegomvh/angular-odata/compare/v0.124.0...v0.125.0
31 | [0.124.0]: https://github.com/diegomvh/angular-odata/compare/v0.123.0...v0.124.0
32 | [0.123.0]: https://github.com/diegomvh/angular-odata/compare/v0.122.0...v0.123.0
33 | [0.122.0]: https://github.com/diegomvh/angular-odata/compare/v0.121.0...v0.122.0
34 | [0.121.0]: https://github.com/diegomvh/angular-odata/compare/v0.120.0...v0.121.0
35 | [0.120.0]: https://github.com/diegomvh/angular-odata/compare/v0.115.0...v0.120.0
36 | [0.115.0]: https://github.com/diegomvh/angular-odata/compare/v0.110.0...v0.115.0
37 | [0.110.0]: https://github.com/diegomvh/angular-odata/compare/v0.105.0...v0.110.0
38 | [0.105.0]: https://github.com/diegomvh/angular-odata/compare/v0.102.0...v0.105.0
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Diego van Haaster
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Angular OData
2 |
3 |
4 | A fluent API for querying, creating, updating and deleting OData resources in Angular.
5 |
6 |
7 |
8 |
9 | Contributing
10 | ·
11 | Documentation
12 | ·
13 | Demo
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | ## Installation
30 |
31 | Install from npm:
32 |
33 | ```bash
34 | npm i angular-odata
35 | ```
36 |
37 | ## OData Version
38 |
39 | The library works mainly with OData Version 4, however, it incorporates basic support for versions 3 and 2.
40 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "angular-odata": {
7 | "projectType": "library",
8 | "root": "projects/angular-odata",
9 | "sourceRoot": "projects/angular-odata/src",
10 | "prefix": "lib",
11 | "architect": {
12 | "build": {
13 | "builder": "@angular-devkit/build-angular:ng-packagr",
14 | "options": {
15 | "project": "projects/angular-odata/ng-package.json"
16 | },
17 | "configurations": {
18 | "production": {
19 | "tsConfig": "projects/angular-odata/tsconfig.lib.prod.json"
20 | },
21 | "development": {
22 | "tsConfig": "projects/angular-odata/tsconfig.lib.json"
23 | }
24 | },
25 | "defaultConfiguration": "production"
26 | },
27 | "test": {
28 | "builder": "@angular-devkit/build-angular:karma",
29 | "options": {
30 | "tsConfig": "projects/angular-odata/tsconfig.spec.json",
31 | "karmaConfig": "projects/angular-odata/karma.config.js",
32 | "polyfills": [
33 | "zone.js",
34 | "zone.js/testing"
35 | ]
36 | }
37 | }
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ## Table of contents
2 |
3 | - [Schema](./schema.md)
4 | - [OData API Generator](./apigentool.md)
5 | - [Schematics](./schematics.md)
6 | - [Usage](./schema.md#usage)
7 | - [Schemaless](./schemaless.md)
8 | - [Usage](./schemaless.md#usage)
9 | - [Queries](./queries.md#query-builder)
10 | - [Models](./models.md)
11 | - [Compodoc](https://diegomvh.github.io/angular-odata/docs/api/)
--------------------------------------------------------------------------------
/docs/api/fonts/ionicons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/ionicons.eot
--------------------------------------------------------------------------------
/docs/api/fonts/ionicons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/ionicons.ttf
--------------------------------------------------------------------------------
/docs/api/fonts/ionicons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/ionicons.woff
--------------------------------------------------------------------------------
/docs/api/fonts/ionicons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/ionicons.woff2
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-300.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-300.eot
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-300.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-300.ttf
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-300.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-300.woff
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-300.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-300.woff2
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-700.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-700.eot
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-700.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-700.ttf
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-700.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-700.woff
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-700.woff2
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-italic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-italic.eot
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-italic.ttf
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-italic.woff
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-italic.woff2
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-regular.eot
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-regular.ttf
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-regular.woff
--------------------------------------------------------------------------------
/docs/api/fonts/roboto-v15-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/fonts/roboto-v15-latin-regular.woff2
--------------------------------------------------------------------------------
/docs/api/images/compodoc-vectorise-inverted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/images/compodoc-vectorise-inverted.png
--------------------------------------------------------------------------------
/docs/api/images/compodoc-vectorise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/images/compodoc-vectorise.png
--------------------------------------------------------------------------------
/docs/api/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diegomvh/angular-odata/56d35c621d92f39d299726f65a2db05f9d3b2cdc/docs/api/images/favicon.ico
--------------------------------------------------------------------------------
/docs/api/js/compodoc.js:
--------------------------------------------------------------------------------
1 | var compodoc = {
2 | EVENTS: {
3 | READY: 'compodoc.ready',
4 | SEARCH_READY: 'compodoc.search.ready'
5 | }
6 | };
7 |
8 | Object.assign( compodoc, EventDispatcher.prototype );
9 |
10 | document.addEventListener('DOMContentLoaded', function() {
11 | compodoc.dispatchEvent({
12 | type: compodoc.EVENTS.READY
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/docs/api/js/lazy-load-graphs.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('DOMContentLoaded', function() {
2 | var lazyGraphs = [].slice.call(document.querySelectorAll('[lazy]'));
3 | var active = false;
4 |
5 | var lazyLoad = function() {
6 | if (active === false) {
7 | active = true;
8 |
9 | setTimeout(function() {
10 | lazyGraphs.forEach(function(lazyGraph) {
11 | if (
12 | lazyGraph.getBoundingClientRect().top <= window.innerHeight &&
13 | lazyGraph.getBoundingClientRect().bottom >= 0 &&
14 | getComputedStyle(lazyGraph).display !== 'none'
15 | ) {
16 | lazyGraph.data = lazyGraph.getAttribute('lazy');
17 | lazyGraph.removeAttribute('lazy');
18 |
19 | lazyGraphs = lazyGraphs.filter(function(image) { return image !== lazyGraph});
20 |
21 | if (lazyGraphs.length === 0) {
22 | document.removeEventListener('scroll', lazyLoad);
23 | window.removeEventListener('resize', lazyLoad);
24 | window.removeEventListener('orientationchange', lazyLoad);
25 | }
26 | }
27 | });
28 |
29 | active = false;
30 | }, 200);
31 | }
32 | };
33 |
34 | // initial load
35 | lazyLoad();
36 |
37 | var container = document.querySelector('.container-fluid.modules');
38 | if (container) {
39 | container.addEventListener('scroll', lazyLoad);
40 | window.addEventListener('resize', lazyLoad);
41 | window.addEventListener('orientationchange', lazyLoad);
42 | }
43 |
44 | });
45 |
--------------------------------------------------------------------------------
/docs/api/js/libs/EventDispatcher.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | */
4 |
5 | var EventDispatcher=function(){};Object.assign(EventDispatcher.prototype,{addEventListener:function(i,t){void 0===this._listeners&&(this._listeners={});var e=this._listeners;void 0===e[i]&&(e[i]=[]),-1===e[i].indexOf(t)&&e[i].push(t)},hasEventListener:function(i,t){if(void 0===this._listeners)return!1;var e=this._listeners;return void 0!==e[i]&&-1!==e[i].indexOf(t)},removeEventListener:function(i,t){if(void 0!==this._listeners){var e=this._listeners[i];if(void 0!==e){var s=e.indexOf(t);-1!==s&&e.splice(s,1)}}},dispatchEvent:function(i){if(void 0!==this._listeners){var t=this._listeners[i.type];if(void 0!==t){i.target=this;var e=[],s=0,n=t.length;for(s=0;s",">"));else if(1==i){if(r.push("<",e.tagName),e.hasAttributes())for(var n=e.attributes,s=0,o=n.length;s");for(var h=e.childNodes,s=0,o=h.length;s")}else r.push("/>")}else{if(8!=i)throw"Error serializing XML. Unhandled node of type: "+i;r.push("\x3c!--",e.nodeValue,"--\x3e")}};Object.defineProperty(e.prototype,"innerHTML",{get:function(){for(var e=[],r=this.firstChild;r;)t(r,e),r=r.nextSibling;return e.join("")},set:function(e){for(;this.firstChild;)this.removeChild(this.firstChild);try{var t=new DOMParser;t.async=!1,sXML="";for(var r=t.parseFromString(sXML,"text/xml").documentElement.firstChild;r;)this.appendChild(this.ownerDocument.importNode(r,!0)),r=r.nextSibling}catch(e){throw new Error("Error parsing XML string")}}})}}((0,eval)("this").SVGElement);
--------------------------------------------------------------------------------
/docs/api/js/libs/promise.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 (c) Pierre Duquesne
3 | * Licensed under the New BSD License.
4 | * https://github.com/stackp/promisejs
5 | */
6 | (function(a){function b(){this._callbacks=[];}b.prototype.then=function(a,c){var d;if(this._isdone)d=a.apply(c,this.result);else{d=new b();this._callbacks.push(function(){var b=a.apply(c,arguments);if(b&&typeof b.then==='function')b.then(d.done,d);});}return d;};b.prototype.done=function(){this.result=arguments;this._isdone=true;for(var a=0;a=300)&&j.status!==304);h.done(a,j.responseText,j);}};j.send(k);return h;}function h(a){return function(b,c,d){return g(a,b,c,d);};}var i={Promise:b,join:c,chain:d,ajax:g,get:h('GET'),post:h('POST'),put:h('PUT'),del:h('DELETE'),ENOXHR:1,ETIMEOUT:2,ajaxTimeout:0};if(typeof define==='function'&&define.amd)define(function(){return i;});else a.promise=i;})(this);
--------------------------------------------------------------------------------
/docs/api/js/libs/tablesort.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * tablesort v5.2.1 (2021-10-30)
3 | * http://tristen.ca/tablesort/demo/
4 | * Copyright (c) 2021 ; Licensed MIT
5 | */
6 | !function(){function a(b,c){if(!(this instanceof a))return new a(b,c);if(!b||"TABLE"!==b.tagName)throw new Error("Element must be a table");this.init(b,c||{})}var b=[],c=function(a){var b;return window.CustomEvent&&"function"==typeof window.CustomEvent?b=new CustomEvent(a):(b=document.createEvent("CustomEvent"),b.initCustomEvent(a,!1,!1,void 0)),b},d=function(a,b){return a.getAttribute(b.sortAttribute||"data-sort")||a.textContent||a.innerText||""},e=function(a,b){return a=a.trim().toLowerCase(),b=b.trim().toLowerCase(),a===b?0:a0)if(a.tHead&&a.tHead.rows.length>0){for(e=0;e0&&n.push(m),o++;if(!n)return}for(o=0;o 0) {
9 | tabs = tabs[0].querySelectorAll('li');
10 | for (var i = 0; i < tabs.length; i++) {
11 | tabs[i].addEventListener('click', updateAddress);
12 | var linkTag = tabs[i].querySelector('a');
13 | if (location.hash !== '') {
14 | var currentHash = location.hash.substr(1);
15 | if (currentHash === linkTag.dataset.link) {
16 | linkTag.click();
17 | }
18 | }
19 | }
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/docs/api/styles/dark.css:
--------------------------------------------------------------------------------
1 | body.dark {
2 | background: #212121;
3 | color: #fafafa;
4 | }
5 |
6 | .dark code {
7 | color: #e09393;
8 | }
9 |
10 | .dark a,
11 | .dark .menu ul.list li a.active {
12 | color: #7fc9ff;
13 | }
14 |
15 | .dark .menu {
16 | background: #212121;
17 | border-right: 1px solid #444;
18 | }
19 |
20 | .dark .menu ul.list li a {
21 | color: #fafafa;
22 | }
23 |
24 | .dark .menu ul.list li.divider {
25 | background: #444;
26 | }
27 |
28 | .dark .xs-menu ul.list li:nth-child(2) {
29 | margin: 0;
30 | background: none;
31 | }
32 |
33 | .dark .menu ul.list li:nth-child(2) {
34 | margin: 0;
35 | background: none;
36 | }
37 |
38 | .dark #book-search-input {
39 | background: #212121;
40 | border-top: 1px solid #444;
41 | border-bottom: 1px solid #444;
42 | color: #fafafa;
43 | }
44 |
45 | .dark .table.metadata > tbody > tr:hover {
46 | color: #555;
47 | }
48 |
49 | .dark .table-bordered {
50 | border: 1px solid #444;
51 | }
52 |
53 | .dark .table-bordered > tbody > tr > td,
54 | .dark .table-bordered > tbody > tr > th,
55 | .dark .table-bordered > tfoot > tr > td,
56 | .dark .table-bordered > tfoot > tr > th,
57 | .dark .table-bordered > thead > tr > td,
58 | .dark .table-bordered > thead > tr > th {
59 | border: 1px solid #444;
60 | }
61 |
62 | .dark .coverage a,
63 | .dark .coverage-count {
64 | color: #fafafa;
65 | }
66 |
67 | .dark .coverage-header {
68 | color: black;
69 | }
70 |
71 | .dark .routes svg text,
72 | .dark .routes svg a {
73 | fill: white;
74 | }
75 | .dark .routes svg rect {
76 | fill: #212121 !important;
77 | }
78 |
79 | .dark .navbar-default,
80 | .dark .btn-default {
81 | background-color: black;
82 | border-color: #444;
83 | color: #fafafa;
84 | }
85 |
86 | .dark .navbar-default .navbar-brand {
87 | color: #fafafa;
88 | }
89 |
90 | .dark .overview .card,
91 | .dark .modules .card {
92 | background: #171717;
93 | color: #fafafa;
94 | border: 1px solid #444;
95 | }
96 | .dark .overview .card a {
97 | color: #fafafa;
98 | }
99 |
100 | .dark .modules .card-header {
101 | background: none;
102 | border-bottom: 1px solid #444;
103 | }
104 |
105 | .dark .module .list-group-item {
106 | background: none;
107 | border: 1px solid #444;
108 | }
109 |
110 | .dark .container-fluid.module h3 a {
111 | color: #337ab7;
112 | }
113 |
114 | .dark table.params thead {
115 | background: #484848;
116 | color: #fafafa;
117 | }
118 |
119 | .dark .content table {
120 | --bs-table-color: #fafafa;
121 | }
122 |
--------------------------------------------------------------------------------
/docs/api/styles/laravel.css:
--------------------------------------------------------------------------------
1 | .nav-tabs > li > a {
2 | text-decoration: none;
3 | }
4 |
5 | .navbar-default .navbar-brand {
6 | color: #f4645f;
7 | text-decoration: none;
8 | font-size: 16px;
9 | }
10 |
11 | .menu ul.list li a[data-type='chapter-link'],
12 | .menu ul.list li.chapter .simple {
13 | color: #525252;
14 | border-bottom: 1px dashed rgba(0, 0, 0, 0.1);
15 | }
16 |
17 | .content h1,
18 | .content h2,
19 | .content h3,
20 | .content h4,
21 | .content h5 {
22 | color: #292e31;
23 | font-weight: normal;
24 | }
25 |
26 | .content {
27 | color: #4c555a;
28 | }
29 |
30 | a {
31 | color: #f4645f;
32 | text-decoration: underline;
33 | }
34 | a:hover {
35 | color: #f1362f;
36 | }
37 |
38 | .menu ul.list li:nth-child(2) {
39 | margin-top: 0;
40 | }
41 |
42 | .menu ul.list li.title a {
43 | color: #f4645f;
44 | text-decoration: none;
45 | font-size: 16px;
46 | }
47 |
48 | .menu ul.list li a {
49 | color: #f4645f;
50 | text-decoration: none;
51 | }
52 | .menu ul.list li a.active {
53 | color: #f4645f;
54 | font-weight: bold;
55 | }
56 |
57 | code {
58 | box-sizing: border-box;
59 | display: inline-block;
60 | padding: 0 5px;
61 | background: #f0f2f1;
62 | border-radius: 3px;
63 | color: #b93d6a;
64 | font-size: 13px;
65 | line-height: 20px;
66 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.125);
67 | }
68 |
69 | pre {
70 | margin: 0;
71 | padding: 12px 12px;
72 | background: rgba(238, 238, 238, 0.35);
73 | border-radius: 3px;
74 | font-size: 13px;
75 | line-height: 1.5em;
76 | font-weight: 500;
77 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.125);
78 | }
79 |
80 | .dark body {
81 | color: #fafafa;
82 | }
83 | .dark .content h1,
84 | .dark .content h2,
85 | .dark .content h3,
86 | .dark .content h4,
87 | .dark .content h5 {
88 | color: #fafafa;
89 | }
90 |
91 | .dark code {
92 | background: none;
93 | }
94 |
95 | .dark .content {
96 | color: #fafafa;
97 | }
98 |
99 | .dark .menu ul.list li a[data-type='chapter-link'],
100 | .dark .menu ul.list li.chapter .simple {
101 | color: #fafafa;
102 | }
103 |
104 | .dark .menu ul.list li.title a {
105 | color: #fafafa;
106 | }
107 |
108 | .dark .menu ul.list li a {
109 | color: #fafafa;
110 | }
111 | .dark .menu ul.list li a.active {
112 | color: #7fc9ff;
113 | }
114 |
--------------------------------------------------------------------------------
/docs/api/styles/material.css:
--------------------------------------------------------------------------------
1 | .menu {
2 | background: none;
3 | }
4 |
5 | a:hover {
6 | text-decoration: none;
7 | }
8 |
9 | /** LINK **/
10 |
11 | .menu ul.list li a {
12 | text-decoration: none;
13 | }
14 |
15 | .menu ul.list li a:hover,
16 | .menu ul.list li.chapter .simple:hover {
17 | background-color: #f8f9fa;
18 | text-decoration: none;
19 | }
20 |
21 | #book-search-input {
22 | margin-bottom: 0;
23 | }
24 |
25 | .menu ul.list li.divider {
26 | margin-top: 0;
27 | background: #e9ecef;
28 | }
29 |
30 | .menu .title:hover {
31 | background-color: #f8f9fa;
32 | }
33 |
34 | /** CARD **/
35 |
36 | .card {
37 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2),
38 | 0 1px 5px 0 rgba(0, 0, 0, 0.12);
39 | border-radius: 0.125rem;
40 | border: 0;
41 | margin-top: 1px;
42 | }
43 |
44 | .card-header {
45 | background: none;
46 | }
47 |
48 | /** BUTTON **/
49 |
50 | .btn {
51 | border-radius: 0.125rem;
52 | }
53 |
54 | /** NAV BAR **/
55 |
56 | .nav {
57 | border: 0;
58 | }
59 | .nav-tabs > li > a {
60 | border: 0;
61 | border-bottom: 0.214rem solid transparent;
62 | color: rgba(0, 0, 0, 0.54);
63 | margin-right: 0;
64 | }
65 | .nav-tabs > li.active > a,
66 | .nav-tabs > li.active > a:focus,
67 | .nav-tabs > li.active > a:hover {
68 | color: rgba(0, 0, 0, 0.87);
69 | border-top: 0;
70 | border-left: 0;
71 | border-right: 0;
72 | border-bottom: 0.214rem solid transparent;
73 | border-color: #008cff;
74 | font-weight: bold;
75 | }
76 | .nav > li > a:focus,
77 | .nav > li > a:hover {
78 | background: none;
79 | }
80 |
81 | /** LIST **/
82 |
83 | .list-group-item:first-child {
84 | border-top-left-radius: 0.125rem;
85 | border-top-right-radius: 0.125rem;
86 | }
87 | .list-group-item:last-child {
88 | border-bottom-left-radius: 0.125rem;
89 | border-bottom-right-radius: 0.125rem;
90 | }
91 |
92 | /** MISC **/
93 |
94 | .modifier {
95 | border-radius: 0.125rem;
96 | }
97 |
98 | pre[class*='language-'] {
99 | border-radius: 0.125rem;
100 | }
101 |
102 | /** TABLE **/
103 |
104 | .table-hover > tbody > tr:hover {
105 | background: rgba(0, 0, 0, 0.075);
106 | }
107 |
108 | table.params thead {
109 | background: none;
110 | }
111 | table.params thead td {
112 | color: rgba(0, 0, 0, 0.54);
113 | font-weight: bold;
114 | }
115 |
116 | .dark .menu .title:hover {
117 | background-color: #2d2d2d;
118 | }
119 | .dark .menu ul.list li a:hover,
120 | .dark .menu ul.list li.chapter .simple:hover {
121 | background-color: #2d2d2d;
122 | }
123 | .dark .nav-tabs > li:not(.active) > a {
124 | color: #fafafa;
125 | }
126 | .dark table.params thead {
127 | background: #484848;
128 | }
129 | .dark table.params thead td {
130 | color: #fafafa;
131 | }
132 |
--------------------------------------------------------------------------------
/docs/api/styles/original.css:
--------------------------------------------------------------------------------
1 | .navbar-default .navbar-brand,
2 | .menu ul.list li.title {
3 | font-weight: bold;
4 | color: #3c3c3c;
5 | padding-bottom: 5px;
6 | }
7 |
8 | .menu ul.list li a[data-type='chapter-link'],
9 | .menu ul.list li.chapter .simple {
10 | font-weight: bold;
11 | font-size: 14px;
12 | }
13 |
14 | .menu ul.list li a[href='./routes.html'] {
15 | border-bottom: none;
16 | }
17 |
18 | .menu ul.list > li:nth-child(2) {
19 | display: none;
20 | }
21 |
22 | .menu ul.list li.chapter ul.links {
23 | background: #fff;
24 | padding-left: 0;
25 | }
26 |
27 | .menu ul.list li.chapter ul.links li {
28 | border-bottom: 1px solid #ddd;
29 | padding-left: 20px;
30 | }
31 |
32 | .menu ul.list li.chapter ul.links li:last-child {
33 | border-bottom: none;
34 | }
35 |
36 | .menu ul.list li a.active {
37 | color: #337ab7;
38 | font-weight: bold;
39 | }
40 |
41 | #book-search-input {
42 | margin-bottom: 0;
43 | border-bottom: none;
44 | }
45 | .menu ul.list li.divider {
46 | margin: 0;
47 | }
48 |
49 | .dark .menu ul.list li.chapter ul.links {
50 | background: none;
51 | }
52 |
--------------------------------------------------------------------------------
/docs/api/styles/readthedocs.css:
--------------------------------------------------------------------------------
1 | .navbar-default {
2 | background: #2980b9;
3 | border: none;
4 | }
5 |
6 | .navbar-default .navbar-brand {
7 | color: #fcfcfc;
8 | }
9 |
10 | .menu {
11 | background: #343131;
12 | color: #fcfcfc;
13 | }
14 |
15 | .menu ul.list li a {
16 | color: #fcfcfc;
17 | }
18 |
19 | .menu ul.list li.title {
20 | background: #2980b9;
21 | padding-bottom: 5px;
22 | }
23 |
24 | .menu ul.list li:nth-child(2) {
25 | margin-top: 0;
26 | }
27 |
28 | .menu ul.list li.chapter a,
29 | .menu ul.list li.chapter .simple {
30 | color: #555;
31 | text-transform: uppercase;
32 | text-decoration: none;
33 | }
34 |
35 | .menu ul.list li.chapter ul.links a {
36 | color: #b3b3b3;
37 | text-transform: none;
38 | padding-left: 35px;
39 | }
40 |
41 | .menu ul.list li.chapter ul.links a:hover {
42 | background: #4e4a4a;
43 | }
44 |
45 | .menu ul.list li.chapter a.active,
46 | .menu ul.list li.chapter ul.links a.active {
47 | color: #0099e5;
48 | }
49 |
50 | .menu ul.list li.chapter ul.links {
51 | padding-left: 0;
52 | }
53 |
54 | .menu ul.list li.divider {
55 | background: rgba(255, 255, 255, 0.07);
56 | }
57 |
58 | #book-search-input input,
59 | #book-search-input input:focus,
60 | #book-search-input input:hover {
61 | color: #949494;
62 | }
63 |
64 | .copyright {
65 | color: #b3b3b3;
66 | background: #272525;
67 | }
68 |
69 | .content {
70 | background: #fcfcfc;
71 | }
72 |
73 | .content a {
74 | color: #2980b9;
75 | }
76 |
77 | .content a:hover {
78 | color: #3091d1;
79 | }
80 |
81 | .content a:visited {
82 | color: #9b59b6;
83 | }
84 |
85 | .menu ul.list li:nth-last-child(2) {
86 | background: none;
87 | }
88 |
89 | code {
90 | white-space: nowrap;
91 | max-width: 100%;
92 | background: #fff;
93 | padding: 2px 5px;
94 | color: #e74c3c;
95 | overflow-x: auto;
96 | border-radius: 0;
97 | }
98 |
99 | pre {
100 | white-space: pre;
101 | margin: 0;
102 | padding: 12px 12px;
103 | font-size: 12px;
104 | line-height: 1.5;
105 | display: block;
106 | overflow: auto;
107 | color: #404040;
108 | background: rgba(238, 238, 238, 0.35);
109 | }
110 |
111 | .dark .content {
112 | background: none;
113 | }
114 | .dark code {
115 | background: none;
116 | color: #e09393;
117 | }
118 |
--------------------------------------------------------------------------------
/docs/api/styles/reset.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html,
7 | body,
8 | div,
9 | span,
10 | applet,
11 | object,
12 | iframe,
13 | h1,
14 | h2,
15 | h3,
16 | h4,
17 | h5,
18 | h6,
19 | p,
20 | blockquote,
21 | pre,
22 | a,
23 | abbr,
24 | acronym,
25 | address,
26 | big,
27 | cite,
28 | code,
29 | del,
30 | dfn,
31 | em,
32 | img,
33 | ins,
34 | kbd,
35 | q,
36 | s,
37 | samp,
38 | small,
39 | strike,
40 | strong,
41 | sub,
42 | sup,
43 | tt,
44 | var,
45 | b,
46 | u,
47 | i,
48 | center,
49 | dl,
50 | dt,
51 | dd,
52 | ol,
53 | ul,
54 | li,
55 | fieldset,
56 | form,
57 | label,
58 | legend,
59 | table,
60 | caption,
61 | tbody,
62 | tfoot,
63 | thead,
64 | tr,
65 | th,
66 | td,
67 | article,
68 | aside,
69 | canvas,
70 | details,
71 | embed,
72 | figure,
73 | figcaption,
74 | footer,
75 | header,
76 | hgroup,
77 | menu,
78 | nav,
79 | output,
80 | ruby,
81 | section,
82 | summary,
83 | time,
84 | mark,
85 | audio,
86 | video {
87 | margin: 0;
88 | padding: 0;
89 | border: 0;
90 | font: inherit;
91 | font-size: 100%;
92 | vertical-align: baseline;
93 | }
94 | /* HTML5 display-role reset for older browsers */
95 | article,
96 | aside,
97 | details,
98 | figcaption,
99 | figure,
100 | footer,
101 | header,
102 | hgroup,
103 | menu,
104 | nav,
105 | section {
106 | display: block;
107 | }
108 | body {
109 | line-height: 1;
110 | }
111 | ol,
112 | ul {
113 | list-style: none;
114 | }
115 | blockquote,
116 | q {
117 | quotes: none;
118 | }
119 | blockquote:before,
120 | blockquote:after,
121 | q:before,
122 | q:after {
123 | content: '';
124 | content: none;
125 | }
126 | table {
127 | border-collapse: collapse;
128 | border-spacing: 0;
129 | }
130 |
--------------------------------------------------------------------------------
/docs/api/styles/stripe.css:
--------------------------------------------------------------------------------
1 | .navbar-default .navbar-brand {
2 | color: #0099e5;
3 | }
4 |
5 | .menu ul.list li a[data-type='chapter-link'],
6 | .menu ul.list li.chapter .simple {
7 | color: #939da3;
8 | text-transform: uppercase;
9 | }
10 |
11 | .content h1,
12 | .content h2,
13 | .content h3,
14 | .content h4,
15 | .content h5 {
16 | color: #292e31;
17 | font-weight: normal;
18 | }
19 |
20 | .content {
21 | color: #4c555a;
22 | }
23 |
24 | .menu ul.list li.title {
25 | padding: 5px 0;
26 | }
27 |
28 | a {
29 | color: #0099e5;
30 | text-decoration: none;
31 | }
32 | a:hover {
33 | color: #292e31;
34 | text-decoration: none;
35 | }
36 |
37 | .menu ul.list li:nth-child(2) {
38 | margin-top: 0;
39 | }
40 |
41 | .menu ul.list li.title a,
42 | .navbar a {
43 | color: #0099e5;
44 | text-decoration: none;
45 | font-size: 16px;
46 | }
47 |
48 | .menu ul.list li a.active {
49 | color: #0099e5;
50 | }
51 |
52 | code {
53 | box-sizing: border-box;
54 | display: inline-block;
55 | padding: 0 5px;
56 | background: #fafcfc;
57 | border-radius: 4px;
58 | color: #b93d6a;
59 | font-size: 13px;
60 | line-height: 20px;
61 | }
62 |
63 | pre {
64 | margin: 0;
65 | padding: 12px 12px;
66 | background: #272b2d;
67 | border-radius: 5px;
68 | font-size: 13px;
69 | line-height: 1.5em;
70 | font-weight: 500;
71 | }
72 |
73 | .dark body {
74 | color: #fafafa;
75 | }
76 | .dark .content h1,
77 | .dark .content h2,
78 | .dark .content h3,
79 | .dark .content h4,
80 | .dark .content h5 {
81 | color: #fafafa;
82 | }
83 |
84 | .dark code {
85 | background: none;
86 | }
87 |
88 | .dark .content {
89 | color: #fafafa;
90 | }
91 |
92 | .dark .menu ul.list li a[data-type='chapter-link'],
93 | .dark .menu ul.list li.chapter .simple {
94 | color: #fafafa;
95 | }
96 |
97 | .dark .menu ul.list li.title a {
98 | color: #fafafa;
99 | }
100 |
101 | .dark .menu ul.list li a {
102 | color: #fafafa;
103 | }
104 | .dark .menu ul.list li a.active {
105 | color: #7fc9ff;
106 | }
107 |
--------------------------------------------------------------------------------
/docs/api/styles/style.css:
--------------------------------------------------------------------------------
1 | @import "./reset.css";
2 | @import "./bootstrap.min.css";
3 | @import "./bootstrap-card.css";
4 | @import "./prism.css";
5 | @import "./ionicons.min.css";
6 | @import "./compodoc.css";
7 | @import "./tablesort.css";
8 |
--------------------------------------------------------------------------------
/docs/api/styles/tablesort.css:
--------------------------------------------------------------------------------
1 | th[role=columnheader]:not(.no-sort) {
2 | cursor: pointer;
3 | }
4 |
5 | th[role=columnheader]:not(.no-sort):after {
6 | content: '';
7 | float: right;
8 | margin-top: 7px;
9 | border-width: 0 4px 4px;
10 | border-style: solid;
11 | border-color: #404040 transparent;
12 | visibility: visible;
13 | opacity: 1;
14 | -ms-user-select: none;
15 | -webkit-user-select: none;
16 | -moz-user-select: none;
17 | user-select: none;
18 | }
19 |
20 | th[aria-sort=ascending]:not(.no-sort):after {
21 | border-bottom: none;
22 | border-width: 4px 4px 0;
23 | }
24 |
25 | th[aria-sort]:not(.no-sort):after {
26 | visibility: visible;
27 | opacity: 0.4;
28 | }
29 |
30 | th[role=columnheader]:not(.no-sort):hover:after {
31 | visibility: visible;
32 | opacity: 1;
33 | }
34 |
--------------------------------------------------------------------------------
/docs/api/styles/vagrant.css:
--------------------------------------------------------------------------------
1 | .navbar-default .navbar-brand {
2 | background: white;
3 | color: #8d9ba8;
4 | }
5 |
6 | .menu .list {
7 | background: #0c5593;
8 | }
9 |
10 | .menu .chapter {
11 | padding: 0 20px;
12 | }
13 |
14 | .menu ul.list li a[data-type='chapter-link'],
15 | .menu ul.list li.chapter .simple {
16 | color: white;
17 | text-transform: uppercase;
18 | border-bottom: 1px solid rgba(255, 255, 255, 0.4);
19 | }
20 |
21 | .content h1,
22 | .content h2,
23 | .content h3,
24 | .content h4,
25 | .content h5 {
26 | color: #292e31;
27 | font-weight: normal;
28 | }
29 |
30 | .content {
31 | color: #4c555a;
32 | }
33 |
34 | a {
35 | color: #0094bf;
36 | text-decoration: underline;
37 | }
38 | a:hover {
39 | color: #f1362f;
40 | }
41 |
42 | .menu ul.list li.title {
43 | background: white;
44 | padding-bottom: 5px;
45 | }
46 |
47 | .menu ul.list li:nth-child(2) {
48 | margin-top: 0;
49 | }
50 |
51 | .menu ul.list li:nth-last-child(2) {
52 | background: none;
53 | }
54 |
55 | .menu ul.list li.title a {
56 | padding: 10px 15px;
57 | }
58 |
59 | .menu ul.list li.title a,
60 | .navbar a {
61 | color: #8d9ba8;
62 | text-decoration: none;
63 | font-size: 16px;
64 | font-weight: 300;
65 | }
66 |
67 | .menu ul.list li a {
68 | color: white;
69 | padding: 10px;
70 | font-weight: 300;
71 | text-decoration: none;
72 | }
73 | .menu ul.list li a.active {
74 | color: white;
75 | font-weight: bold;
76 | }
77 |
78 | .copyright {
79 | color: white;
80 | background: #000;
81 | }
82 |
83 | code {
84 | box-sizing: border-box;
85 | display: inline-block;
86 | padding: 0 5px;
87 | background: rgba(0, 148, 191, 0.1);
88 | border-radius: 3px;
89 | color: #0094bf;
90 | font-size: 13px;
91 | line-height: 20px;
92 | }
93 |
94 | pre {
95 | margin: 0;
96 | padding: 12px 12px;
97 | background: rgba(238, 238, 238, 0.35);
98 | border-radius: 3px;
99 | font-size: 13px;
100 | line-height: 1.5em;
101 | font-weight: 500;
102 | }
103 |
104 | .dark body {
105 | color: #fafafa;
106 | }
107 | .dark .content h1,
108 | .dark .content h2,
109 | .dark .content h3,
110 | .dark .content h4,
111 | .dark .content h5 {
112 | color: #fafafa;
113 | }
114 |
115 | .dark code {
116 | background: none;
117 | }
118 |
119 | .dark .content {
120 | color: #fafafa;
121 | }
122 |
123 | .dark .menu ul.list li.title a,
124 | .dark .navbar a {
125 | color: #8d9ba8;
126 | }
127 |
128 | .dark .menu ul.list li a {
129 | color: #fafafa;
130 | }
131 |
--------------------------------------------------------------------------------
/docs/apigentool.md:
--------------------------------------------------------------------------------
1 | # OData API Generator
2 |
3 | Please check also my other related project, [OData Angular Generator](https://github.com/diegomvh/ODataApiGen)
4 |
--------------------------------------------------------------------------------
/docs/models.md:
--------------------------------------------------------------------------------
1 | # Models and Collections
2 |
3 | Essentially, the goal is to encapsulate entities with behavior within structures known as models, and to group sets of these entities with behavior into structures called collections.
4 |
5 | If you're familiar with Backbone.js, you'll notice that much of the inspiration for this approach comes from there.
--------------------------------------------------------------------------------
/docs/queries.md:
--------------------------------------------------------------------------------
1 | # Queries
2 |
3 | ## Query Builder
4 |
5 | For a deep query customizations the library use `odata-query` and `odata-filter-builder` as a builders.
6 |
7 | - [OData v4 query builder](https://github.com/techniq/odata-query)
8 | - [OData Filter Builder](https://github.com/bodia-uz/odata-filter-builder)
9 |
--------------------------------------------------------------------------------
/docs/schema.md:
--------------------------------------------------------------------------------
1 | # Schema
2 |
3 | Use [OData Angular Generator](https://github.com/diegomvh/ODataApiGen) for generate the \Config and the \Module definition.
4 |
5 | Import ODataModule, \Config and \Module into your application module.
6 | Setup ODataModule with \Config and import it along with \Module.
7 |
8 | ```typescript
9 | import { NgModule } from '@angular/core';
10 |
11 | import { ODataModule } from 'angular-odata';
12 | import { TripPinConfig, TripPinModule } from './trippin';
13 |
14 | @NgModule({
15 | imports: [
16 | ...
17 | ODataModule.forRoot({ config: TripPinConfig }),
18 | TripPinModule
19 | ]
20 | ...
21 | })
22 | export class AppModule {}
23 | ```
24 |
--------------------------------------------------------------------------------
/docs/schematics.md:
--------------------------------------------------------------------------------
1 | # Schematics
2 |
3 | The angular-odata library includes schematics that allow generating TypeScript code from OData metadata.
4 | By using the ng generate command along with the appropriate parameters, it is possible to create a module that defines all the types specified in the OData metadata document.
5 | These types are mapped to their TypeScript equivalents as follows:
6 |
7 | **EdmTypes**: mapped to the corresponding primitive types in TypeScript, such as string, number, boolean, etc.
8 |
9 | **EnumType**: converted to a TypeScript enum.
10 |
11 | **EntityType and ComplexType**: converted to TypeScript interfaces.
12 |
13 | **EntitySets**: converted to Angular services.
14 |
15 | **Functions**: added to the generated services.
16 |
17 | **Actions**: added to the generated services.
18 |
19 |
20 | ```bash
21 | ng generate angular-odata:apigen --name=TripPin --metadata=https://services.odata.org/V4/TripPinServiceRW/\$metadata
22 |
23 | ```
24 |
25 |
26 | ```json
27 | {
28 | "compilerOptions": {
29 | "resolveJsonModule": true
30 | }
31 | }
32 | ```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-odata",
3 | "version": "0.130.0",
4 | "license": "MIT",
5 | "description": "Client side OData typescript library for Angular",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/diegomvh/angular-odata.git"
9 | },
10 | "keywords": [
11 | "client",
12 | "odata",
13 | "odata v4",
14 | "odata v3",
15 | "odata v2",
16 | "typescript",
17 | "api",
18 | "@angular",
19 | "angular"
20 | ],
21 | "author": "Diego van Haaster",
22 | "bugs": {
23 | "url": "https://github.com/diegomvh/angular-odata/issues"
24 | },
25 | "homepage": "https://github.com/diegomvh/angular-odata",
26 | "private": false,
27 | "scripts": {
28 | "ng": "ng",
29 | "start": "ng serve",
30 | "build": "ng test angular-odata && ng build angular-odata --configuration production",
31 | "schematics": "cd projects/angular-odata && npm run build && npm run postbuild",
32 | "link": "npm link angular-odata",
33 | "test": "ng test",
34 | "watch": "ng build --watch --configuration development",
35 | "docs": "compodoc -p projects/angular-odata/tsconfig.lib.json -d docs/api --disableGraph --disableCoverage",
36 | "versioning": "npm version 0.130.0 --allow-same-version && cd projects/angular-odata && npm version 0.130.0 --allow-same-version && cd ../..",
37 | "publish": "npm run build && npm run schematics && npm publish dist/angular-odata/",
38 | "release": "cp README.md projects/angular-odata/README.md && npm run docs && npm run publish",
39 | "prettier": "prettier --write \"projects/angular-odata/**/*.ts\""
40 | },
41 | "dependencies": {
42 | "@angular/common": "^19.2.0",
43 | "@angular/compiler": "^19.2.0",
44 | "@angular/core": "^19.2.0",
45 | "@angular/forms": "^19.2.0",
46 | "@angular/platform-browser": "^19.2.0",
47 | "@angular/platform-browser-dynamic": "^19.2.0",
48 | "@angular/router": "^19.2.0",
49 | "rxjs": "~7.8.0",
50 | "tslib": "^2.3.0",
51 | "zone.js": "~0.15.0"
52 | },
53 | "devDependencies": {
54 | "@angular-devkit/build-angular": "^19.2.13",
55 | "@angular/cli": "^19.2.13",
56 | "@angular/compiler-cli": "^19.2.0",
57 | "@compodoc/compodoc": "^1.1.26",
58 | "@types/jasmine": "~5.1.0",
59 | "@types/jsdom": "^21.1.7",
60 | "jasmine-core": "~5.6.0",
61 | "jsdom": "^26.1.0",
62 | "karma": "~6.4.0",
63 | "karma-chrome-launcher": "~3.2.0",
64 | "karma-coverage": "~2.2.0",
65 | "karma-jasmine": "~5.1.0",
66 | "karma-jasmine-html-reporter": "~2.1.0",
67 | "ng-packagr": "^19.2.0",
68 | "prettier": "^3.5.3",
69 | "typescript": "~5.7.2"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/projects/angular-odata/README.md:
--------------------------------------------------------------------------------
1 | # AngularOdata
2 |
3 | This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.0.
4 |
5 | ## Code scaffolding
6 |
7 | Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
8 |
9 | ```bash
10 | ng generate component component-name
11 | ```
12 |
13 | For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
14 |
15 | ```bash
16 | ng generate --help
17 | ```
18 |
19 | ## Building
20 |
21 | To build the library, run:
22 |
23 | ```bash
24 | ng build angular-odata
25 | ```
26 |
27 | This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
28 |
29 | ### Publishing the Library
30 |
31 | Once the project is built, you can publish your library by following these steps:
32 |
33 | 1. Navigate to the `dist` directory:
34 | ```bash
35 | cd dist/angular-odata
36 | ```
37 |
38 | 2. Run the `npm publish` command to publish your library to the npm registry:
39 | ```bash
40 | npm publish
41 | ```
42 |
43 | ## Running unit tests
44 |
45 | To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
46 |
47 | ```bash
48 | ng test
49 | ```
50 |
51 | ## Running end-to-end tests
52 |
53 | For end-to-end (e2e) testing, run:
54 |
55 | ```bash
56 | ng e2e
57 | ```
58 |
59 | Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
60 |
61 | ## Additional Resources
62 |
63 | For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
64 |
--------------------------------------------------------------------------------
/projects/angular-odata/karma.config.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | jasmine: {
17 | // you can add configuration options for Jasmine here
18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
19 | // for example, you can disable the random execution with `random: false`
20 | // or set a specific seed with `seed: 4321`
21 | },
22 | clearContext: false // leave Jasmine Spec Runner output visible in browser
23 | },
24 | jasmineHtmlReporter: {
25 | suppressAll: true // removes the duplicated traces
26 | },
27 | coverageReporter: {
28 | dir: require('path').join(__dirname, '../../coverage/angular-odata'),
29 | subdir: '.',
30 | reporters: [
31 | { type: 'html' },
32 | { type: 'text-summary' }
33 | ]
34 | },
35 | reporters: ['progress', 'kjhtml'],
36 | port: 9876,
37 | colors: true,
38 | logLevel: config.LOG_INFO,
39 | autoWatch: true,
40 | browsers: ['ChromeHeadless'],
41 | singleRun: true,
42 | restartOnFileChange: true
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/projects/angular-odata/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../../dist/angular-odata",
4 | "lib": {
5 | "entryFile": "src/public-api.ts"
6 | }
7 | }
--------------------------------------------------------------------------------
/projects/angular-odata/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-odata",
3 | "version": "0.130.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "angular-odata",
9 | "version": "0.130.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "tslib": "^2.3.0"
13 | },
14 | "peerDependencies": {
15 | "@angular/common": ">=16.0.0",
16 | "@angular/core": ">=16.0.0"
17 | }
18 | },
19 | "node_modules/@angular/common": {
20 | "version": "19.2.13",
21 | "resolved": "https://registry.npmjs.org/@angular/common/-/common-19.2.13.tgz",
22 | "integrity": "sha512-k7I4bLH+bgI02VL81MaL0NcZPfVl153KAiARwk+ZlkmQjMnWlmsAHQ6054SWoNEXwP855ATR6YYDVqJh8TZaqw==",
23 | "license": "MIT",
24 | "peer": true,
25 | "dependencies": {
26 | "tslib": "^2.3.0"
27 | },
28 | "engines": {
29 | "node": "^18.19.1 || ^20.11.1 || >=22.0.0"
30 | },
31 | "peerDependencies": {
32 | "@angular/core": "19.2.13",
33 | "rxjs": "^6.5.3 || ^7.4.0"
34 | }
35 | },
36 | "node_modules/@angular/core": {
37 | "version": "19.2.13",
38 | "resolved": "https://registry.npmjs.org/@angular/core/-/core-19.2.13.tgz",
39 | "integrity": "sha512-HpzDI3TSQzVV2mmQ8KwH0JSLNlYNemNrEo3L3hcqqYwTzqFgAK4y1Q2Xym3yiRSLTenYhW5D4CQqOHUQ26HxwQ==",
40 | "license": "MIT",
41 | "peer": true,
42 | "dependencies": {
43 | "tslib": "^2.3.0"
44 | },
45 | "engines": {
46 | "node": "^18.19.1 || ^20.11.1 || >=22.0.0"
47 | },
48 | "peerDependencies": {
49 | "rxjs": "^6.5.3 || ^7.4.0",
50 | "zone.js": "~0.15.0"
51 | }
52 | },
53 | "node_modules/rxjs": {
54 | "version": "7.8.2",
55 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
56 | "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
57 | "license": "Apache-2.0",
58 | "peer": true,
59 | "dependencies": {
60 | "tslib": "^2.1.0"
61 | }
62 | },
63 | "node_modules/tslib": {
64 | "version": "2.8.1",
65 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
66 | "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
67 | "license": "0BSD"
68 | },
69 | "node_modules/zone.js": {
70 | "version": "0.15.1",
71 | "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz",
72 | "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==",
73 | "license": "MIT",
74 | "peer": true
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/projects/angular-odata/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-odata",
3 | "version": "0.130.0",
4 | "license": "MIT",
5 | "description": "Client side OData typescript library for Angular",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/diegomvh/angular-odata.git"
9 | },
10 | "keywords": [
11 | "client",
12 | "odata",
13 | "odata v4",
14 | "odata v3",
15 | "odata v2",
16 | "typescript",
17 | "api",
18 | "@angular",
19 | "angular"
20 | ],
21 | "author": "Diego van Haaster",
22 | "bugs": {
23 | "url": "https://github.com/diegomvh/angular-odata/issues"
24 | },
25 | "homepage": "https://github.com/diegomvh/angular-odata",
26 | "private": false,
27 | "scripts": {
28 | "build": "../../node_modules/.bin/tsc -p tsconfig.schematics.json",
29 | "copy:schemas": "cp --parents schematics/*/schema.json ../../dist/angular-odata/",
30 | "copy:files": "cp --parents -p schematics/*/files/**/* ../../dist/angular-odata/",
31 | "copy:collection": "cp schematics/collection.json ../../dist/angular-odata/schematics/collection.json",
32 | "postbuild": "npm run copy:schemas && npm run copy:files && npm run copy:collection"
33 | },
34 | "peerDependencies": {
35 | "@angular/common": ">=16.0.0",
36 | "@angular/core": ">=16.0.0"
37 | },
38 | "schematics": "./schematics/collection.json",
39 | "ng-add": {
40 | "save": "dependencies"
41 | },
42 | "dependencies": {
43 | "tslib": "^2.3.0"
44 | },
45 | "sideEffects": false
46 | }
47 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/angular/api-config.ts:
--------------------------------------------------------------------------------
1 | import { strings } from '@angular-devkit/core';
2 | import { Base } from './base';
3 | import { url, Source } from '@angular-devkit/schematics';
4 | import { Schema as ApiGenSchema } from '../schema';
5 |
6 | export class ApiConfig extends Base {
7 | constructor(options: ApiGenSchema) {
8 | super(options);
9 | }
10 | public override template(): Source {
11 | return url('./files/api-config');
12 | }
13 | public override variables(): { [name: string]: any } {
14 | return {
15 | serviceRootUrl: this.options.serviceRootUrl,
16 | metadataUrl: this.options.metadata,
17 | apiConfigName: this.options.name,
18 | version: this.options.version,
19 | creation: this.options.creation,
20 | };
21 | }
22 | public override name() {
23 | return strings.classify(this.options.name) + 'Config';
24 | }
25 | public override fileName() {
26 | return strings.dasherize(this.options.name) + '.config';
27 | }
28 | public override directory() {
29 | return '';
30 | }
31 | public override fullName() {
32 | return this.name();
33 | }
34 | public override importTypes(): string[] {
35 | return [];
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/angular/entity.ts:
--------------------------------------------------------------------------------
1 | import { strings } from '@angular-devkit/core';
2 | import { Base } from './base';
3 | import {
4 | CsdlComplexType,
5 | CsdlEntityType,
6 | } from '../metadata/csdl/csdl-structured-type';
7 | import { url, Source } from '@angular-devkit/schematics';
8 | import { Schema as ApiGenSchema } from '../schema';
9 | import {
10 | CsdlNavigationProperty,
11 | CsdlProperty,
12 | } from '../metadata/csdl/csdl-structural-property';
13 | import { toTypescriptType } from '../utils';
14 |
15 | export class EntityProperty {
16 | constructor(protected edmType: CsdlProperty | CsdlNavigationProperty) {}
17 |
18 | name() {
19 | return this.edmType.Name;
20 | }
21 |
22 | type() {
23 | let type = toTypescriptType(this.edmType.Type);
24 | type += this.edmType.Collection ? '[]' : '';
25 | type += this.edmType.Nullable ? ' | null' : '';
26 | return type;
27 | }
28 | }
29 |
30 | export class Entity extends Base {
31 | constructor(
32 | options: ApiGenSchema,
33 | protected edmType: CsdlEntityType | CsdlComplexType,
34 | ) {
35 | super(options);
36 | }
37 |
38 | public override template(): Source {
39 | return url('./files/entity');
40 | }
41 | public override variables(): { [name: string]: any } {
42 | return {
43 | type:
44 | this.name() +
45 | (this.edmType instanceof CsdlEntityType ? 'EntityType' : 'ComplexType'),
46 | baseType: this.edmType.BaseType,
47 | properties: [
48 | ...(this.edmType.Property ?? []).map((p) => new EntityProperty(p)),
49 | ...(this.edmType.NavigationProperty ?? []).map(
50 | (p) => new EntityProperty(p),
51 | ),
52 | ],
53 | };
54 | }
55 | public override name() {
56 | return strings.classify(this.edmType.name());
57 | }
58 | public override fileName() {
59 | return (
60 | strings.dasherize(this.edmType.name()) +
61 | (this.edmType instanceof CsdlEntityType ? '.entity' : '.complex')
62 | );
63 | }
64 | public override directory() {
65 | return this.edmType.namespace().replace(/\./g, '/');
66 | }
67 | public override fullName() {
68 | return this.edmType.fullName();
69 | }
70 | public override importTypes(): string[] {
71 | const imports = [];
72 | if (this.edmType.BaseType) {
73 | imports.push(this.edmType.BaseType);
74 | }
75 | for (let prop of this.edmType?.Property ?? []) {
76 | if (!prop.Type.startsWith('Edm.')) {
77 | imports.push(prop.Type);
78 | }
79 | }
80 | for (let prop of this.edmType?.NavigationProperty ?? []) {
81 | if (!prop.Type.startsWith('Edm.')) {
82 | imports.push(prop.Type);
83 | }
84 | }
85 | return imports;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/angular/enum.ts:
--------------------------------------------------------------------------------
1 | import { CsdlEnumType, CsdlMember } from '../metadata/csdl/csdl-enum-type';
2 | import { strings } from '@angular-devkit/core';
3 | import { Base } from './base';
4 | import { Import } from './import';
5 | import { url, Source } from '@angular-devkit/schematics';
6 | import { Schema as ApiGenSchema } from '../schema';
7 |
8 | export class EnumValue {
9 | constructor(private edmType: CsdlMember) {}
10 | public name() {
11 | return this.edmType.Name;
12 | }
13 | public value() {
14 | return this.edmType.Value;
15 | }
16 | }
17 | export class Enum extends Base {
18 | constructor(
19 | options: ApiGenSchema,
20 | protected edmType: CsdlEnumType,
21 | ) {
22 | super(options);
23 | }
24 | public override template(): Source {
25 | return url('./files/enum');
26 | }
27 | public override variables(): { [name: string]: any } {
28 | return {
29 | type: this.name() + 'EnumType',
30 | values: (this.edmType.Member ?? []).map((m) => new EnumValue(m)),
31 | };
32 | }
33 | public override name() {
34 | return strings.classify(this.edmType.name());
35 | }
36 | public override fileName() {
37 | return strings.dasherize(this.edmType.name()) + '.enum';
38 | }
39 | public override directory() {
40 | return this.edmType.namespace().replace(/\./g, '/');
41 | }
42 | public override fullName() {
43 | return this.edmType.fullName();
44 | }
45 | public members() {
46 | return this.edmType.Member.map((m) => `${m.Name} = ${m.Value}`);
47 | }
48 | public flags() {
49 | return this.edmType.IsFlags;
50 | }
51 | public override importTypes(): string[] {
52 | return [];
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/angular/import.ts:
--------------------------------------------------------------------------------
1 | export class Import {
2 | public names: string[] = [];
3 | public from: string;
4 | public constructor(names: string[], from: string) {
5 | this.names = names;
6 | this.from = from;
7 | }
8 |
9 | public path(): string {
10 | var path = this.from.toString();
11 | if (!path.startsWith('../')) path = `./${path}`;
12 | return path;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/angular/module.ts:
--------------------------------------------------------------------------------
1 | import { strings } from '@angular-devkit/core';
2 | import { Base } from './base';
3 | import { url, Source } from '@angular-devkit/schematics';
4 | import { Schema as ApiGenSchema } from '../schema';
5 | import { Service } from './service';
6 |
7 | export class Module extends Base {
8 | services: Service[] = [];
9 | constructor(options: ApiGenSchema) {
10 | super(options);
11 | }
12 | public override template(): Source {
13 | return url('./files/module');
14 | }
15 | public override variables(): { [name: string]: any } {
16 | return {
17 | services: this.services,
18 | };
19 | }
20 | public addService(service: Service) {
21 | this.services.push(service);
22 | this.addDependency(service);
23 | }
24 | public override name() {
25 | return strings.classify(this.options.name) + 'Module';
26 | }
27 | public override fileName() {
28 | return strings.dasherize(this.options.name) + '.module';
29 | }
30 | public override directory() {
31 | return '';
32 | }
33 | public override fullName() {
34 | return this.name();
35 | }
36 | public override importTypes(): string[] {
37 | return [];
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/angular/service.ts:
--------------------------------------------------------------------------------
1 | import { strings } from '@angular-devkit/core';
2 | import { Base } from './base';
3 | import { CsdlEntityContainer } from '../metadata/csdl/csdl-entity-container';
4 | import { CsdlSingleton } from '../metadata/csdl/csdl-singleton';
5 | import { CsdlEntitySet } from '../metadata/csdl/csdl-entity-set';
6 | import { url, Source } from '@angular-devkit/schematics';
7 | import { Schema as ApiGenSchema } from '../schema';
8 |
9 | export class Service extends Base {
10 | constructor(
11 | options: ApiGenSchema,
12 | protected edmElement: CsdlEntitySet | CsdlEntityContainer | CsdlSingleton,
13 | ) {
14 | super(options);
15 | }
16 | public override template(): Source {
17 | return this.edmElement instanceof CsdlEntitySet
18 | ? url('./files/entityset-service')
19 | : this.edmElement instanceof CsdlSingleton
20 | ? url('./files/singleton-service')
21 | : url('./files/entitycontainer-service');
22 | }
23 | public override variables(): { [name: string]: any } {
24 | return {
25 | path: this.edmElement.name(),
26 | type:
27 | this.edmElement instanceof CsdlEntitySet
28 | ? this.edmElement.EntityType
29 | : this.edmElement instanceof CsdlSingleton
30 | ? this.edmElement.Type
31 | : this.options.name,
32 | callables: this.callables ?? [],
33 | };
34 | }
35 | public entityType() {
36 | return this.edmElement instanceof CsdlEntitySet
37 | ? this.edmElement.EntityType
38 | : this.edmElement instanceof CsdlSingleton
39 | ? this.edmElement.Type
40 | : '';
41 | }
42 |
43 | public override name() {
44 | return strings.classify(this.edmElement.name()) + 'Service';
45 | }
46 | public override fileName() {
47 | return strings.dasherize(this.edmElement.name()) + '.service';
48 | }
49 | public override directory() {
50 | return this.edmElement.namespace().replace(/\./g, '/');
51 | }
52 | public override fullName() {
53 | return this.edmElement.fullName();
54 | }
55 | public override importTypes(): string[] {
56 | const imports = [];
57 | if (this.edmElement instanceof CsdlEntitySet) {
58 | imports.push(this.edmElement.EntityType);
59 | } else if (this.edmElement instanceof CsdlSingleton) {
60 | imports.push(this.edmElement.Type);
61 | }
62 | for (var call of this.callables ?? []) {
63 | const ret = call.returnType();
64 | if (ret !== undefined && !ret.Type.startsWith('Edm.')) {
65 | imports.push(ret.Type);
66 | }
67 | const { binding, required, optional } = call.parameters();
68 | for (let param of [...required, ...optional]) {
69 | if (!param.Type.startsWith('Edm.')) {
70 | imports.push(param.Type);
71 | }
72 | }
73 | }
74 | return imports;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/files/api-config/__fileName__.ts:
--------------------------------------------------------------------------------
1 | import { ODataApiConfig, EDM_PARSERS, ODataMetadata, ODataVersion } from 'angular-odata';
2 | import * as json from './metadata.json';
3 |
4 | export const <%= classify(name) %> = ODataMetadata.fromJson(json).toConfig({
5 | serviceRootUrl: '<%= serviceRootUrl %>',
6 | metadataUrl: '<%= metadataUrl %>',
7 | name: '<%= apiConfigName %>',
8 | version: '<%= version %>' as ODataVersion,
9 | creation: new Date('<%= creation.toISOString() %>'),
10 | parsers: EDM_PARSERS
11 | }) as ODataApiConfig;
12 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/files/entity/__fileName__.ts:
--------------------------------------------------------------------------------
1 | import { Duration } from 'angular-odata';<% for (let imp of imports) { %>
2 | import { <%= imp.names.join(", ") %> } from '<%= imp.path() %>';<% } %>
3 |
4 | export const <%= type %> = '<%= fullName %>';
5 | export interface <%= classify(name) %><% if (baseType) { %> extends <%= toTypescriptType(baseType) %><% } %> {<% for(let prop of properties) { %>
6 | <%= prop.name() %>: <%= prop.type() %>;<% } %>
7 | }
8 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/files/entitycontainer-service/__fileName__.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { ODataClient,
3 | ODataActionResource,
4 | ODataActionOptions,
5 | ODataFunctionResource,
6 | ODataFunctionOptions,
7 | ODataEntitySetService,
8 | ODataOptions,
9 | ODataBaseService,
10 | EntityKey } from 'angular-odata';<% for (let imp of imports) { %>
11 | import { <%= imp.names.join(", ") %> } from '<%= imp.path() %>';<% } %>
12 |
13 | @Injectable()
14 | export class <%= classify(name) %> extends ODataBaseService {
15 | constructor(client: ODataClient) {
16 | super(client, '<%= path %>', '<%= type %>');
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/files/entityset-service/__fileName__.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { ODataClient,
3 | ODataActionResource,
4 | ODataActionOptions,
5 | ODataFunctionResource,
6 | ODataFunctionOptions,
7 | ODataEntitySetService,
8 | ODataOptions,
9 | EntityKey } from 'angular-odata';<% for (let imp of imports) { %>
10 | import { <%= imp.names.join(", ") %> } from '<%= imp.path() %>';<% } %>
11 |
12 | @Injectable()
13 | export class <%= classify(name) %> extends ODataEntitySetService<<%= toTypescriptType(type) %>> {
14 | constructor(client: ODataClient) {
15 | super(client, '<%= path %>', '<%= type %>');
16 | }
17 | <%= camelize(toTypescriptType(type)) %>Model(entity?: Partial<<%= toTypescriptType(type) %>>) {
18 | return this.model(entity);
19 | }
20 | <%= camelize(toTypescriptType(type)) %>Collection(entities?: Partial<<%= toTypescriptType(type) %>>[]) {
21 | return this.collection(entities);
22 | }<% for (let cal of callables) { %>
23 | // <%= cal.name() %>
24 | <%= cal.resourceFunction() %>
25 | <%= cal.callableFunction() %>
26 | <% } %>
27 | }
28 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/files/enum/__fileName__.ts:
--------------------------------------------------------------------------------
1 | export const <%= type %> = '<%= fullName %>';
2 | export enum <%= classify(name) %> {<% for(let value of values) { %>
3 | <%= value.name() %> = <%= value.value() %>,<% } %>
4 | }
5 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/files/index/__fileName__.ts:
--------------------------------------------------------------------------------
1 | <% for (let imp of imports) { %>export * from '<%= imp.path() %>';
2 | <% } %>
3 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/files/metadata/metadata.json:
--------------------------------------------------------------------------------
1 | <%= content %>
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/files/module/__fileName__.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';<% for (let imp of imports) { %>
2 | import { <%= imp.names.join(", ") %> } from '<%= imp.path() %>';<% } %>
3 |
4 | @NgModule({
5 | providers: [<% for(let service of services) { %>
6 | <%= service.name() %>,<% } %>
7 | ]
8 | })
9 | export class <%= classify(name) %> { }
10 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/files/singleton-service/__fileName__.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { ODataClient,
3 | ODataActionResource,
4 | ODataActionOptions,
5 | ODataFunctionResource,
6 | ODataFunctionOptions,
7 | ODataEntitySetService,
8 | ODataOptions,
9 | ODataSingletonService,
10 | EntityKey } from 'angular-odata';<% for (let imp of imports) { %>
11 | import { <%= imp.names.join(", ") %> } from '<%= imp.path() %>';<% } %>
12 |
13 | @Injectable()
14 | export class <%= classify(name) %> extends ODataSingletonService<<%= toTypescriptType(type) %>> {
15 | constructor(client: ODataClient) {
16 | super(client, '<%= path %>', '<%= type %>');
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/metadata/csdl/csdl-entity-container.ts:
--------------------------------------------------------------------------------
1 | import { CsdlEntitySet } from './csdl-entity-set';
2 | import { CsdlSingleton } from './csdl-singleton';
3 | import { CsdlFunctionImport, CsdlActionImport } from './csdl-function-action';
4 | import { CsdlAnnotable } from './csdl-annotation';
5 | import type { CsdlSchema } from './csdl-schema';
6 |
7 | export class CsdlEntityContainer extends CsdlAnnotable {
8 | public Name: string;
9 | public Extend?: string;
10 | public EntitySet?: CsdlEntitySet[];
11 | public Singleton?: CsdlSingleton[];
12 | public FunctionImport?: CsdlFunctionImport[];
13 | public ActionImport?: CsdlActionImport[];
14 |
15 | constructor(
16 | private schema: CsdlSchema,
17 | {
18 | Name,
19 | Extend,
20 | EntitySet,
21 | Singleton,
22 | FunctionImport,
23 | ActionImport,
24 | Annotation,
25 | }: {
26 | Name: string;
27 | Extend?: string;
28 | EntitySet?: any[];
29 | Singleton?: any[];
30 | FunctionImport?: any[];
31 | ActionImport?: any[];
32 | Annotation?: any[];
33 | },
34 | ) {
35 | super({ Annotation });
36 |
37 | this.Name = Name;
38 | this.Extend = Extend;
39 | this.EntitySet = EntitySet?.map((e) => new CsdlEntitySet(this, e));
40 | this.Singleton = Singleton?.map((s) => new CsdlSingleton(this, s));
41 | this.FunctionImport = FunctionImport?.map(
42 | (f) => new CsdlFunctionImport(this, f),
43 | );
44 | this.ActionImport = ActionImport?.map((a) => new CsdlActionImport(this, a));
45 | }
46 |
47 | override toJson() {
48 | const json: { [key: string]: any } = { ...super.toJson() };
49 | if (this.Extend !== undefined) {
50 | json['Extend'] = this.Extend;
51 | }
52 | if (Array.isArray(this.EntitySet) && this.EntitySet.length > 0) {
53 | json['EntitySet'] = this.EntitySet.map((a) => a.toJson());
54 | }
55 | if (Array.isArray(this.Singleton) && this.Singleton.length > 0) {
56 | json['Singleton'] = this.Singleton.map((a) => a.toJson());
57 | }
58 | if (Array.isArray(this.FunctionImport) && this.FunctionImport.length > 0) {
59 | json['FunctionImport'] = this.FunctionImport.map((a) => a.toJson());
60 | }
61 | if (Array.isArray(this.ActionImport) && this.ActionImport.length > 0) {
62 | json['ActionImport'] = this.ActionImport.map((a) => a.toJson());
63 | }
64 | return json;
65 | }
66 |
67 | name() {
68 | return `${this.Name}`;
69 | }
70 |
71 | namespace() {
72 | return `${this.schema.Namespace}`;
73 | }
74 |
75 | fullName() {
76 | return `${this.schema.Namespace}.${this.Name}`;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/metadata/csdl/csdl-entity-set.ts:
--------------------------------------------------------------------------------
1 | import { CsdlAnnotable } from './csdl-annotation';
2 | import type { CsdlEntityContainer } from './csdl-entity-container';
3 | import { CsdlNavigationPropertyBinding } from './csdl-navigation-property-binding';
4 |
5 | export class CsdlEntitySet extends CsdlAnnotable {
6 | public Name: string;
7 | public EntityType: string;
8 | public NavigationPropertyBinding?: CsdlNavigationPropertyBinding[];
9 | public IncludeInServiceDocument?: boolean;
10 |
11 | constructor(
12 | private container: CsdlEntityContainer,
13 | {
14 | Name,
15 | EntityType,
16 | NavigationPropertyBinding,
17 | IncludeInServiceDocument,
18 | Annotation,
19 | }: {
20 | Name: string;
21 | EntityType: string;
22 | NavigationPropertyBinding?: any[];
23 | IncludeInServiceDocument?: boolean;
24 | Annotation?: any[];
25 | },
26 | ) {
27 | super({ Annotation });
28 |
29 | this.Name = Name;
30 | this.EntityType = EntityType;
31 | this.NavigationPropertyBinding = NavigationPropertyBinding?.map(
32 | (n) => new CsdlNavigationPropertyBinding(n),
33 | );
34 | this.IncludeInServiceDocument = IncludeInServiceDocument;
35 | }
36 |
37 | override toJson() {
38 | const json: { [key: string]: any } = {
39 | ...super.toJson(),
40 | Name: this.Name,
41 | EntityType: this.EntityType,
42 | };
43 | if (
44 | Array.isArray(this.NavigationPropertyBinding) &&
45 | this.NavigationPropertyBinding.length > 0
46 | ) {
47 | json['NavigationPropertyBinding'] = this.NavigationPropertyBinding.map(
48 | (n) => n.toJson(),
49 | );
50 | }
51 | if (this.IncludeInServiceDocument !== undefined) {
52 | json['IncludeInServiceDocument'] = this.IncludeInServiceDocument;
53 | }
54 | return json;
55 | }
56 |
57 | name() {
58 | return `${this.Name}`;
59 | }
60 |
61 | namespace() {
62 | return `${this.container.namespace()}`;
63 | }
64 |
65 | fullName() {
66 | return `${this.container.namespace()}.${this.Name}`;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/metadata/csdl/csdl-enum-type.ts:
--------------------------------------------------------------------------------
1 | import { CsdlAnnotable } from './csdl-annotation';
2 | import type { CsdlSchema } from './csdl-schema';
3 |
4 | export class CsdlEnumType extends CsdlAnnotable {
5 | Name: string;
6 | Member: CsdlMember[];
7 | UnderlyingType?: string;
8 | IsFlags?: boolean;
9 | constructor(
10 | private schema: CsdlSchema,
11 | {
12 | Name,
13 | Member,
14 | UnderlyingType,
15 | IsFlags,
16 | Annotation,
17 | }: {
18 | Name: string;
19 | Member: any[];
20 | UnderlyingType?: string;
21 | IsFlags?: boolean;
22 | Annotation?: any[];
23 | },
24 | ) {
25 | super({ Annotation });
26 | this.Name = Name;
27 | this.Member = Member.map((m) => new CsdlMember(m));
28 | this.UnderlyingType = UnderlyingType;
29 | this.IsFlags = IsFlags;
30 | }
31 |
32 | override toJson() {
33 | const json: { [key: string]: any } = {
34 | ...super.toJson(),
35 | Name: this.Name,
36 | Member: this.Member.map((m) => m.toJson()),
37 | };
38 | if (this.UnderlyingType !== undefined) {
39 | json['UnderlyingType'] = this.UnderlyingType;
40 | }
41 | if (this.IsFlags !== undefined) {
42 | json['IsFlags'] = this.IsFlags;
43 | }
44 | return json;
45 | }
46 |
47 | name() {
48 | return `${this.Name}`;
49 | }
50 |
51 | namespace() {
52 | return `${this.schema.Namespace}`;
53 | }
54 |
55 | fullName() {
56 | return `${this.schema.Namespace}.${this.Name}`;
57 | }
58 | }
59 |
60 | export class CsdlMember extends CsdlAnnotable {
61 | Name: string;
62 | Value?: number;
63 | constructor({
64 | Name,
65 | Value,
66 | Annotation,
67 | }: {
68 | Name: string;
69 | Value?: number;
70 | Annotation?: any[];
71 | }) {
72 | super({ Annotation });
73 | this.Name = Name;
74 | this.Value = Value;
75 | }
76 |
77 | override toJson() {
78 | const json: { [key: string]: any } = { ...super.toJson(), Name: this.Name };
79 | if (this.Value !== undefined) {
80 | json['Value'] = this.Value;
81 | }
82 | return json;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/metadata/csdl/csdl-navigation-property-binding.ts:
--------------------------------------------------------------------------------
1 | export class CsdlNavigationPropertyBinding {
2 | Path: string;
3 | Target: string;
4 |
5 | constructor({ Path, Target }: { Path: string; Target: string }) {
6 | this.Path = Path;
7 | this.Target = Target;
8 | }
9 |
10 | toJson() {
11 | return {
12 | Path: this.Path,
13 | Target: this.Target,
14 | };
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/metadata/csdl/csdl-reference.ts:
--------------------------------------------------------------------------------
1 | import { CsdlAnnotable } from './csdl-annotation';
2 |
3 | export class CsdlReference extends CsdlAnnotable {
4 | Uri: string;
5 | Include?: CsdlInclude[];
6 | IncludeAnnotations?: CsdlIncludeAnnotations[];
7 | constructor({
8 | Uri,
9 | Include,
10 | IncludeAnnotations,
11 | Annotation,
12 | }: {
13 | Uri: string;
14 | Include?: any[];
15 | IncludeAnnotations?: any[];
16 | Annotation?: any[];
17 | }) {
18 | super({ Annotation });
19 | this.Uri = Uri;
20 | this.Include = Include?.map((i) => new CsdlInclude(i));
21 | this.IncludeAnnotations = IncludeAnnotations?.map(
22 | (i) => new CsdlIncludeAnnotations(i),
23 | );
24 | }
25 |
26 | override toJson() {
27 | const json: { [key: string]: any } = { ...super.toJson(), Uri: this.Uri };
28 | if (Array.isArray(this.Include) && this.Include.length > 0) {
29 | json['Include'] = this.Include.map((i) => i.toJson());
30 | }
31 | if (
32 | Array.isArray(this.IncludeAnnotations) &&
33 | this.IncludeAnnotations.length > 0
34 | ) {
35 | json['IncludeAnnotations'] = this.IncludeAnnotations.map((i) =>
36 | i.toJson(),
37 | );
38 | }
39 | return json;
40 | }
41 | }
42 |
43 | export class CsdlInclude {
44 | Namespace: string;
45 | Alias?: string;
46 | constructor({ Namespace, Alias }: { Namespace: string; Alias?: string }) {
47 | this.Namespace = Namespace;
48 | this.Alias = Alias;
49 | }
50 |
51 | toJson() {
52 | return {
53 | Namespace: this.Namespace,
54 | Alias: this.Alias,
55 | };
56 | }
57 | }
58 |
59 | export class CsdlIncludeAnnotations {
60 | TermNamespace: string;
61 | Qualifier?: string;
62 | TargetNamespace?: string;
63 | constructor({
64 | TermNamespace,
65 | Qualifier,
66 | TargetNamespace,
67 | }: {
68 | TermNamespace: string;
69 | Qualifier?: string;
70 | TargetNamespace?: string;
71 | }) {
72 | this.TermNamespace = TermNamespace;
73 | this.Qualifier = Qualifier;
74 | this.TargetNamespace = TargetNamespace;
75 | }
76 |
77 | toJson() {
78 | return {
79 | TermNamespace: this.TermNamespace,
80 | Qualifier: this.Qualifier,
81 | TargetNamespace: this.TargetNamespace,
82 | };
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/metadata/csdl/csdl-schema.ts:
--------------------------------------------------------------------------------
1 | import { CsdlTerm, CsdlAnnotations } from './csdl-annotation';
2 | import { CsdlTypeDefinition } from './csdl-type-definition';
3 | import { CsdlEnumType } from './csdl-enum-type';
4 | import { CsdlEntityType, CsdlComplexType } from './csdl-structured-type';
5 | import { CsdlFunction, CsdlAction } from './csdl-function-action';
6 | import { CsdlEntityContainer } from './csdl-entity-container';
7 |
8 | export class CsdlSchema {
9 | Namespace: string;
10 | Alias?: string;
11 | EnumType?: CsdlEnumType[];
12 | ComplexType?: CsdlComplexType[];
13 | EntityType?: CsdlEntityType[];
14 | Function?: CsdlFunction[];
15 | Action?: CsdlAction[];
16 | EntityContainer?: CsdlEntityContainer[];
17 | TypeDefinition?: CsdlTypeDefinition[];
18 | Term?: CsdlTerm[];
19 | Annotations?: CsdlAnnotations[];
20 | constructor({
21 | Namespace,
22 | Alias,
23 | EnumType,
24 | ComplexType,
25 | EntityType,
26 | Function,
27 | Action,
28 | EntityContainer,
29 | TypeDefinition,
30 | Term,
31 | Annotations,
32 | }: {
33 | Namespace: string;
34 | Alias?: string;
35 | EnumType?: any[];
36 | ComplexType?: any[];
37 | EntityType?: any[];
38 | Function?: any[];
39 | Action?: any[];
40 | EntityContainer?: any[];
41 | TypeDefinition?: any[];
42 | Term?: any[];
43 | Annotations?: any[];
44 | }) {
45 | this.Namespace = Namespace;
46 | this.Alias = Alias;
47 | this.EnumType = EnumType?.map((e) => new CsdlEnumType(this, e));
48 | this.ComplexType = ComplexType?.map((c) => new CsdlComplexType(this, c));
49 | this.EntityType = EntityType?.map((e) => new CsdlEntityType(this, e));
50 | this.Function = Function?.map((f) => new CsdlFunction(this, f));
51 | this.Action = Action?.map((a) => new CsdlAction(this, a));
52 | this.EntityContainer = EntityContainer?.map(
53 | (e) => new CsdlEntityContainer(this, e),
54 | );
55 | this.TypeDefinition = TypeDefinition?.map(
56 | (t) => new CsdlTypeDefinition(this, t),
57 | );
58 | this.Term = Term?.map((t) => new CsdlTerm(this, t));
59 | this.Annotations = Annotations?.map((a) => new CsdlAnnotations(this, a));
60 | }
61 |
62 | toJson() {
63 | const json: { [key: string]: any } = {
64 | Namespace: this.Namespace,
65 | };
66 | if (this.Alias !== undefined) {
67 | json['Alias'] = this.Alias;
68 | }
69 | if (
70 | Array.isArray(this.EntityContainer) &&
71 | this.EntityContainer.length > 0
72 | ) {
73 | json['EntityContainer'] = this.EntityContainer.map((a) => a.toJson());
74 | }
75 | if (Array.isArray(this.EntityType) && this.EntityType.length > 0) {
76 | json['EntityType'] = this.EntityType.map((a) => a.toJson());
77 | }
78 | if (Array.isArray(this.ComplexType) && this.ComplexType.length > 0) {
79 | json['ComplexType'] = this.ComplexType.map((a) => a.toJson());
80 | }
81 | if (Array.isArray(this.EnumType) && this.EnumType.length > 0) {
82 | json['EnumType'] = this.EnumType.map((a) => a.toJson());
83 | }
84 | if (Array.isArray(this.TypeDefinition) && this.TypeDefinition.length > 0) {
85 | json['TypeDefinition'] = this.TypeDefinition.map((a) => a.toJson());
86 | }
87 | if (Array.isArray(this.Term) && this.Term.length > 0) {
88 | json['Term'] = this.Term.map((a) => a.toJson());
89 | }
90 | if (Array.isArray(this.Annotations) && this.Annotations.length > 0) {
91 | json['Annotations'] = this.Annotations.map((a) => a.toJson());
92 | }
93 | if (Array.isArray(this.Action) && this.Action.length > 0) {
94 | json['Action'] = this.Action.map((a) => a.toJson());
95 | }
96 | if (Array.isArray(this.Function) && this.Function.length > 0) {
97 | json['Function'] = this.Function.map((a) => a.toJson());
98 | }
99 | return json;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/metadata/csdl/csdl-singleton.ts:
--------------------------------------------------------------------------------
1 | import { CsdlAnnotable } from './csdl-annotation';
2 | import type { CsdlEntityContainer } from './csdl-entity-container';
3 | import { CsdlNavigationPropertyBinding } from './csdl-navigation-property-binding';
4 |
5 | export class CsdlSingleton extends CsdlAnnotable {
6 | Name: string;
7 | Type: string;
8 | NavigationPropertyBindings?: CsdlNavigationPropertyBinding[];
9 |
10 | constructor(
11 | private container: CsdlEntityContainer,
12 | {
13 | Name,
14 | Type,
15 | NavigationPropertyBindings,
16 | Annotation,
17 | }: {
18 | Name: string;
19 | Type: string;
20 | NavigationPropertyBindings?: any[];
21 | Annotation?: any[];
22 | },
23 | ) {
24 | super({ Annotation });
25 | this.Name = Name;
26 | this.Type = Type;
27 | this.NavigationPropertyBindings = NavigationPropertyBindings?.map(
28 | (n) => new CsdlNavigationPropertyBinding(n),
29 | );
30 | }
31 |
32 | override toJson() {
33 | const json: { [key: string]: any } = {
34 | ...super.toJson(),
35 | Name: this.Name,
36 | Type: this.Type,
37 | };
38 | if (
39 | Array.isArray(this.NavigationPropertyBindings) &&
40 | this.NavigationPropertyBindings.length > 0
41 | ) {
42 | json['NavigationPropertyBindings'] = this.NavigationPropertyBindings.map(
43 | (n) => n.toJson(),
44 | );
45 | }
46 | return json;
47 | }
48 |
49 | name() {
50 | return `${this.Name}`;
51 | }
52 |
53 | namespace() {
54 | return `${this.container.namespace()}`;
55 | }
56 |
57 | fullName() {
58 | return `${this.container.namespace()}.${this.Name}`;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/metadata/csdl/csdl-type-definition.ts:
--------------------------------------------------------------------------------
1 | import { CsdlAnnotable, CsdlAnnotation } from './csdl-annotation';
2 | import type { CsdlSchema } from './csdl-schema';
3 |
4 | export class CsdlTypeDefinition extends CsdlAnnotable {
5 | public Name: string;
6 | public UnderlayingType: string;
7 | public MaxLength?: number;
8 | public Precision?: number;
9 | public Scale?: number;
10 | public Unicode?: boolean;
11 | public SRID?: string;
12 |
13 | constructor(
14 | private schema: CsdlSchema,
15 | {
16 | Name,
17 | UnderlayingType,
18 | MaxLength,
19 | Precision,
20 | Scale,
21 | Unicode,
22 | SRID,
23 | Annotation,
24 | }: {
25 | Name: string;
26 | UnderlayingType: string;
27 | MaxLength?: number;
28 | Precision?: number;
29 | Scale?: number;
30 | Unicode?: boolean;
31 | SRID?: string;
32 | Annotation?: CsdlAnnotation[];
33 | },
34 | ) {
35 | super({ Annotation });
36 | this.Name = Name;
37 | this.UnderlayingType = UnderlayingType;
38 | this.MaxLength = MaxLength;
39 | this.Precision = Precision;
40 | this.Scale = Scale;
41 | this.Unicode = Unicode;
42 | this.SRID = SRID;
43 | }
44 |
45 | override toJson() {
46 | const json: { [key: string]: any } = {
47 | ...super.toJson(),
48 | Name: this.Name,
49 | UnderlayingType: this.UnderlayingType,
50 | };
51 | if (this.MaxLength !== undefined) {
52 | json['MaxLength'] = this.MaxLength;
53 | }
54 | if (this.Precision !== undefined) {
55 | json['Precision'] = this.Precision;
56 | }
57 | if (this.Scale !== undefined) {
58 | json['Scale'] = this.Scale;
59 | }
60 | if (this.Unicode !== undefined) {
61 | json['Unicode'] = this.Unicode;
62 | }
63 | if (this.SRID !== undefined) {
64 | json['SRID'] = this.SRID;
65 | }
66 | return json;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/metadata/index.ts:
--------------------------------------------------------------------------------
1 | export * from './metadata';
2 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/metadata/metadata.ts:
--------------------------------------------------------------------------------
1 | import { CsdlAction, CsdlFunction } from './csdl/csdl-function-action';
2 | import { CsdlReference } from './csdl/csdl-reference';
3 | import { CsdlSchema } from './csdl/csdl-schema';
4 |
5 | export class ODataMetadata {
6 | Version: string;
7 | References: CsdlReference[];
8 | Schemas: CsdlSchema[];
9 | constructor(Version: string, References: any[], Schemas: any[]) {
10 | this.Version = Version;
11 | this.References = References?.map((r) => new CsdlReference(r));
12 | this.Schemas = Schemas?.map((s) => new CsdlSchema(s));
13 | }
14 |
15 | toJson() {
16 | return {
17 | Version: this.Version,
18 | References: this.References.map((r) => r.toJson()),
19 | Schemas: this.Schemas.map((s) => s.toJson()),
20 | };
21 | }
22 |
23 | functions() {
24 | return this.Schemas.reduce((acc, s) => {
25 | return [...acc, ...(s.Function ?? [])];
26 | }, [] as CsdlFunction[]);
27 | }
28 |
29 | actions() {
30 | return this.Schemas.reduce((acc, s) => {
31 | return [...acc, ...(s.Action ?? [])];
32 | }, [] as CsdlAction[]);
33 | }
34 |
35 | static fromJson(json: any): ODataMetadata {
36 | return new ODataMetadata(json.Version, json.References, json.Schemas);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/schema",
3 | "$id": "SchematicsMetadata",
4 | "title": "Metadata Schema",
5 | "type": "object",
6 | "properties": {
7 | "name": {
8 | "description": "The name for the module.",
9 | "type": "string"
10 | },
11 | "metadata": {
12 | "description": "The url of the metadata.",
13 | "type": "string"
14 | },
15 | "path": {
16 | "type": "string",
17 | "format": "path",
18 | "description": "The path at which to create the module, relative to the workspace root.",
19 | "visible": false
20 | },
21 | "project": {
22 | "type": "string",
23 | "description": "The name of the project.",
24 | "$default": {
25 | "$source": "projectName"
26 | }
27 | },
28 | "serviceRootUrl": {
29 | "description": "The serviceRootUrl of the api.",
30 | "type": "string"
31 | }
32 | },
33 | "required": [
34 | "name",
35 | "metadata"
36 | ]
37 | }
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/apigen/schema.ts:
--------------------------------------------------------------------------------
1 | export interface Schema {
2 | name: string;
3 | project: string;
4 | metadata: string;
5 | path: string;
6 | serviceRootUrl?: string;
7 | version?: string;
8 | creation?: Date;
9 | }
10 |
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json",
3 | "schematics": {
4 | "ng-add": {
5 | "description": "Add my library to the project.",
6 | "factory": "./ng-add/index#ngAdd"
7 | },
8 | "apigen": {
9 | "description": "Generate API from metadata file.",
10 | "factory": "./apigen/index#apigen",
11 | "schema": "./apigen/schema.json"
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/projects/angular-odata/schematics/ng-add/index.ts:
--------------------------------------------------------------------------------
1 | import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
2 | import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
3 |
4 | // Just return the tree
5 | export function ngAdd(): Rule {
6 | return (tree: Tree, context: SchematicContext) => {
7 | context.addTask(new NodePackageInstallTask());
8 | return tree;
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/annotations.spec.ts:
--------------------------------------------------------------------------------
1 | import { VERSION_4_0 } from './constants';
2 | import { ODataHelper } from './helper';
3 | import { ODataEntitiesAnnotations } from './annotations';
4 |
5 | describe('ODataEntitiesAnnotations', () => {
6 | let instance: ODataEntitiesAnnotations;
7 | let annots: Map;
8 |
9 | describe('version 4.0', () => {
10 | beforeEach(() => {
11 | const helper = ODataHelper[VERSION_4_0];
12 | annots = new Map();
13 | instance = new ODataEntitiesAnnotations(helper, annots);
14 | });
15 |
16 | it('returns skipToken', () => {
17 | // Given
18 | const nextLink =
19 | 'https://graph.microsoft.com/v1.0/users?$skiptoken=RFNwdAoAAQAAAAAAAAAAFAAAAHoO-P3xtNOT90O-DRY2LSZF_AFWAAAAAQIAAAA';
20 | annots.set('@odata.nextLink', nextLink);
21 |
22 | // When
23 | const actual = instance.skiptoken;
24 |
25 | // Then
26 | const expected =
27 | 'RFNwdAoAAQAAAAAAAAAAFAAAAHoO-P3xtNOT90O-DRY2LSZF_AFWAAAAAQIAAAA';
28 | expect(actual).toBe(expected);
29 | });
30 | });
31 | });
32 |
33 | interface AirPort {}
34 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/cache/index.ts:
--------------------------------------------------------------------------------
1 | export * from './cache';
2 | export * from './memory';
3 | export * from './storage';
4 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/cache/memory.ts:
--------------------------------------------------------------------------------
1 | import { ODataRequest, ODataResponse } from '../resources';
2 | import { ODataBaseCache } from './cache';
3 |
4 | export class ODataInMemoryCache extends ODataBaseCache {
5 | constructor({ timeout }: { timeout?: number } = {}) {
6 | super({ timeout });
7 | }
8 |
9 | /**
10 | * Store the response in the cache
11 | * @param req The request with the resource to store the response
12 | * @param res The response to store in the cache
13 | */
14 | putResponse(req: ODataRequest, res: ODataResponse) {
15 | let scope = this.scope(req);
16 | let tags = this.tags(res);
17 | this.put(req.cacheKey, res, {
18 | timeout: res.options.maxAge,
19 | scope,
20 | tags,
21 | });
22 | }
23 |
24 | /**
25 | * Restore the response from the cache
26 | * @param req The request with the resource to get the response
27 | * @returns The response from the cache
28 | */
29 | getResponse(req: ODataRequest): ODataResponse | undefined {
30 | let scope = this.scope(req);
31 | return this.get(req.cacheKey, { scope });
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/cache/storage.ts:
--------------------------------------------------------------------------------
1 | import { ODataRequest, ODataResponse } from '../resources';
2 | import { ODataBaseCache, ODataCacheEntry } from './cache';
3 |
4 | interface ResponseJson {
5 | body: any | null;
6 | headers: { [name: string]: string | string[] };
7 | status: number;
8 | statusText: string;
9 | url: string | null;
10 | }
11 |
12 | export class ODataInStorageCache extends ODataBaseCache {
13 | name: string;
14 | storage: Storage;
15 |
16 | constructor({
17 | name,
18 | storage = sessionStorage,
19 | timeout,
20 | }: {
21 | timeout?: number;
22 | name: string;
23 | storage?: Storage;
24 | }) {
25 | super({ timeout });
26 | this.name = name;
27 | this.storage = storage;
28 | this.restore();
29 | window.addEventListener('beforeunload', () => this.store());
30 | }
31 |
32 | /**
33 | * Store the cache in the storage
34 | */
35 | store() {
36 | this.storage.setItem(
37 | this.name,
38 | JSON.stringify(Array.from(this.entries.entries())),
39 | );
40 | }
41 |
42 | /**
43 | * Restore the cache from the storage
44 | */
45 | restore() {
46 | this.entries = new Map>(
47 | JSON.parse(this.storage.getItem(this.name) || '[]'),
48 | );
49 | }
50 |
51 | /**
52 | * Flush the cache and clean the storage
53 | */
54 | override flush() {
55 | super.flush();
56 | this.store();
57 | }
58 |
59 | /**
60 | * Store the response in the cache
61 | * @param req The request with the resource to store the response
62 | * @param res The response to store in the cache
63 | */
64 | putResponse(req: ODataRequest, res: ODataResponse) {
65 | const scope = this.scope(req);
66 | const tags = this.tags(res);
67 | this.put(req.cacheKey, res.toJson(), {
68 | timeout: res.options.maxAge,
69 | scope,
70 | tags,
71 | });
72 | }
73 |
74 | /**
75 | * Restore the response from the cache
76 | * @param req The request with the resource to get the response
77 | * @returns The response from the cache
78 | */
79 | getResponse(req: ODataRequest): ODataResponse | undefined {
80 | const scope = this.scope(req);
81 | const data = this.get(req.cacheKey, { scope });
82 |
83 | return data !== undefined ? ODataResponse.fromJson(req, data) : undefined;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/constants.ts:
--------------------------------------------------------------------------------
1 | export const $ID = '$id';
2 | export const ODATA_ID = '@odata.id';
3 |
4 | // SEGMENTS
5 | export const $METADATA = '$metadata';
6 | export const $BATCH = '$batch';
7 | export const $REF = '$ref';
8 | export const $VALUE = '$value';
9 | export const $COUNT = '$count';
10 | export const $QUERY = '$query';
11 | export const $INLINECOUNT = '$inlinecount';
12 |
13 | // HTTP HEADERS
14 | export const IF_MATCH_HEADER = 'If-Match';
15 | export const IF_NONE_MATCH_HEADER = 'If-None-Match';
16 | export const CONTENT_TYPE = 'Content-Type';
17 | export const HTTP11 = 'HTTP/1.1';
18 | export const ACCEPT = 'Accept';
19 | export const PREFER = 'Prefer';
20 | export const CACHE_CONTROL = 'Cache-Control';
21 | export const CACHE_CONTROL_HEADERS = [
22 | CACHE_CONTROL,
23 | CACHE_CONTROL.toLowerCase(),
24 | ];
25 | export const ODATA_VERSION = 'OData-Version';
26 | export const ODATA_VERSION_HEADERS = [
27 | ODATA_VERSION,
28 | ODATA_VERSION.toLowerCase(),
29 | 'dataserviceversion',
30 | ];
31 | export const LOCATION_HEADER = 'Location';
32 | export const LOCATION_HEADERS = [
33 | LOCATION_HEADER,
34 | LOCATION_HEADER.toLowerCase(),
35 | ];
36 | export const ODATA_ENTITYID = 'OData-EntityId';
37 | export const ODATA_ENTITYID_HEADERS = [
38 | ODATA_ENTITYID,
39 | ODATA_ENTITYID.toLowerCase(),
40 | ];
41 | export const PREFERENCE_APPLIED = 'Preference-Applied';
42 | export const PREFERENCE_APPLIED_HEADERS = [
43 | PREFERENCE_APPLIED,
44 | PREFERENCE_APPLIED.toLowerCase(),
45 | ];
46 | export const ETAG_HEADER = 'ETag';
47 | export const ETAG_HEADERS = [ETAG_HEADER, ETAG_HEADER.toLowerCase()];
48 |
49 | export const RETRY_AFTER = 'Retry-After';
50 | export const RETRY_AFTER_HEADERS = [RETRY_AFTER, RETRY_AFTER.toLowerCase()];
51 |
52 | // HTTP HEADER VALUES
53 | export const APPLICATION_JSON = 'application/json';
54 | export const APPLICATION_HTTP = 'application/http';
55 | export const APPLICATION_XHTML = 'application/xhtml+xml';
56 | export const APPLICATION_XML = 'application/xml';
57 | export const TEXT_PLAIN = 'text/plain';
58 | export const CONTENT_TYPE_ANY = '*/*';
59 | export const MULTIPART_MIXED = 'multipart/mixed';
60 | export const MULTIPART_MIXED_BOUNDARY = 'multipart/mixed;boundary=';
61 | export const CONTENT_TRANSFER_ENCODING = 'Content-Transfer-Encoding';
62 | export const CONTENT_ID = 'Content-ID';
63 | export const MAX_AGE = 'max-age';
64 |
65 | // VERSIONS
66 | export const VERSION_4_0 = '4.0';
67 | export const VERSION_3_0 = '3.0';
68 | export const VERSION_2_0 = '2.0';
69 | export const DEFAULT_VERSION = VERSION_4_0;
70 |
71 | export const BINARY = 'binary';
72 | export const BOUNDARY_PREFIX_SUFFIX = '--';
73 | export const BATCH_PREFIX = 'batch_';
74 | export const CHANGESET_PREFIX = 'changeset_';
75 | export const DEFAULT_METADATA = 'minimal';
76 | export const DEFAULT_STRIP_METADATA = 'full';
77 | export const DEFAULT_FETCH_POLICY = 'network-only';
78 | export const DEFAULT_TIMEOUT = 60; // Time in seconds
79 | export const CALLABLE_BINDING_PARAMETER = 'bindingParameter';
80 | export const XSSI_PREFIX = /^\)\]\}',?\n/;
81 |
82 | // URL PARTS
83 | export const QUERY_SEPARATOR = '?';
84 | export const PARAM_SEPARATOR = '&';
85 | export const VALUE_SEPARATOR = '=';
86 | export const PATH_SEPARATOR = '/';
87 | export const ODATA_PARAM_PREFIX = '$';
88 | export const ODATA_ALIAS_PREFIX = '@';
89 |
90 | export const NEWLINE = '\r\n';
91 | export const NEWLINE_REGEXP = /\r?\n/;
92 | export const CACHE_KEY_SEPARATOR = ':';
93 |
94 | // Models
95 | export const CID_FIELD_NAME = '_cid';
96 | export const EVENT_SPLITTER = /\s+/;
97 |
98 | // Standard vocabularies for annotating OData services
99 | // https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Core.V1.md
100 |
101 | export const COMPUTED = /.*Computed$/;
102 | export const OPTIMISTIC_CONCURRENCY = /.*OptimisticConcurrency$/;
103 | export const DESCRIPTION = /.*Description$/;
104 | export const LONG_DESCRIPTION = /.*LongDescription$/;
105 | export const OPTIONARL_PARAMETER = /.*OptionalParameter$/;
106 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | export * from './types';
2 | export * from './settings';
3 | export * from './annotations';
4 | export * from './api';
5 | export * from './client';
6 | export * from './module';
7 | export * from './loaders';
8 |
9 | // Utils
10 | export * from './utils/index';
11 |
12 | // Services
13 | export * from './services/index';
14 |
15 | // Schema
16 | export * from './schema/index';
17 |
18 | // Models
19 | export * from './models/index';
20 |
21 | // Resources
22 | export * from './resources/index';
23 |
24 | // Cache
25 | export * from './cache/index';
26 |
27 | // Metadata
28 | export * from './metadata/index';
29 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/loaders.ts:
--------------------------------------------------------------------------------
1 | import { Observable, forkJoin, map, of } from 'rxjs';
2 | import { ODataApiConfig } from './types';
3 | import { ODataMetadataParser } from './metadata';
4 |
5 | export abstract class ODataConfigLoader {
6 | abstract loadConfigs(): Observable;
7 | }
8 |
9 | export class ODataConfigSyncLoader implements ODataConfigLoader {
10 | constructor(
11 | private readonly passedConfigs: ODataApiConfig | ODataApiConfig[],
12 | ) {}
13 |
14 | loadConfigs(): Observable {
15 | return Array.isArray(this.passedConfigs)
16 | ? of(this.passedConfigs)
17 | : of([this.passedConfigs]);
18 | }
19 | }
20 |
21 | export class ODataConfigAsyncLoader implements ODataConfigLoader {
22 | constructor(
23 | private readonly configs$:
24 | | Observable[]
25 | | Observable,
26 | ) {}
27 |
28 | loadConfigs(): Observable {
29 | return Array.isArray(this.configs$)
30 | ? forkJoin(this.configs$)
31 | : (this.configs$ as Observable).pipe(
32 | map((value) =>
33 | Array.isArray(value)
34 | ? (value as ODataApiConfig[])
35 | : ([value] as ODataApiConfig[]),
36 | ),
37 | );
38 | }
39 | }
40 |
41 | export class ODataMetadataLoader implements ODataConfigLoader {
42 | constructor(
43 | private readonly sources$: Observable,
44 | private readonly baseConfigs: ODataApiConfig | ODataApiConfig[],
45 | ) {}
46 |
47 | loadConfigs(): Observable {
48 | const configs = Array.isArray(this.baseConfigs)
49 | ? this.baseConfigs
50 | : [this.baseConfigs];
51 | return this.sources$.pipe(
52 | map((source) =>
53 | (Array.isArray(source) ? source : [source]).map((m, i) =>
54 | new ODataMetadataParser(m).metadata().toConfig(configs[i] ?? {}),
55 | ),
56 | ),
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/metadata/csdl/csdl-entity-container.ts:
--------------------------------------------------------------------------------
1 | import { CsdlEntitySet } from './csdl-entity-set';
2 | import { CsdlSingleton } from './csdl-singleton';
3 | import { CsdlFunctionImport, CsdlActionImport } from './csdl-function-action';
4 | import { CsdlAnnotable } from './csdl-annotation';
5 | import type { CsdlSchema } from './csdl-schema';
6 | import { ODataEntityContainerConfig } from '../../types';
7 |
8 | export class CsdlEntityContainer extends CsdlAnnotable {
9 | public Name: string;
10 | public Extend?: string;
11 | public EntitySet?: CsdlEntitySet[];
12 | public Singleton?: CsdlSingleton[];
13 | public FunctionImport?: CsdlFunctionImport[];
14 | public ActionImport?: CsdlActionImport[];
15 |
16 | constructor(
17 | private schema: CsdlSchema,
18 | {
19 | Name,
20 | Extend,
21 | EntitySet,
22 | Singleton,
23 | FunctionImport,
24 | ActionImport,
25 | Annotation,
26 | }: {
27 | Name: string;
28 | Extend?: string;
29 | EntitySet?: any[];
30 | Singleton?: any[];
31 | FunctionImport?: any[];
32 | ActionImport?: any[];
33 | Annotation?: any[];
34 | },
35 | ) {
36 | super({ Annotation });
37 |
38 | this.Name = Name;
39 | this.Extend = Extend;
40 | this.EntitySet = EntitySet?.map((e) => new CsdlEntitySet(this, e));
41 | this.Singleton = Singleton?.map((s) => new CsdlSingleton(this, s));
42 | this.FunctionImport = FunctionImport?.map(
43 | (f) => new CsdlFunctionImport(this, f),
44 | );
45 | this.ActionImport = ActionImport?.map((a) => new CsdlActionImport(this, a));
46 | }
47 |
48 | override toJson() {
49 | const json: { [key: string]: any } = { ...super.toJson() };
50 | if (this.Extend !== undefined) {
51 | json['Extend'] = this.Extend;
52 | }
53 | if (Array.isArray(this.EntitySet) && this.EntitySet.length > 0) {
54 | json['EntitySet'] = this.EntitySet.map((a) => a.toJson());
55 | }
56 | if (Array.isArray(this.Singleton) && this.Singleton.length > 0) {
57 | json['Singleton'] = this.Singleton.map((a) => a.toJson());
58 | }
59 | if (Array.isArray(this.FunctionImport) && this.FunctionImport.length > 0) {
60 | json['FunctionImport'] = this.FunctionImport.map((a) => a.toJson());
61 | }
62 | if (Array.isArray(this.ActionImport) && this.ActionImport.length > 0) {
63 | json['ActionImport'] = this.ActionImport.map((a) => a.toJson());
64 | }
65 | return json;
66 | }
67 |
68 | name() {
69 | return `${this.Name}`;
70 | }
71 |
72 | namespace() {
73 | return `${this.schema.Namespace}`;
74 | }
75 |
76 | fullName() {
77 | return `${this.schema.Namespace}.${this.Name}`;
78 | }
79 |
80 | override toConfig(
81 | base?: Partial,
82 | ): ODataEntityContainerConfig {
83 | return {
84 | ...super.toConfig(),
85 | name: this.Name,
86 | entitySets: this.EntitySet?.map((t) => t.toConfig()),
87 | };
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/metadata/csdl/csdl-entity-set.ts:
--------------------------------------------------------------------------------
1 | import { ODataEntitySetConfig } from '../../types';
2 | import { CsdlAnnotable } from './csdl-annotation';
3 | import type { CsdlEntityContainer } from './csdl-entity-container';
4 | import { CsdlNavigationPropertyBinding } from './csdl-navigation-property-binding';
5 |
6 | export class CsdlEntitySet extends CsdlAnnotable {
7 | public Name: string;
8 | public EntityType: string;
9 | public NavigationPropertyBinding?: CsdlNavigationPropertyBinding[];
10 | public IncludeInServiceDocument?: boolean;
11 |
12 | constructor(
13 | private container: CsdlEntityContainer,
14 | {
15 | Name,
16 | EntityType,
17 | NavigationPropertyBinding,
18 | IncludeInServiceDocument,
19 | Annotation,
20 | }: {
21 | Name: string;
22 | EntityType: string;
23 | NavigationPropertyBinding?: any[];
24 | IncludeInServiceDocument?: boolean;
25 | Annotation?: any[];
26 | },
27 | ) {
28 | super({ Annotation });
29 |
30 | this.Name = Name;
31 | this.EntityType = EntityType;
32 | this.NavigationPropertyBinding = NavigationPropertyBinding?.map(
33 | (n) => new CsdlNavigationPropertyBinding(n),
34 | );
35 | this.IncludeInServiceDocument = IncludeInServiceDocument;
36 | }
37 |
38 | override toJson() {
39 | const json: { [key: string]: any } = {
40 | ...super.toJson(),
41 | Name: this.Name,
42 | EntityType: this.EntityType,
43 | };
44 | if (
45 | Array.isArray(this.NavigationPropertyBinding) &&
46 | this.NavigationPropertyBinding.length > 0
47 | ) {
48 | json['NavigationPropertyBinding'] = this.NavigationPropertyBinding.map(
49 | (n) => n.toJson(),
50 | );
51 | }
52 | if (this.IncludeInServiceDocument !== undefined) {
53 | json['IncludeInServiceDocument'] = this.IncludeInServiceDocument;
54 | }
55 | return json;
56 | }
57 |
58 | name() {
59 | return `${this.Name}`;
60 | }
61 |
62 | namespace() {
63 | return `${this.container.namespace()}`;
64 | }
65 |
66 | fullName() {
67 | return `${this.container.namespace()}.${this.Name}`;
68 | }
69 |
70 | override toConfig(): ODataEntitySetConfig {
71 | return {
72 | ...super.toConfig(),
73 | name: this.Name,
74 | entityType: this.EntityType,
75 | service: {},
76 | } as ODataEntitySetConfig;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/metadata/csdl/csdl-enum-type.ts:
--------------------------------------------------------------------------------
1 | import { ODataEnumTypeConfig, ODataEnumTypeFieldConfig } from '../../types';
2 | import { CsdlAnnotable } from './csdl-annotation';
3 | import type { CsdlSchema } from './csdl-schema';
4 |
5 | export class CsdlEnumType extends CsdlAnnotable {
6 | Name: string;
7 | Member: CsdlMember[];
8 | UnderlyingType?: string;
9 | IsFlags?: boolean;
10 | constructor(
11 | private schema: CsdlSchema,
12 | {
13 | Name,
14 | Member,
15 | UnderlyingType,
16 | IsFlags,
17 | Annotation,
18 | }: {
19 | Name: string;
20 | Member: any[];
21 | UnderlyingType?: string;
22 | IsFlags?: boolean;
23 | Annotation?: any[];
24 | },
25 | ) {
26 | super({ Annotation });
27 | this.Name = Name;
28 | this.Member = Member.map((m) => new CsdlMember(m));
29 | this.UnderlyingType = UnderlyingType;
30 | this.IsFlags = IsFlags;
31 | }
32 |
33 | override toJson() {
34 | const json: { [key: string]: any } = {
35 | ...super.toJson(),
36 | Name: this.Name,
37 | Member: this.Member.map((m) => m.toJson()),
38 | };
39 | if (this.UnderlyingType !== undefined) {
40 | json['UnderlyingType'] = this.UnderlyingType;
41 | }
42 | if (this.IsFlags !== undefined) {
43 | json['IsFlags'] = this.IsFlags;
44 | }
45 | return json;
46 | }
47 |
48 | name() {
49 | return `${this.Name}`;
50 | }
51 |
52 | namespace() {
53 | return `${this.schema.Namespace}`;
54 | }
55 |
56 | fullName() {
57 | return `${this.schema.Namespace}.${this.Name}`;
58 | }
59 |
60 | override toConfig(base?: Partial): ODataEnumTypeConfig {
61 | return {
62 | ...super.toConfig(),
63 | name: this.Name,
64 | fields: this.Member.reduce(
65 | (acc, m) => ({
66 | ...acc,
67 | [m.Name]: m.toConfig(),
68 | }),
69 | {},
70 | ),
71 | flags: this.IsFlags,
72 | } as ODataEnumTypeConfig;
73 | }
74 | }
75 |
76 | export class CsdlMember extends CsdlAnnotable {
77 | Name: string;
78 | Value?: number;
79 | constructor({
80 | Name,
81 | Value,
82 | Annotation,
83 | }: {
84 | Name: string;
85 | Value?: number;
86 | Annotation?: any[];
87 | }) {
88 | super({ Annotation });
89 | this.Name = Name;
90 | this.Value = Value;
91 | }
92 |
93 | override toJson() {
94 | const json: { [key: string]: any } = { ...super.toJson(), Name: this.Name };
95 | if (this.Value !== undefined) {
96 | json['Value'] = this.Value;
97 | }
98 | return json;
99 | }
100 |
101 | override toConfig(
102 | base?: Partial,
103 | ): ODataEnumTypeFieldConfig {
104 | const config: { [key: string]: any } = {
105 | ...super.toConfig(),
106 | value: this.Value,
107 | };
108 | return config as ODataEnumTypeFieldConfig;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/metadata/csdl/csdl-navigation-property-binding.ts:
--------------------------------------------------------------------------------
1 | export class CsdlNavigationPropertyBinding {
2 | Path: string;
3 | Target: string;
4 |
5 | constructor({ Path, Target }: { Path: string; Target: string }) {
6 | this.Path = Path;
7 | this.Target = Target;
8 | }
9 |
10 | toJson() {
11 | return {
12 | Path: this.Path,
13 | Target: this.Target,
14 | };
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/metadata/csdl/csdl-reference.ts:
--------------------------------------------------------------------------------
1 | import { ODataReferenceConfig } from '../../types';
2 | import { CsdlAnnotable } from './csdl-annotation';
3 |
4 | export class CsdlReference extends CsdlAnnotable {
5 | Uri: string;
6 | Include?: CsdlInclude[];
7 | IncludeAnnotations?: CsdlIncludeAnnotations[];
8 | constructor({
9 | Uri,
10 | Include,
11 | IncludeAnnotations,
12 | Annotation,
13 | }: {
14 | Uri: string;
15 | Include?: any[];
16 | IncludeAnnotations?: any[];
17 | Annotation?: any[];
18 | }) {
19 | super({ Annotation });
20 | this.Uri = Uri;
21 | this.Include = Include?.map((i) => new CsdlInclude(i));
22 | this.IncludeAnnotations = IncludeAnnotations?.map(
23 | (i) => new CsdlIncludeAnnotations(i),
24 | );
25 | }
26 |
27 | override toJson() {
28 | const json: { [key: string]: any } = { ...super.toJson(), Uri: this.Uri };
29 | if (Array.isArray(this.Include) && this.Include.length > 0) {
30 | json['Include'] = this.Include.map((i) => i.toJson());
31 | }
32 | if (
33 | Array.isArray(this.IncludeAnnotations) &&
34 | this.IncludeAnnotations.length > 0
35 | ) {
36 | json['IncludeAnnotations'] = this.IncludeAnnotations.map((i) =>
37 | i.toJson(),
38 | );
39 | }
40 | return json;
41 | }
42 |
43 | override toConfig(base?: Partial) {
44 | return {
45 | ...super.toConfig(),
46 | uri: this.Uri,
47 | includes: this.Include?.map((i) => i.toConfig()),
48 | includeAnnotations: this.IncludeAnnotations?.map((i) => i.toConfig()),
49 | } as ODataReferenceConfig;
50 | }
51 | }
52 |
53 | export class CsdlInclude {
54 | Namespace: string;
55 | Alias?: string;
56 | constructor({ Namespace, Alias }: { Namespace: string; Alias?: string }) {
57 | this.Namespace = Namespace;
58 | this.Alias = Alias;
59 | }
60 |
61 | toJson() {
62 | return {
63 | Namespace: this.Namespace,
64 | Alias: this.Alias,
65 | };
66 | }
67 |
68 | toConfig() {
69 | return {
70 | namespace: this.Namespace,
71 | alias: this.Alias,
72 | };
73 | }
74 | }
75 |
76 | export class CsdlIncludeAnnotations {
77 | TermNamespace: string;
78 | Qualifier?: string;
79 | TargetNamespace?: string;
80 | constructor({
81 | TermNamespace,
82 | Qualifier,
83 | TargetNamespace,
84 | }: {
85 | TermNamespace: string;
86 | Qualifier?: string;
87 | TargetNamespace?: string;
88 | }) {
89 | this.TermNamespace = TermNamespace;
90 | this.Qualifier = Qualifier;
91 | this.TargetNamespace = TargetNamespace;
92 | }
93 |
94 | toJson() {
95 | return {
96 | TermNamespace: this.TermNamespace,
97 | Qualifier: this.Qualifier,
98 | TargetNamespace: this.TargetNamespace,
99 | };
100 | }
101 |
102 | toConfig() {
103 | return {
104 | termNamespace: this.TermNamespace,
105 | qualifier: this.Qualifier,
106 | targetNamespace: this.TargetNamespace,
107 | };
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/metadata/csdl/csdl-singleton.ts:
--------------------------------------------------------------------------------
1 | import { CsdlAnnotable } from './csdl-annotation';
2 | import type { CsdlEntityContainer } from './csdl-entity-container';
3 | import { CsdlNavigationPropertyBinding } from './csdl-navigation-property-binding';
4 |
5 | export class CsdlSingleton extends CsdlAnnotable {
6 | Name: string;
7 | Type: string;
8 | NavigationPropertyBindings?: CsdlNavigationPropertyBinding[];
9 |
10 | constructor(
11 | private container: CsdlEntityContainer,
12 | {
13 | Name,
14 | Type,
15 | NavigationPropertyBindings,
16 | Annotation,
17 | }: {
18 | Name: string;
19 | Type: string;
20 | NavigationPropertyBindings?: any[];
21 | Annotation?: any[];
22 | },
23 | ) {
24 | super({ Annotation });
25 | this.Name = Name;
26 | this.Type = Type;
27 | this.NavigationPropertyBindings = NavigationPropertyBindings?.map(
28 | (n) => new CsdlNavigationPropertyBinding(n),
29 | );
30 | }
31 |
32 | override toJson() {
33 | const json: { [key: string]: any } = {
34 | ...super.toJson(),
35 | Name: this.Name,
36 | Type: this.Type,
37 | };
38 | if (
39 | Array.isArray(this.NavigationPropertyBindings) &&
40 | this.NavigationPropertyBindings.length > 0
41 | ) {
42 | json['NavigationPropertyBindings'] = this.NavigationPropertyBindings.map(
43 | (n) => n.toJson(),
44 | );
45 | }
46 | return json;
47 | }
48 |
49 | name() {
50 | return `${this.Name}`;
51 | }
52 |
53 | namespace() {
54 | return `${this.container.namespace()}`;
55 | }
56 |
57 | fullName() {
58 | return `${this.container.namespace()}.${this.Name}`;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/metadata/csdl/csdl-type-definition.ts:
--------------------------------------------------------------------------------
1 | import { CsdlAnnotable, CsdlAnnotation } from './csdl-annotation';
2 | import type { CsdlSchema } from './csdl-schema';
3 |
4 | export class CsdlTypeDefinition extends CsdlAnnotable {
5 | public Name: string;
6 | public UnderlayingType: string;
7 | public MaxLength?: number;
8 | public Precision?: number;
9 | public Scale?: number;
10 | public Unicode?: boolean;
11 | public SRID?: string;
12 |
13 | constructor(
14 | private schema: CsdlSchema,
15 | {
16 | Name,
17 | UnderlayingType,
18 | MaxLength,
19 | Precision,
20 | Scale,
21 | Unicode,
22 | SRID,
23 | Annotation,
24 | }: {
25 | Name: string;
26 | UnderlayingType: string;
27 | MaxLength?: number;
28 | Precision?: number;
29 | Scale?: number;
30 | Unicode?: boolean;
31 | SRID?: string;
32 | Annotation?: CsdlAnnotation[];
33 | },
34 | ) {
35 | super({ Annotation });
36 | this.Name = Name;
37 | this.UnderlayingType = UnderlayingType;
38 | this.MaxLength = MaxLength;
39 | this.Precision = Precision;
40 | this.Scale = Scale;
41 | this.Unicode = Unicode;
42 | this.SRID = SRID;
43 | }
44 |
45 | override toJson() {
46 | const json: { [key: string]: any } = {
47 | ...super.toJson(),
48 | Name: this.Name,
49 | UnderlayingType: this.UnderlayingType,
50 | };
51 | if (this.MaxLength !== undefined) {
52 | json['MaxLength'] = this.MaxLength;
53 | }
54 | if (this.Precision !== undefined) {
55 | json['Precision'] = this.Precision;
56 | }
57 | if (this.Scale !== undefined) {
58 | json['Scale'] = this.Scale;
59 | }
60 | if (this.Unicode !== undefined) {
61 | json['Unicode'] = this.Unicode;
62 | }
63 | if (this.SRID !== undefined) {
64 | json['SRID'] = this.SRID;
65 | }
66 | return json;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/metadata/index.ts:
--------------------------------------------------------------------------------
1 | export * from './metadata';
2 | export * from './parser';
3 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/metadata/metadata.ts:
--------------------------------------------------------------------------------
1 | import { CsdlAction, CsdlFunction } from './csdl/csdl-function-action';
2 | import { CsdlReference } from './csdl/csdl-reference';
3 | import { CsdlSchema } from './csdl/csdl-schema';
4 | import { ODataApiConfig, ODataVersion } from '../types';
5 |
6 | export class ODataMetadata {
7 | Version: string;
8 | References: CsdlReference[];
9 | Schemas: CsdlSchema[];
10 | constructor(Version: string, References: any[], Schemas: any[]) {
11 | this.Version = Version;
12 | this.References = References?.map((r) => new CsdlReference(r));
13 | this.Schemas = Schemas?.map((s) => new CsdlSchema(s));
14 | }
15 |
16 | toConfig(base?: Partial): ODataApiConfig {
17 | return {
18 | ...base,
19 | version: base?.version ?? (this.Version as ODataVersion),
20 | schemas: (this.Schemas ?? []).map((ms) =>
21 | ms.toConfig(base?.schemas?.find((cs) => cs.namespace === ms.Namespace)),
22 | ),
23 | references: (this.References ?? []).map((mr) =>
24 | mr.toConfig(base?.references?.find((cs) => cs.uri === mr.Uri)),
25 | ),
26 | } as ODataApiConfig;
27 | }
28 |
29 | toJson() {
30 | return {
31 | Version: this.Version,
32 | References: this.References.map((r) => r.toJson()),
33 | Schemas: this.Schemas.map((s) => s.toJson()),
34 | };
35 | }
36 |
37 | functions() {
38 | return this.Schemas.reduce((acc, s) => {
39 | return [...acc, ...(s.Function ?? [])];
40 | }, [] as CsdlFunction[]);
41 | }
42 |
43 | actions() {
44 | return this.Schemas.reduce((acc, s) => {
45 | return [...acc, ...(s.Action ?? [])];
46 | }, [] as CsdlAction[]);
47 | }
48 |
49 | static fromJson(json: any): ODataMetadata {
50 | return new ODataMetadata(json.Version, json.References, json.Schemas);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/models/index.ts:
--------------------------------------------------------------------------------
1 | export * from './options';
2 | export * from './model';
3 | export * from './collection';
4 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/module.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from '@angular/common';
2 | import { HttpClientModule } from '@angular/common/http';
3 | import {
4 | EnvironmentProviders,
5 | InjectionToken,
6 | ModuleWithProviders,
7 | NgModule,
8 | Provider,
9 | makeEnvironmentProviders,
10 | } from '@angular/core';
11 | import { ODataClient } from './client';
12 | import { ODataConfigLoader, ODataConfigSyncLoader } from './loaders';
13 | import { ODataServiceFactory } from './services/index';
14 | import { ODataApiConfig } from './types';
15 |
16 | export interface PassedInitialConfig {
17 | config?: ODataApiConfig | ODataApiConfig[];
18 | loader?: Provider;
19 | }
20 |
21 | export const ODATA_CONFIG = new InjectionToken('odata.config');
22 |
23 | export function createSyncLoader(passedConfig: PassedInitialConfig) {
24 | return new ODataConfigSyncLoader(passedConfig.config!);
25 | }
26 |
27 | // Standalone version
28 | export function provideODataClient(
29 | passedConfig: PassedInitialConfig,
30 | ): EnvironmentProviders {
31 | return makeEnvironmentProviders([
32 | { provide: ODATA_CONFIG, useValue: passedConfig },
33 | passedConfig?.loader ?? {
34 | provide: ODataConfigLoader,
35 | useFactory: createSyncLoader,
36 | deps: [ODATA_CONFIG],
37 | },
38 | ODataClient,
39 | ODataServiceFactory,
40 | ]);
41 | }
42 |
43 | // Module version
44 | @NgModule({
45 | imports: [CommonModule, HttpClientModule],
46 | providers: [ODataClient, ODataServiceFactory],
47 | })
48 | export class ODataModule {
49 | static forRoot(
50 | passedConfig: PassedInitialConfig,
51 | ): ModuleWithProviders {
52 | return {
53 | ngModule: ODataModule,
54 | providers: [
55 | // Make the ODATA_CONFIG available through injection
56 | { provide: ODATA_CONFIG, useValue: passedConfig },
57 |
58 | // Create the loader: Either the one getting passed or a sync one
59 | passedConfig?.loader ?? {
60 | provide: ODataConfigLoader,
61 | useFactory: createSyncLoader,
62 | deps: [ODATA_CONFIG],
63 | },
64 | ODataClient,
65 | ODataServiceFactory,
66 | ],
67 | };
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/index.ts:
--------------------------------------------------------------------------------
1 | export * from './query';
2 | export * from './path';
3 | export * from './request';
4 | export * from './resource';
5 | export * from './types';
6 | export * from './response';
7 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/options.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CacheCacheability,
3 | ODataMetadataType,
4 | ODataVersion,
5 | ParserOptions,
6 | ResponseOptions,
7 | } from '../types';
8 | import {
9 | DEFAULT_VERSION,
10 | MAX_AGE,
11 | VERSION_2_0,
12 | VERSION_3_0,
13 | VERSION_4_0,
14 | } from '../constants';
15 |
16 | import { ODataHelper } from '../helper';
17 |
18 | export class ODataResponseOptions implements ResponseOptions {
19 | version: ODataVersion;
20 | streaming?: boolean;
21 | // OData
22 | metadata?: ODataMetadataType;
23 | ieee754Compatible?: boolean;
24 | // Location
25 | location?: string;
26 | // Cache
27 | cacheability?: 'public' | 'private' | 'no-cache' | 'no-store';
28 | maxAge?: number;
29 |
30 | constructor(config: ParserOptions) {
31 | this.version = config.version || DEFAULT_VERSION;
32 | }
33 |
34 | get helper() {
35 | return ODataHelper[this.version];
36 | }
37 |
38 | clone() {
39 | return new ODataResponseOptions(this);
40 | }
41 |
42 | setFeatures(features: string) {
43 | features.split(';').forEach((o) => {
44 | let [k, v] = o.split('=');
45 | switch (k.trim()) {
46 | case 'odata.metadata':
47 | this.metadata = v as ODataMetadataType;
48 | break;
49 | case 'odata.streaming':
50 | this.streaming = v == 'true';
51 | break;
52 | case 'IEEE754Compatible':
53 | this.ieee754Compatible = v == 'true';
54 | break;
55 | }
56 | });
57 | }
58 |
59 | setVersion(version: string) {
60 | const value = version.replace(/\;/g, '').trim();
61 | if ([VERSION_2_0, VERSION_3_0, VERSION_4_0].indexOf(value) !== -1)
62 | this.version = value as ODataVersion;
63 | }
64 |
65 | setLocation(location: string) {
66 | // TODO: resolve location?
67 | this.location = location;
68 | }
69 |
70 | setPreferenceApplied(preference: string) {
71 | preference.split(',').forEach((prefer) => {
72 | // TODO: resolve preference
73 | });
74 | }
75 |
76 | setCache(cacheControl: string) {
77 | cacheControl.split(',').forEach((directive) => {
78 | if (directive.startsWith(MAX_AGE)) {
79 | let maxAge = Number(directive.split('=')[1]);
80 | if (!Number.isNaN(maxAge)) this.maxAge = maxAge;
81 | }
82 | if (
83 | ['public', 'private', 'no-cache', 'no-store'].indexOf(directive) !== -1
84 | ) {
85 | this.cacheability = directive as CacheCacheability;
86 | }
87 | });
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/path/handlers.ts:
--------------------------------------------------------------------------------
1 | import { PathSegment } from '../../types';
2 | import { Types } from '../../utils';
3 | import { EntityKey } from '../resource';
4 | import { ODataPathSegments, ODataSegment } from './segments';
5 |
6 | export class SegmentHandler {
7 | constructor(private segment: ODataSegment) {}
8 | get name() {
9 | return this.segment.name;
10 | }
11 | outgoingType(value?: string) {
12 | if (value !== undefined) this.segment.outgoingType = value;
13 | return this.segment.outgoingType;
14 | }
15 | incomingType(value?: string) {
16 | if (value !== undefined) this.segment.incomingType = value;
17 | return this.segment.incomingType;
18 | }
19 | bindingType(value?: string) {
20 | if (value !== undefined) this.segment.bindingType = value;
21 | return this.segment.bindingType;
22 | }
23 | path(value?: string) {
24 | if (value !== undefined) this.segment.path = value;
25 | return this.segment.path;
26 | }
27 | key(value?: EntityKey) {
28 | if (value !== undefined) this.segment.key = value;
29 | return this.segment.key as EntityKey;
30 | }
31 | hasKey() {
32 | return !Types.isEmpty(this.segment.key);
33 | }
34 | clearKey() {
35 | delete this.segment.key;
36 | }
37 | parameters(value?: T) {
38 | if (value !== undefined) this.segment.parameters = value;
39 | return this.segment.parameters as T;
40 | }
41 | hasParameters() {
42 | return !Types.isEmpty(this.segment.parameters);
43 | }
44 | clearParameters() {
45 | delete this.segment.parameters;
46 | }
47 | }
48 |
49 | export class ODataPathSegmentsHandler {
50 | constructor(protected segments: ODataPathSegments) {}
51 | entitySet() {
52 | return this.segments.get(PathSegment.entitySet);
53 | }
54 | singleton() {
55 | return this.segments.get(PathSegment.singleton);
56 | }
57 | action() {
58 | return this.segments.get(PathSegment.action);
59 | }
60 | function() {
61 | return this.segments.get(PathSegment.function);
62 | }
63 | keys(values?: (EntityKey | undefined)[]) {
64 | return this.segments.keys(values);
65 | }
66 | property() {
67 | return this.segments.get(PathSegment.property);
68 | }
69 | navigationProperty() {
70 | return this.segments.get(PathSegment.navigationProperty);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/path/index.ts:
--------------------------------------------------------------------------------
1 | export * from './segments';
2 | export * from './handlers';
3 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/base.ts:
--------------------------------------------------------------------------------
1 | import { Parser, ParserOptions } from '../../../types';
2 | import { Types } from '../../../utils';
3 | import { QueryCustomType } from '../builder';
4 | import { Renderable } from './syntax';
5 |
6 | export abstract class Expression implements Renderable {
7 | protected _children: Renderable[];
8 | constructor({
9 | children,
10 | }: {
11 | children?: Renderable[];
12 | } = {}) {
13 | this._children = children || [];
14 | }
15 |
16 | get [Symbol.toStringTag]() {
17 | return 'Expression';
18 | }
19 |
20 | abstract render({
21 | aliases,
22 | escape,
23 | prefix,
24 | parser,
25 | options,
26 | }: {
27 | aliases?: QueryCustomType[];
28 | escape?: boolean;
29 | prefix?: string;
30 | parser?: Parser;
31 | options?: ParserOptions;
32 | }): string;
33 |
34 | abstract clone(): Expression;
35 |
36 | children() {
37 | return [...this._children];
38 | }
39 |
40 | length() {
41 | return this._children.length;
42 | }
43 |
44 | toJson() {
45 | return {
46 | $type: Types.rawType(this),
47 | children: this._children.map((c) => c.toJson()),
48 | };
49 | }
50 |
51 | resolve(parser: any) {
52 | return parser;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/compute.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComputeExpression } from './compute';
2 |
3 | describe('OData compute builder', () => {
4 | interface Pet {
5 | Id?: number;
6 | Name?: string;
7 | Age?: number;
8 | Person?: Person;
9 | }
10 |
11 | interface Model {
12 | Id?: number;
13 | }
14 |
15 | interface Car {
16 | Id?: number;
17 | Model?: Model;
18 | Year?: number;
19 | }
20 |
21 | interface Person {
22 | Id?: number;
23 | Name?: string;
24 | Age?: number;
25 | IsCorrect?: boolean;
26 | EditedOn?: Date;
27 | CreatedOn?: Date;
28 | BornOn?: Date;
29 | Car?: Car;
30 | Pets?: Pet[];
31 | }
32 |
33 | describe('base condition', () => {
34 | it('field', () => {
35 | const compare1 = ComputeExpression.factory(({ e, t }) =>
36 | e().field('Class', ({ f }) => f.year(t.BornOn)),
37 | );
38 |
39 | expect(compare1.render()).toBe('year(BornOn) as Class');
40 | });
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/compute.ts:
--------------------------------------------------------------------------------
1 | import { Parser, ParserOptions } from '../../../types';
2 | import { QueryCustomType } from '../builder';
3 | import { Expression } from './base';
4 | import {
5 | FieldFactory,
6 | functions,
7 | ODataFunctions,
8 | ODataOperators,
9 | operators,
10 | Renderable,
11 | RenderableFactory,
12 | } from './syntax';
13 |
14 | export type ComputeExpressionBuilder = {
15 | t: Required;
16 | e: () => ComputeExpression;
17 | };
18 | export class ComputeExpression extends Expression {
19 | protected names: string[];
20 | constructor({
21 | children,
22 | names,
23 | }: {
24 | children?: Renderable[];
25 | names?: string[];
26 | } = {}) {
27 | super({ children });
28 | this.names = names ?? [];
29 | }
30 |
31 | override get [Symbol.toStringTag]() {
32 | return 'ComputeExpression';
33 | }
34 |
35 | static factory(
36 | opts: (
37 | builder: ComputeExpressionBuilder,
38 | current: ComputeExpression,
39 | ) => ComputeExpression,
40 | current?: ComputeExpression,
41 | ): ComputeExpression {
42 | return opts(
43 | {
44 | t: FieldFactory>(),
45 | e: () => new ComputeExpression(),
46 | },
47 | current ?? new ComputeExpression(),
48 | ) as ComputeExpression;
49 | }
50 |
51 | override toJson() {
52 | const json = super.toJson();
53 | return Object.assign(json, {
54 | names: this.names,
55 | });
56 | }
57 |
58 | static fromJson(json: { [name: string]: any }): ComputeExpression {
59 | return new ComputeExpression({
60 | children: json['children'].map((c: any) => RenderableFactory(c)),
61 | names: json['names'],
62 | });
63 | }
64 |
65 | render({
66 | aliases,
67 | escape,
68 | prefix,
69 | parser,
70 | options,
71 | }: {
72 | aliases?: QueryCustomType[];
73 | escape?: boolean;
74 | prefix?: string;
75 | parser?: Parser;
76 | options?: ParserOptions;
77 | } = {}): string {
78 | const children = this._children.map((n) =>
79 | n.render({ aliases, escape, prefix, parser, options }),
80 | );
81 | return this.names
82 | .map((name, index) => `${children[index]} as ${name}`)
83 | .join(',');
84 | }
85 |
86 | clone() {
87 | return new ComputeExpression({
88 | children: this._children.map((c) => c.clone()),
89 | names: [...this.names],
90 | });
91 | }
92 |
93 | private _add(name: string, node: Renderable): ComputeExpression {
94 | this.names.push(name);
95 | this._children.push(node);
96 | return this;
97 | }
98 |
99 | field(
100 | name: string,
101 | opts: (e: { o: ODataOperators; f: ODataFunctions }) => Renderable,
102 | ): ComputeExpression {
103 | const node = opts({
104 | o: operators as ODataOperators,
105 | f: functions as ODataFunctions,
106 | });
107 | return this._add(name, node);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/count.spec.ts:
--------------------------------------------------------------------------------
1 | import { CountExpression } from './count';
2 |
3 | describe('OData orderBy builder', () => {
4 | interface Pet {
5 | Id?: number;
6 | Name?: string;
7 | Age?: number;
8 | Person?: Person;
9 | }
10 |
11 | interface Model {
12 | Id?: number;
13 | Name?: string;
14 | }
15 |
16 | interface Car {
17 | Id?: number;
18 | Model?: Model;
19 | Year?: number;
20 | }
21 |
22 | interface Person {
23 | Id?: number;
24 | Name?: string;
25 | Age?: number;
26 | IsCorrect?: boolean;
27 | EditedOn?: boolean;
28 | CreatedOn?: boolean;
29 | Car?: Car;
30 | Pets?: Pet[];
31 | }
32 |
33 | describe('base condition', () => {
34 | describe('as factory function', () => {
35 | it('count', () => {
36 | const compare1 = CountExpression.factory(({ e, t }) =>
37 | e().field(t.Pets),
38 | );
39 |
40 | expect(compare1.render()).toBe('Pets/$count');
41 | });
42 |
43 | it('count filter', () => {
44 | const compare1 = CountExpression.factory(({ e, t }) =>
45 | e().field(t.Pets, ({ f }) =>
46 | f.filter(({ e, t }) => e().gt(t.Age, 3)),
47 | ),
48 | );
49 |
50 | expect(compare1.render()).toBe('Pets/$count($filter=Age gt 3)');
51 | });
52 | });
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/expand.spec.ts:
--------------------------------------------------------------------------------
1 | import { ExpandExpression } from './expand';
2 |
3 | describe('OData search builder', () => {
4 | interface Pet {
5 | Id?: number;
6 | Name?: string;
7 | Age?: number;
8 | Person?: Person;
9 | }
10 |
11 | interface Model {
12 | Id?: number;
13 | Name?: string;
14 | }
15 |
16 | interface Car {
17 | Id?: number;
18 | Model?: Model;
19 | Year?: number;
20 | }
21 |
22 | interface Person {
23 | Id?: number;
24 | Name?: string;
25 | Age?: number;
26 | IsCorrect?: boolean;
27 | EditedOn?: boolean;
28 | CreatedOn?: boolean;
29 | Car?: Car;
30 | Pets?: Pet[];
31 | }
32 |
33 | describe('base condition', () => {
34 | describe('as factory function', () => {
35 | it('field', () => {
36 | const compare1 = ExpandExpression.factory(({ e, t }) =>
37 | e().field(t.Car),
38 | );
39 |
40 | expect(compare1.render()).toBe('Car');
41 | });
42 |
43 | it('navigation', () => {
44 | const compare1 = ExpandExpression.factory(({ e, t }) =>
45 | e().field(t.Car?.Model),
46 | );
47 |
48 | expect(compare1.render()).toBe('Car/Model');
49 | });
50 | });
51 | });
52 |
53 | describe('nested condition', () => {
54 | describe('as factory function', () => {
55 | it('field', () => {
56 | const compare1 = ExpandExpression.factory(({ e, t }) =>
57 | e().field(t.Car, (f) => {
58 | f.expand(({ e, t }) => e().field(t.Model));
59 | f.skip(1);
60 | f.filter(({ e, t }) => e().eq(t.Year, 2000));
61 | }),
62 | );
63 |
64 | expect(compare1.render()).toBe(
65 | 'Car($expand=Model;$filter=Year eq 2000;$skip=1)',
66 | );
67 | });
68 |
69 | it('navigation', () => {
70 | const compare1 = ExpandExpression.factory(({ e, t }) =>
71 | e().field(t.Car.Model!, (f) => {
72 | f.filter(({ e, t }) => e().in(t.Name, ['BMW', 'Audi']));
73 | f.skip(1);
74 | f.top(1);
75 | }),
76 | );
77 |
78 | expect(compare1.render()).toBe(
79 | "Car/Model($filter=Name in ('BMW','Audi');$skip=1;$top=1)",
80 | );
81 | });
82 | });
83 | });
84 | });
85 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/index.ts:
--------------------------------------------------------------------------------
1 | export * from './base';
2 | export * from './compute';
3 | export * from './apply';
4 | export * from './filter';
5 | export * from './orderby';
6 | export * from './search';
7 | export * from './select';
8 | export * from './syntax';
9 | export * from './expand';
10 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/orderby.spec.ts:
--------------------------------------------------------------------------------
1 | import { OrderByExpression } from './orderby';
2 |
3 | describe('OData orderBy builder', () => {
4 | interface Pet {
5 | Id?: number;
6 | Name?: string;
7 | Age?: number;
8 | Person?: Person;
9 | }
10 |
11 | interface Model {
12 | Id?: number;
13 | Name?: string;
14 | }
15 |
16 | interface Car {
17 | Id?: number;
18 | Model?: Model;
19 | Year?: number;
20 | }
21 |
22 | interface Person {
23 | Id?: number;
24 | Name?: string;
25 | Age?: number;
26 | IsCorrect?: boolean;
27 | EditedOn?: boolean;
28 | CreatedOn?: boolean;
29 | Car?: Car;
30 | Pets?: Pet[];
31 | }
32 |
33 | describe('base condition', () => {
34 | describe('as factory function', () => {
35 | it('asc', () => {
36 | const compare1 = OrderByExpression.factory(({ e, t }) =>
37 | e().ascending(t.Age),
38 | );
39 |
40 | expect(compare1.render()).toBe('Age asc');
41 | });
42 |
43 | it('desc', () => {
44 | const compare1 = OrderByExpression.factory(({ e, t }) =>
45 | e().descending(t.Age),
46 | );
47 |
48 | expect(compare1.render()).toBe('Age desc');
49 | });
50 | });
51 |
52 | describe('combination e().ascending(...).descending(...)', () => {
53 | it('asc,desc', () => {
54 | const compare = OrderByExpression.factory(({ e, t }) =>
55 | e().ascending(t.Age).descending(t.CreatedOn),
56 | );
57 |
58 | expect(compare.render()).toBe('Age asc,CreatedOn desc');
59 | });
60 | });
61 |
62 | describe('navigate main', () => {
63 | it('navigate', () => {
64 | const compare1 = OrderByExpression.factory(({ e, t }) =>
65 | e().ascending(t.Car!.Year),
66 | );
67 | expect(compare1.render()).toBe('Car/Year asc');
68 | });
69 |
70 | it('combination navigate', () => {
71 | const compare1 = OrderByExpression.factory(({ e, t }) =>
72 | e().ascending(t.Car!.Year).descending(t.Car!.Model!.Name),
73 | );
74 | expect(compare1.render()).toBe('Car/Year asc,Car/Model/Name desc');
75 | });
76 | });
77 | });
78 | });
79 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/orderby.ts:
--------------------------------------------------------------------------------
1 | import { Parser, ParserOptions } from '../../../types';
2 | import { Types } from '../../../utils';
3 | import { QueryCustomType } from '../builder';
4 | import { Expression } from './base';
5 | import { render, FieldFactory, Renderable, RenderableFactory } from './syntax';
6 |
7 | export type OrderAttribute = 'asc' | 'desc';
8 | export class OrderByField implements Renderable {
9 | constructor(
10 | protected field: Renderable,
11 | protected order: OrderAttribute,
12 | ) {}
13 |
14 | get [Symbol.toStringTag]() {
15 | return 'OrderByField';
16 | }
17 |
18 | toJson() {
19 | return {
20 | $type: Types.rawType(this),
21 | field: this.field.toJson(),
22 | order: this.order,
23 | };
24 | }
25 |
26 | render({
27 | aliases,
28 | escape,
29 | prefix,
30 | parser,
31 | options,
32 | }: {
33 | aliases?: QueryCustomType[];
34 | escape?: boolean;
35 | prefix?: string;
36 | parser?: Parser;
37 | options?: ParserOptions;
38 | }): string {
39 | return `${render(this.field, {
40 | aliases,
41 | escape,
42 | prefix,
43 | parser,
44 | options,
45 | })} ${this.order}`;
46 | }
47 |
48 | clone() {
49 | return new OrderByField(
50 | typeof this.field !== 'string' ? this.field.clone() : this.field,
51 | this.order,
52 | );
53 | }
54 |
55 | resolve(parser: any) {
56 | return parser;
57 | }
58 | }
59 |
60 | export type OrderByExpressionBuilder = {
61 | t: Required;
62 | e: () => OrderByExpression;
63 | };
64 |
65 | export class OrderByExpression extends Expression {
66 | constructor({
67 | children,
68 | }: {
69 | children?: Renderable[];
70 | } = {}) {
71 | super({ children });
72 | }
73 |
74 | override get [Symbol.toStringTag]() {
75 | return 'OrderByExpression';
76 | }
77 |
78 | static factory(
79 | opts: (
80 | builder: OrderByExpressionBuilder,
81 | current: OrderByExpression,
82 | ) => OrderByExpression,
83 | current?: OrderByExpression,
84 | ): OrderByExpression {
85 | return opts(
86 | {
87 | t: FieldFactory>(),
88 | e: () => new OrderByExpression(),
89 | },
90 | current ?? new OrderByExpression(),
91 | ) as OrderByExpression;
92 | }
93 |
94 | private _add(node: Renderable): OrderByExpression {
95 | this._children.push(node);
96 | return this;
97 | }
98 |
99 | override toJson() {
100 | const json = super.toJson();
101 | return Object.assign(json, {});
102 | }
103 |
104 | static fromJson(json: { [name: string]: any }): OrderByExpression {
105 | return new OrderByExpression({
106 | children: json['children'].map((c: any) => RenderableFactory(c)),
107 | });
108 | }
109 |
110 | render({
111 | aliases,
112 | escape,
113 | prefix,
114 | parser,
115 | options,
116 | }: {
117 | aliases?: QueryCustomType[];
118 | escape?: boolean;
119 | prefix?: string;
120 | parser?: Parser;
121 | options?: ParserOptions;
122 | } = {}): string {
123 | let content = this._children
124 | .map((n) => n.render({ aliases, escape, prefix, parser, options }))
125 | .join(`,`);
126 | return content;
127 | }
128 |
129 | clone() {
130 | return new OrderByExpression({
131 | children: this._children.map((c) => c.clone()),
132 | });
133 | }
134 |
135 | ascending(field: any) {
136 | return this._add(new OrderByField(field, 'asc'));
137 | }
138 |
139 | descending(field: any) {
140 | return this._add(new OrderByField(field, 'desc'));
141 | }
142 |
143 | combine(expression: OrderByExpression): OrderByExpression {
144 | return this._add(expression);
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/search.spec.ts:
--------------------------------------------------------------------------------
1 | import { SearchExpression } from './search';
2 |
3 | describe('OData search builder', () => {
4 | interface Pet {
5 | Id?: number;
6 | Name?: string;
7 | Age?: number;
8 | Person?: Person;
9 | }
10 |
11 | interface Model {
12 | Id?: number;
13 | Name?: string;
14 | }
15 |
16 | interface Car {
17 | Id?: number;
18 | Model?: Model;
19 | Year?: number;
20 | }
21 |
22 | interface Person {
23 | Id?: number;
24 | Name?: string;
25 | Age?: number;
26 | IsCorrect?: boolean;
27 | EditedOn?: boolean;
28 | CreatedOn?: boolean;
29 | Car?: Car;
30 | Pets?: Pet[];
31 | }
32 |
33 | describe('base condition', () => {
34 | describe('as factory function', () => {
35 | it('term', () => {
36 | const compare1 = SearchExpression.factory(({ e }) =>
37 | e().term('John'),
38 | );
39 |
40 | expect(compare1.render()).toBe('John');
41 | });
42 | });
43 |
44 | describe('combination e().and(...).or(...)', () => {
45 | it('and,or', () => {
46 | const compare = SearchExpression.factory(({ e }) =>
47 | e().term('John').and(e().term('Lennon')).or(e().term('Beatles')),
48 | );
49 |
50 | expect(compare.render()).toBe('(John AND Lennon) OR Beatles');
51 | });
52 | });
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/select.spec.ts:
--------------------------------------------------------------------------------
1 | import { SelectExpression } from './select';
2 |
3 | describe('OData search builder', () => {
4 | interface Pet {
5 | Id?: number;
6 | Name?: string;
7 | Age?: number;
8 | Person?: Person;
9 | }
10 |
11 | interface Model {
12 | Id?: number;
13 | Name?: string;
14 | }
15 |
16 | interface Car {
17 | Id?: number;
18 | Model?: Model;
19 | Year?: number;
20 | }
21 |
22 | interface Person {
23 | Id?: number;
24 | Name?: string;
25 | Age?: number;
26 | IsCorrect?: boolean;
27 | EditedOn?: boolean;
28 | CreatedOn?: boolean;
29 | Car?: Car;
30 | Pets?: Pet[];
31 | }
32 |
33 | describe('base condition', () => {
34 | describe('as factory function', () => {
35 | it('select', () => {
36 | const compare1 = SelectExpression.factory(({ t, e }) =>
37 | e().field(t.Car).field(t.Name),
38 | );
39 |
40 | expect(compare1.render()).toBe('Car,Name');
41 | });
42 | });
43 |
44 | describe('navigation e().field(...)', () => {
45 | it('navigate', () => {
46 | const compare = SelectExpression.factory(({ t, e }) =>
47 | e().field(t.Car?.Model?.Name).field(t.Age),
48 | );
49 |
50 | expect(compare.render()).toBe('Car/Model/Name,Age');
51 | });
52 | });
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/expressions/select.ts:
--------------------------------------------------------------------------------
1 | import { Parser, ParserOptions } from '../../../types';
2 | import { QueryCustomType } from '../builder';
3 | import { Expression } from './base';
4 | import { FieldFactory, Renderable, RenderableFactory } from './syntax';
5 |
6 | export type SelectExpressionBuilder = {
7 | t: Required;
8 | e: () => SelectExpression;
9 | };
10 | export class SelectExpression extends Expression {
11 | constructor({
12 | children,
13 | }: {
14 | children?: Renderable[];
15 | } = {}) {
16 | super({ children });
17 | }
18 |
19 | override get [Symbol.toStringTag]() {
20 | return 'SelectExpression';
21 | }
22 |
23 | static factory(
24 | opts: (
25 | builder: SelectExpressionBuilder,
26 | current: SelectExpression,
27 | ) => SelectExpression,
28 | current?: SelectExpression,
29 | ): SelectExpression {
30 | return opts(
31 | {
32 | t: FieldFactory>(),
33 | e: () => new SelectExpression(),
34 | },
35 | current ?? new SelectExpression(),
36 | ) as SelectExpression;
37 | }
38 |
39 | override toJson() {
40 | const json = super.toJson();
41 | return Object.assign(json, {});
42 | }
43 |
44 | static fromJson(json: { [name: string]: any }): SelectExpression {
45 | return new SelectExpression({
46 | children: json['children'].map((c: any) => RenderableFactory(c)),
47 | });
48 | }
49 | render({
50 | aliases,
51 | escape,
52 | prefix,
53 | parser,
54 | options,
55 | }: {
56 | aliases?: QueryCustomType[];
57 | escape?: boolean;
58 | prefix?: string;
59 | parser?: Parser;
60 | options?: ParserOptions;
61 | } = {}): string {
62 | return this._children
63 | .map((n) =>
64 | typeof n === 'string'
65 | ? n
66 | : n.render({ aliases, escape, prefix, parser, options }),
67 | )
68 | .join(',');
69 | }
70 |
71 | clone() {
72 | return new SelectExpression({
73 | children: this._children.map((c) => c.clone()),
74 | });
75 | }
76 |
77 | private _add(node: Renderable): SelectExpression {
78 | this._children.push(node);
79 | return this;
80 | }
81 |
82 | field(field: any): SelectExpression {
83 | return this._add(field);
84 | }
85 |
86 | fields(...fields: any[]): SelectExpression {
87 | fields.forEach((f) => this._add(f));
88 | return this;
89 | }
90 |
91 | combine(expression: SelectExpression): SelectExpression {
92 | return this._add(expression);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/query/index.ts:
--------------------------------------------------------------------------------
1 | export * from './builder';
2 | export * from './options';
3 | export * from './handlers';
4 | export * from './expressions';
5 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/types/count.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | import { ODataApi } from '../../api';
3 | import { $COUNT } from '../../constants';
4 | import { EdmType, PathSegment, QueryOption } from '../../types';
5 | import { ODataPathSegments } from '../path';
6 | import { ODataQueryOptions } from '../query';
7 | import { ODataResource } from '../resource';
8 | import { ODataOptions } from './options';
9 |
10 | export class ODataCountResource extends ODataResource {
11 | //#region Factory
12 | static factory(
13 | api: ODataApi,
14 | {
15 | segments,
16 | query,
17 | }: {
18 | segments: ODataPathSegments;
19 | query?: ODataQueryOptions;
20 | },
21 | ) {
22 | const currentType = segments.last()?.outgoingType();
23 | const segment = segments.add(PathSegment.count, $COUNT);
24 | segment.outgoingType(currentType);
25 | segment.incomingType(EdmType.Int32);
26 | query?.keep(QueryOption.filter, QueryOption.search);
27 | return new ODataCountResource(api, { segments, query });
28 | }
29 |
30 | override clone(): ODataCountResource {
31 | return super.clone() as ODataCountResource;
32 | }
33 | //#endregion
34 |
35 | //#region Requests
36 | protected override get(options?: ODataOptions): Observable {
37 | return super.get({ responseType: 'value', ...options });
38 | }
39 | //#endregion
40 |
41 | //#region Shortcuts
42 | /**
43 | * Fetch the count of the set.
44 | * @param options Options for the request
45 | * @returns The count of the set
46 | */
47 | fetch(options?: ODataOptions): Observable {
48 | return this.get(options);
49 | }
50 | //#endregion
51 | }
52 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/types/index.ts:
--------------------------------------------------------------------------------
1 | export * from './options';
2 | export * from './action';
3 | export * from './batch';
4 | export * from './count';
5 | export * from './entity';
6 | export * from './entity-set';
7 | export * from './function';
8 | export * from './metadata';
9 | export * from './navigation-property';
10 | export * from './property';
11 | export * from './reference';
12 | export * from './singleton';
13 | export * from './media';
14 | export * from './value';
15 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/types/media.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | import { ODataApi } from '../../api';
3 | import { $VALUE } from '../../constants';
4 | import { PathSegment } from '../../types';
5 | import { Http } from '../../utils';
6 | import { ODataPathSegments } from '../path';
7 | import { ODataQueryOptions } from '../query';
8 | import { ODataResource } from '../resource';
9 | import { ODataOptions } from './options';
10 |
11 | export class ODataMediaResource extends ODataResource {
12 | //#region Factory
13 | static factory(
14 | api: ODataApi,
15 | {
16 | segments,
17 | query,
18 | }: {
19 | segments: ODataPathSegments;
20 | query?: ODataQueryOptions;
21 | },
22 | ) {
23 | segments.add(PathSegment.value, $VALUE);
24 | return new ODataMediaResource(api, { segments, query });
25 | }
26 |
27 | override clone(): ODataMediaResource {
28 | return super.clone() as ODataMediaResource;
29 | }
30 | //#endregion
31 |
32 | //#region Requests
33 | protected override get(
34 | options: { responseType: 'arraybuffer' | 'blob' } & ODataOptions,
35 | ): Observable {
36 | return super.get(options);
37 | }
38 |
39 | protected override put(
40 | data: ArrayBuffer | Blob,
41 | options: ODataOptions = {},
42 | ): Observable {
43 | return super.put(data, options);
44 | }
45 | //#endregion
46 |
47 | //#region Shortcuts
48 | fetch(
49 | options: { responseType: 'arraybuffer' } & ODataOptions,
50 | ): Observable;
51 | fetch(options: { responseType: 'blob' } & ODataOptions): Observable;
52 | fetch(options: { responseType: any } & ODataOptions): Observable {
53 | return this.get(options);
54 | }
55 |
56 | fetchArraybuffer(options: ODataOptions = {}): Observable {
57 | return this.fetch({ responseType: 'arraybuffer', ...options });
58 | }
59 |
60 | fetchBlob(options: ODataOptions = {}): Observable {
61 | return this.fetch({ responseType: 'blob', ...options });
62 | }
63 |
64 | upload(
65 | data: ArrayBuffer | Blob,
66 | options: ODataOptions = {},
67 | ): Observable {
68 | return this.put(data, options);
69 | }
70 |
71 | uploadArrayBuffer(
72 | data: ArrayBuffer,
73 | contentType: string,
74 | options: ODataOptions = {},
75 | ): Observable {
76 | options.headers = Http.mergeHttpHeaders(options.headers || {}, {
77 | 'Content-Type': contentType,
78 | });
79 | return this.upload(data, options);
80 | }
81 |
82 | uploadBlob(data: Blob, options: ODataOptions = {}): Observable {
83 | return this.upload(data, options);
84 | }
85 | //#endregion
86 | }
87 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/types/metadata.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | import { map } from 'rxjs/operators';
3 | import { ODataApi } from '../../api';
4 | import { $METADATA, ACCEPT, APPLICATION_XML } from '../../constants';
5 | import { PathSegment } from '../../types';
6 | import { ODataPathSegments } from '../path';
7 | import { ODataResource } from '../resource';
8 | import { ODataOptions } from './options';
9 | import { ODataMetadata } from '../../metadata/metadata';
10 | import { ODataMetadataParser } from '../../metadata';
11 |
12 | export class ODataMetadataResource extends ODataResource {
13 | constructor(api: ODataApi, segments?: ODataPathSegments) {
14 | super(api, { segments });
15 | }
16 |
17 | //#region Factory
18 | static factory(api: ODataApi) {
19 | let segments = new ODataPathSegments();
20 | segments.add(PathSegment.metadata, $METADATA);
21 | return new ODataMetadataResource(api, segments);
22 | }
23 |
24 | override clone(): ODataMetadataResource {
25 | return super.clone() as ODataMetadataResource;
26 | }
27 | //#endregion
28 |
29 | //#region Requests
30 | protected override get(options?: ODataOptions): Observable {
31 | return super.get({
32 | responseType: 'text',
33 | ...options,
34 | headers: { [ACCEPT]: APPLICATION_XML },
35 | });
36 | }
37 | //#endregion
38 |
39 | //#region Shortcuts
40 | fetch(options?: ODataOptions): Observable {
41 | return this.get(options).pipe(
42 | map((body: any) => new ODataMetadataParser(body).metadata()),
43 | );
44 | }
45 | //#endregion
46 | }
47 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/types/options.ts:
--------------------------------------------------------------------------------
1 | import { HttpContext, HttpHeaders, HttpParams } from '@angular/common/http';
2 | import { FetchPolicy, ParserOptions } from '../../types';
3 | import { ODataQueryArguments } from '../query';
4 |
5 | export type ODataOptions = {
6 | etag?: string;
7 | context?: HttpContext;
8 | headers?: HttpHeaders | { [header: string]: string | string[] };
9 | params?:
10 | | HttpParams
11 | | {
12 | [param: string]:
13 | | string
14 | | number
15 | | boolean
16 | | ReadonlyArray;
17 | };
18 | reportProgress?: boolean;
19 | withCredentials?: boolean;
20 | fetchPolicy?: FetchPolicy;
21 | parserOptions?: ParserOptions;
22 | };
23 |
24 | export type ODataEntityOptions = ODataOptions & { responseType?: 'entity' };
25 | export type ODataEntitiesOptions = ODataOptions & {
26 | responseType?: 'entities';
27 | withCount?: boolean;
28 | };
29 | export type ODataPropertyOptions = ODataOptions & { responseType?: 'property' };
30 | export type ODataQueryArgumentsOptions = ODataOptions &
31 | ODataQueryArguments;
32 | export type ODataActionOptions = ODataQueryArgumentsOptions;
33 | export type ODataFunctionOptions = ODataQueryArgumentsOptions & {
34 | alias?: boolean;
35 | };
36 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/resources/types/value.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | import { ODataApi } from '../../api';
3 | import { $VALUE } from '../../constants';
4 | import { PathSegment } from '../../types';
5 | import { ODataPathSegments } from '../path';
6 | import { ODataResource } from '../resource';
7 | import { ODataOptions } from './options';
8 |
9 | export class ODataValueResource extends ODataResource {
10 | //#region Factory
11 | static factory(
12 | api: ODataApi,
13 | {
14 | segments,
15 | }: {
16 | segments: ODataPathSegments;
17 | },
18 | ) {
19 | const currentType = segments.last()?.outgoingType();
20 | const segment = segments.add(PathSegment.value, $VALUE);
21 | segment.incomingType(currentType);
22 | return new ODataValueResource(api, { segments });
23 | }
24 |
25 | static fromResource(resource: ODataResource) {
26 | const baseType = resource.outgoingType();
27 | let baseSchema =
28 | baseType !== undefined
29 | ? resource.api.structuredType(baseType)
30 | : undefined;
31 | const value = ODataValueResource.factory(resource.api, {
32 | segments: resource.cloneSegments(),
33 | });
34 |
35 | // Switch entitySet to binding type if available
36 | if (baseSchema !== undefined && baseSchema.type() !== baseType) {
37 | let entitySet = resource.api.findEntitySet(baseSchema.type());
38 | if (entitySet !== undefined) {
39 | value.segment((s) => s.entitySet().path(entitySet!.name));
40 | }
41 | }
42 |
43 | return value;
44 | }
45 | override clone(): ODataValueResource {
46 | return super.clone() as ODataValueResource;
47 | }
48 | //#endregion
49 |
50 | //#region Requests
51 | protected override get(options: ODataOptions = {}): Observable {
52 | return super.get({ responseType: 'value', ...options });
53 | }
54 | //#endregion
55 |
56 | //#region Shortcuts
57 |
58 | /**
59 | * Fetch the value of the resource.
60 | * @param options OData options.
61 | * @returns Observable of the value.
62 | */
63 | fetch(options?: ODataOptions): Observable {
64 | return this.get(options);
65 | }
66 |
67 | //#endregion
68 | }
69 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/schema/annotation.ts:
--------------------------------------------------------------------------------
1 | import { ODataAnnotationConfig } from '../types';
2 |
3 | export class ODataAnnotation {
4 | term: string;
5 | string?: string;
6 | bool?: boolean;
7 | int?: number;
8 | permissions?: string[];
9 | properties?: string[];
10 |
11 | constructor(annot: ODataAnnotationConfig) {
12 | this.term = annot.term;
13 | Object.assign(this, annot);
14 | }
15 | }
16 |
17 | export class ODataAnnotatable {
18 | annotations: ODataAnnotation[];
19 | constructor(config: { annotations?: ODataAnnotationConfig[] }) {
20 | this.annotations = (config.annotations || []).map(
21 | (annot) => new ODataAnnotation(annot),
22 | );
23 | }
24 |
25 | /**
26 | * Find an annotation inside the annotatable.
27 | * @param predicate Function that returns true if the annotation match.
28 | * @returns The annotation that matches the predicate.
29 | */
30 | findAnnotation(predicate: (annot: ODataAnnotation) => boolean) {
31 | return this.annotations.find(predicate);
32 | }
33 |
34 | /**
35 | * Find an annotation inside the annotatable and return its value.
36 | * @param term The term of the annotation to find.
37 | * @returns The value of the annotation.
38 | */
39 | annotatedValue(term: string | RegExp): T | undefined {
40 | const reg = term instanceof RegExp ? term : new RegExp(`^${term}$`);
41 | const annot = this.findAnnotation((a) => reg.test(a.term));
42 | if (!annot) {
43 | return undefined;
44 | }
45 | return (annot.string ||
46 | annot.bool ||
47 | annot.int ||
48 | annot.permissions ||
49 | annot.properties) as any;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/schema/callable.ts:
--------------------------------------------------------------------------------
1 | import { ODataCallableConfig, ParserOptions } from '../types';
2 | import { ODataParserSchemaElement } from './element';
3 | import { ODataCallableParser } from './parsers';
4 | import { ODataSchema } from './schema';
5 |
6 | export class ODataCallable extends ODataParserSchemaElement<
7 | R,
8 | ODataCallableParser
9 | > {
10 | entitySetPath?: string;
11 | bound?: boolean;
12 | composable?: boolean;
13 |
14 | constructor(config: ODataCallableConfig, schema: ODataSchema) {
15 | super(
16 | config,
17 | schema,
18 | new ODataCallableParser(config, schema.namespace, schema.alias),
19 | );
20 | this.entitySetPath = config.entitySetPath;
21 | this.bound = config.bound;
22 | this.composable = config.composable;
23 | }
24 |
25 | path() {
26 | let path: string;
27 | if (this.entitySetPath) path = this.entitySetPath;
28 | else if (this.bound) path = `${this.schema.namespace}.${this.name}`;
29 | else
30 | path = this.parser.return
31 | ? this.api.findEntitySet(this.parser.return.type)?.name || this.name
32 | : this.name;
33 | return path;
34 | }
35 |
36 | configure({ options }: { options: ParserOptions }) {
37 | this.parser.configure({
38 | options,
39 | parserForType: (t: string) => this.api.parserForType(t),
40 | });
41 | }
42 |
43 | /**
44 | * Deseialize the given value from the callable.
45 | * @param value Value to deserialize
46 | * @param options Options for deserialization
47 | * @returns Deserialized value
48 | */
49 | deserialize(value: any, options?: ParserOptions): any {
50 | return this.parser.deserialize(value, options);
51 | }
52 |
53 | /**
54 | * Serialize the given value for the callable.
55 | * @param value Value to serialize
56 | * @param options Options for serialization
57 | * @returns Serialized value
58 | */
59 | serialize(value: any, options?: ParserOptions): any {
60 | return this.parser.serialize(value, options);
61 | }
62 |
63 | /**
64 | * Encode the given value for the callable.
65 | * @param value Value to encode
66 | * @param options Options for encoding
67 | * @returns Encoded value
68 | */
69 | encode(value: any, options?: ParserOptions): any {
70 | return this.parser.encode(value, options);
71 | }
72 |
73 | /**
74 | * Returns the binding parameter of the callable.
75 | * @returns The binding parameter of the callable.
76 | */
77 | binding() {
78 | return this.parser.binding();
79 | }
80 |
81 | returnType() {
82 | return this.parser.returnType();
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/schema/element.ts:
--------------------------------------------------------------------------------
1 | import { ODataAnnotationConfig, Parser } from '../types';
2 | import { Strings } from '../utils';
3 | import { ODataAnnotatable } from './annotation';
4 | import { ODataSchema } from './schema';
5 |
6 | export class ODataSchemaElement extends ODataAnnotatable {
7 | name: string;
8 | schema: ODataSchema;
9 |
10 | constructor(
11 | config: { annotations?: ODataAnnotationConfig[]; name: string },
12 | schema: ODataSchema,
13 | ) {
14 | super(config);
15 | this.schema = schema;
16 | this.name = config.name;
17 | }
18 |
19 | get api() {
20 | return this.schema.api;
21 | }
22 |
23 | /**
24 | * Create a nicer looking title.
25 | * Titleize is meant for creating pretty output.
26 | * @param term The term of the annotation to find.
27 | * @returns The titleized string.
28 | */
29 | titleize(term?: string | RegExp): string {
30 | return (term && this.annotatedValue(term)) ?? Strings.titleCase(this.name);
31 | }
32 |
33 | /**
34 | * Returns a full type of the structured type including the namespace/alias.
35 | * @param alias Use the alias of the namespace instead of the namespace.
36 | * @returns The string representation of the type.
37 | */
38 | type({ alias = false }: { alias?: boolean } = {}) {
39 | return `${alias ? this.schema.alias : this.schema.namespace}.${this.name}`;
40 | }
41 |
42 | /**
43 | * Returns a boolean indicating if the structured type is of the given type.
44 | * @param type String representation of the type
45 | * @returns True if the callable is type of the given type
46 | */
47 | isTypeOf(element: ODataSchemaElement): boolean {
48 | const names = [`${this.schema.namespace}.${this.name}`];
49 | if (this.schema.alias) names.push(`${this.schema.alias}.${this.name}`);
50 | return names.includes(element.type());
51 | }
52 |
53 | /**
54 | * Returns a boolean indicating if the structured type is a subtype of the given type.
55 | * @param type String representation of the type
56 | * @returns True if the callable is type of the given type
57 | */
58 | isSubtypeOf(element: ODataSchemaElement): boolean {
59 | if (this.isTypeOf(element)) return true;
60 | return false;
61 | }
62 |
63 | /**
64 | * Returns a boolean indicating if the structured type is a supertype of the given type.
65 | * @param type String representation of the type
66 | * @returns True if the callable is type of the given type
67 | */
68 | isSupertypeOf(element: ODataSchemaElement): boolean {
69 | if (this.isTypeOf(element)) return true;
70 | return false;
71 | }
72 | }
73 |
74 | export class ODataParserSchemaElement<
75 | E,
76 | P extends Parser,
77 | > extends ODataSchemaElement {
78 | parser: P;
79 | constructor(
80 | config: { annotations?: ODataAnnotationConfig[]; name: string },
81 | schema: ODataSchema,
82 | parser: P,
83 | ) {
84 | super(config, schema);
85 | this.parser = parser;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/schema/entity-container.ts:
--------------------------------------------------------------------------------
1 | import { ODataEntityContainerConfig } from '../types';
2 | import { ODataSchemaElement } from './element';
3 | import { ODataEntitySet } from './entity-set';
4 | import { ODataSchema } from './schema';
5 | import { ODataSingleton } from './singleton';
6 |
7 | export class ODataEntityContainer extends ODataSchemaElement {
8 | entitySets: ODataEntitySet[];
9 | singletons: ODataSingleton[];
10 |
11 | constructor(config: ODataEntityContainerConfig, schema: ODataSchema) {
12 | super(config, schema);
13 | this.entitySets = (config.entitySets ?? []).map(
14 | (config) => new ODataEntitySet(config, schema),
15 | );
16 | this.singletons = (config.singletons ?? []).map(
17 | (config) => new ODataSingleton(config, schema),
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/schema/entity-set.ts:
--------------------------------------------------------------------------------
1 | import { ODataEntitySetConfig } from '../types';
2 | import { ODataSchemaElement } from './element';
3 | import { ODataSchema } from './schema';
4 |
5 | export class ODataEntitySet extends ODataSchemaElement {
6 | entityType: string;
7 | service: { new (...params: any[]): any };
8 | constructor(config: ODataEntitySetConfig, schema: ODataSchema) {
9 | super(config, schema);
10 | this.entityType = config.entityType;
11 | this.service = config.service;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/schema/enum-type.ts:
--------------------------------------------------------------------------------
1 | import { ODataEnumTypeConfig, ParserOptions } from '../types';
2 | import { ODataParserSchemaElement } from './element';
3 | import { ODataEnumTypeFieldParser, ODataEnumTypeParser } from './parsers';
4 | import { ODataSchema } from './schema';
5 |
6 | export class ODataEnumType extends ODataParserSchemaElement<
7 | E,
8 | ODataEnumTypeParser
9 | > {
10 | members: { [name: string]: number } | { [value: number]: string };
11 | constructor(config: ODataEnumTypeConfig, schema: ODataSchema) {
12 | super(
13 | config,
14 | schema,
15 | new ODataEnumTypeParser(config, schema.namespace, schema.alias),
16 | );
17 | this.members = config.members;
18 | }
19 |
20 | configure({ options }: { options: ParserOptions }) {
21 | this.parser.configure({ options });
22 | }
23 |
24 | /**
25 | * Returns the fields of the enum type.
26 | * @returns The fields of the enum type.
27 | */
28 | fields(namesValue?: string | number): ODataEnumTypeFieldParser[] {
29 | return this.parser.fields(namesValue);
30 | }
31 |
32 | /**
33 | * Find a field by name or value.
34 | * @param enu The name or value of the field
35 | * @returns The field with the given name or value
36 | */
37 | field(nameValue: string | number) {
38 | return this.parser.field(nameValue);
39 | }
40 |
41 | /**
42 | * Map the fields of the enum type.
43 | * @param mapper Function that maps the value to the new value
44 | * @returns The fields mapped by the mapper
45 | */
46 | mapFields(mapper: (field: ODataEnumTypeFieldParser) => T) {
47 | return this.parser.mapFields(mapper);
48 | }
49 |
50 | /**
51 | * Deseialize the given value from the enum type.
52 | * @param value Value to deserialize
53 | * @param options Options for deserialization
54 | * @returns Deserialized value
55 | */
56 | deserialize(value: any, options?: ParserOptions): E {
57 | return this.parser.deserialize(value, options);
58 | }
59 |
60 | /**
61 | * Serialize the given value for the enum type.
62 | * @param value Value to serialize
63 | * @param options Options for serialization
64 | * @returns Serialized value
65 | */
66 | serialize(value: number, options?: ParserOptions): any {
67 | return this.parser.serialize(value, options);
68 | }
69 |
70 | /**
71 | * Encode the given value for the enum type.
72 | * @param value Value to encode
73 | * @param options Options for encoding
74 | * @returns Encoded value
75 | */
76 | encode(value: number, options?: ParserOptions): any {
77 | return this.parser.encode(value, options);
78 | }
79 |
80 | unpack(value: string | number) {
81 | return this.parser.unpack(value);
82 | }
83 |
84 | pack(value: string | number | number[]) {
85 | return this.parser.pack(value);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/schema/index.ts:
--------------------------------------------------------------------------------
1 | export * from './schema';
2 | export * from './entity-container';
3 | export * from './callable';
4 | export * from './enum-type';
5 | export * from './structured-type';
6 | export * from './entity-set';
7 | export * from './singleton';
8 | export * from './parsers';
9 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/schema/parsers/index.ts:
--------------------------------------------------------------------------------
1 | export * from './edm';
2 | export * from './enum-type';
3 | export * from './structured-type';
4 | export * from './callable';
5 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/schema/schema.ts:
--------------------------------------------------------------------------------
1 | import { ODataApi } from '../api';
2 | import {
3 | ParserOptions,
4 | ODataSchemaConfig,
5 | ODataStructuredTypeConfig,
6 | } from '../types';
7 | import { OData } from '../utils/odata';
8 | import { ODataAnnotatable } from './annotation';
9 | import { ODataCallable } from './callable';
10 | import { ODataEntityContainer } from './entity-container';
11 | import { ODataEntitySet } from './entity-set';
12 | import { ODataEnumType } from './enum-type';
13 | import { ODataSingleton } from './singleton';
14 | import { ODataStructuredType } from './structured-type';
15 |
16 | export class ODataSchema extends ODataAnnotatable {
17 | api: ODataApi;
18 | namespace: string;
19 | alias?: string;
20 | enums: ODataEnumType[];
21 | entities: ODataStructuredType[];
22 | callables: ODataCallable[];
23 | containers: ODataEntityContainer[];
24 |
25 | constructor(config: ODataSchemaConfig, api: ODataApi) {
26 | super(config);
27 | this.api = api;
28 | this.namespace = config.namespace;
29 | this.alias = config.alias;
30 | this.enums = (config.enums ?? []).map(
31 | (config) => new ODataEnumType(config, this),
32 | );
33 | this.entities = (config.entities ?? []).map(
34 | (config) => new ODataStructuredType(config, this),
35 | );
36 | this.callables = OData.mergeCallableParameters(config.callables ?? []).map(
37 | (config) => new ODataCallable(config, this),
38 | );
39 | this.containers = (config.containers ?? []).map(
40 | (config) => new ODataEntityContainer(config, this),
41 | );
42 | }
43 |
44 | isNamespaceOf(type: string) {
45 | return (
46 | type.startsWith(this.namespace) ??
47 | (this.alias && type.startsWith(this.alias))
48 | );
49 | }
50 |
51 | get entitySets() {
52 | return this.containers.reduce(
53 | (acc, container) => [...acc, ...container.entitySets],
54 | [] as ODataEntitySet[],
55 | );
56 | }
57 |
58 | get singletons() {
59 | return this.containers.reduce(
60 | (acc, container) => [...acc, ...container.singletons],
61 | [] as ODataSingleton[],
62 | );
63 | }
64 |
65 | //#region Find for Type
66 | public createStructuredType(config: ODataStructuredTypeConfig) {
67 | const entity = new ODataStructuredType(config, this);
68 | entity.configure({ options: this.api.options.parserOptions });
69 | this.entities.push(entity);
70 | return entity;
71 | }
72 | //#endregion
73 |
74 | configure({ options }: { options: ParserOptions }) {
75 | // Configure Enums
76 | this.enums.forEach((enu) => enu.configure({ options }));
77 | // Configure Entities
78 | this.entities.forEach((structured) => structured.configure({ options }));
79 | // Configure callables
80 | this.callables.forEach((callable) => callable.configure({ options }));
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/schema/singleton.ts:
--------------------------------------------------------------------------------
1 | import { ODataSingletonConfig } from '../types';
2 | import { ODataSchemaElement } from './element';
3 | import { ODataSchema } from './schema';
4 |
5 | export class ODataSingleton extends ODataSchemaElement {
6 | singletonType: string;
7 | service: { new (...params: any[]): any };
8 | constructor(config: ODataSingletonConfig, schema: ODataSchema) {
9 | super(config, schema);
10 | this.singletonType = config.type;
11 | this.service = config.service;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/services/entity.ts:
--------------------------------------------------------------------------------
1 | import { ODataModel } from '../models/model';
2 | import { EntityKey, ODataResource } from '../resources';
3 | import { ODataBaseService } from './base';
4 |
5 | export abstract class ODataEntityService extends ODataBaseService {
6 | public abstract entity(key?: EntityKey): ODataResource;
7 | public abstract attach>(value: M): void;
8 |
9 | /**
10 | * The schema for the structured type.
11 | */
12 | get structuredTypeSchema() {
13 | return this.apiNameOrEntityType !== undefined
14 | ? this.api.findStructuredType(this.apiNameOrEntityType)
15 | : undefined;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/services/factory.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { ODataClient } from '../client';
3 | import { ODataEntitySetService } from './entity-set';
4 | import { ODataSingletonService } from './singleton';
5 | import { ODataCollection, ODataModel } from '../models';
6 |
7 | @Injectable()
8 | export class ODataServiceFactory {
9 | constructor(protected client: ODataClient) {}
10 |
11 | /**
12 | * Factory method to create an entity set service.
13 | * @param entitySetName Name of the entity set.
14 | * @param apiNameOrEntityType Name of the API or the type of the entity.
15 | */
16 | entitySet(
17 | entitySetName: string,
18 | apiNameOrEntityType?: string,
19 | options: {
20 | Model?: { new (...params: any[]): ODataModel };
21 | Collection?: {
22 | new (...params: any[]): ODataCollection>;
23 | };
24 | } = {},
25 | ): ODataEntitySetService {
26 | const Service = class extends ODataEntitySetService {
27 | Model = options?.Model;
28 | Collection = options?.Collection;
29 | };
30 | return new Service(this.client, entitySetName, apiNameOrEntityType);
31 | }
32 |
33 | /** Factory method to create a singleton service.
34 | * @param singletonName Name of the singleton.
35 | * @param apiNameOrEntityType Name of the API or the type of the entity.
36 | */
37 | singleton(
38 | singletonName: string,
39 | apiNameOrEntityType?: string,
40 | options: { Model?: { new (...params: any[]): ODataModel } } = {},
41 | ): ODataSingletonService {
42 | const Service = class extends ODataSingletonService {
43 | Model = options?.Model;
44 | };
45 | return new Service(this.client, singletonName, apiNameOrEntityType);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/services/index.ts:
--------------------------------------------------------------------------------
1 | export * from './base';
2 | export * from './entity-set';
3 | export * from './singleton';
4 | export * from './factory';
5 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/services/singleton.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | import { ODataModel } from '../models/model';
3 | import {
4 | ODataEntity,
5 | ODataOptions,
6 | ODataSingletonResource,
7 | } from '../resources';
8 | import { ODataEntityService } from './entity';
9 |
10 | /**
11 | * OData Singleton Service
12 | * www.odata.org/getting-started/advanced-tutorial/#singleton
13 | */
14 | export class ODataSingletonService extends ODataEntityService {
15 | static Model?: typeof ODataModel;
16 | model(entity?: Partial) {
17 | const Service = this.constructor as typeof ODataSingletonService;
18 | return this.entity().asModel((entity ?? {}) as Partial, {
19 | ModelType: Service.Model,
20 | });
21 | }
22 | /**
23 | * Get the entity resource for this service.
24 | * @param key The entity key.
25 | */
26 | public entity(): ODataSingletonResource {
27 | return this.client.singleton(this.name, this.apiNameOrEntityType);
28 | }
29 |
30 | /**
31 | * Attach an existing model to this service.
32 | * @param model The model to attach.
33 | */
34 | public attach>(model: M) {
35 | model.attach(this.entity());
36 | }
37 |
38 | /**
39 | * The schema for the singleton.
40 | */
41 | get singletonSchema() {
42 | return this.api.findEntitySet(this.name);
43 | }
44 |
45 | /**
46 | * Update the singleton entity
47 | * @param attrs The attributes for the entity.
48 | * @param etag The etag for the entity.
49 | * @param options The options for the request.
50 | */
51 | public update(
52 | attrs: Partial,
53 | options?: ODataOptions & { etag?: string },
54 | ): Observable> {
55 | const res = this.entity();
56 | return res.update(attrs, options);
57 | }
58 |
59 | /**
60 | * Patch the singleton entity
61 | * @param attrs The attributes for the entity.
62 | * @param etag The etag for the entity.
63 | * @param options The options for the request.
64 | */
65 | public patch(
66 | attrs: Partial,
67 | options?: ODataOptions & { etag?: string },
68 | ): Observable> {
69 | const res = this.entity();
70 | return res.modify(attrs, options);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/arraybuffers.ts:
--------------------------------------------------------------------------------
1 | //https://github.com/niklasvh/base64-arraybuffer
2 | const chars =
3 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
4 |
5 | // Use a lookup table to find the index.
6 | const lookup = new Uint8Array(256);
7 | for (var i = 0; i < chars.length; i++) {
8 | lookup[chars.charCodeAt(i)] = i;
9 | }
10 |
11 | export const ArrayBuffers = {
12 | toArrayBuffer(v: string): ArrayBuffer {
13 | var bufferLength = v.length * 0.75,
14 | len = v.length,
15 | i,
16 | p = 0,
17 | encoded1,
18 | encoded2,
19 | encoded3,
20 | encoded4;
21 |
22 | if (v[v.length - 1] === '=') {
23 | bufferLength--;
24 | if (v[v.length - 2] === '=') {
25 | bufferLength--;
26 | }
27 | }
28 |
29 | var arraybuffer = new ArrayBuffer(bufferLength),
30 | bytes = new Uint8Array(arraybuffer);
31 |
32 | for (i = 0; i < len; i += 4) {
33 | encoded1 = lookup[v.charCodeAt(i)];
34 | encoded2 = lookup[v.charCodeAt(i + 1)];
35 | encoded3 = lookup[v.charCodeAt(i + 2)];
36 | encoded4 = lookup[v.charCodeAt(i + 3)];
37 |
38 | bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
39 | bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
40 | bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
41 | }
42 |
43 | return arraybuffer;
44 | },
45 | toString(v: ArrayBuffer): string {
46 | var bytes = new Uint8Array(v),
47 | i,
48 | len = bytes.length,
49 | base64 = '';
50 |
51 | for (i = 0; i < len; i += 3) {
52 | base64 += chars[bytes[i] >> 2];
53 | base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
54 | base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
55 | base64 += chars[bytes[i + 2] & 63];
56 | }
57 |
58 | if (len % 3 === 2) {
59 | base64 = base64.substring(0, base64.length - 1) + '=';
60 | } else if (len % 3 === 1) {
61 | base64 = base64.substring(0, base64.length - 2) + '==';
62 | }
63 | return base64;
64 | },
65 | };
66 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/arrays.spec.ts:
--------------------------------------------------------------------------------
1 | import { Arrays } from './arrays';
2 |
3 | describe('Arrays', () => {
4 | it('should convert to title case', () => {
5 | expect(
6 | Arrays.zip([1, 2, 3, 4, 5, 6], ['a', 'b', 'c', 'd', 'e', 'f']),
7 | ).toEqual([
8 | [1, 'a'],
9 | [2, 'b'],
10 | [3, 'c'],
11 | [4, 'd'],
12 | [5, 'e'],
13 | [6, 'f'],
14 | ]);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/arrays.ts:
--------------------------------------------------------------------------------
1 | export const Arrays = {
2 | // Zip arrays
3 | // Example
4 | // Arrays.zip([1, 2, 3, 4, 5, 6], ['a', 'b', 'c', 'd', 'e', 'f'])
5 | // => [[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd'], [5, 'e'], [6, 'f']]
6 | zip: (...arrays: any[][]) => {
7 | return arrays[0].map((_: any, i: number) =>
8 | arrays.map((array: any[]) => array[i]),
9 | );
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/dates.ts:
--------------------------------------------------------------------------------
1 | const ISO_REGEX =
2 | /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/;
3 |
4 | export const Dates = {
5 | isoStringToDate(value: any): any {
6 | if (typeof value === 'string' && value.search(ISO_REGEX) === 0) {
7 | return new Date(value);
8 | } else if (Array.isArray(value)) {
9 | return value.map((v) => this.isoStringToDate(v));
10 | } else if (value && value.constructor === Object) {
11 | return Object.keys(value)
12 | .map((key) => [key, this.isoStringToDate(value[key])])
13 | .reduce((acc, v) => Object.assign(acc, { [v[0]]: v[1] }), {});
14 | }
15 | return value;
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/durations.ts:
--------------------------------------------------------------------------------
1 | const DURATION_REGEX =
2 | /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
3 |
4 | //https://en.wikipedia.org/wiki/ISO_8601#Durations
5 | export type Duration = {
6 | sign?: 1 | -1;
7 | years?: number;
8 | months?: number;
9 | weeks?: number;
10 | days?: number;
11 | hours?: number;
12 | minutes?: number;
13 | seconds?: number;
14 | };
15 |
16 | export const Durations = {
17 | toDuration(v: string): Duration {
18 | const matches = DURATION_REGEX.exec(v);
19 | if (!matches || v.length < 3) {
20 | throw new TypeError(
21 | `duration invalid: "${v}". Must be a ISO 8601 duration. See https://en.wikipedia.org/wiki/ISO_8601#Durations`,
22 | );
23 | }
24 | let duration: Duration = {};
25 | duration.sign = matches[1] === '-' ? -1 : 1;
26 | return [
27 | 'years',
28 | 'months',
29 | 'weeks',
30 | 'days',
31 | 'hours',
32 | 'minutes',
33 | 'seconds',
34 | ].reduce((acc: any, name, index) => {
35 | const v = parseFloat(matches[index + 2]);
36 | if (!Number.isNaN(v)) acc[name] = v;
37 | return acc;
38 | }, duration) as Duration;
39 | },
40 | toString(v: Duration): string {
41 | return [
42 | v.sign === -1 ? '-' : '',
43 | 'P',
44 | v.years ? v.years + 'Y' : '',
45 | v.months ? v.months + 'M' : '',
46 | v.weeks ? v.weeks + 'W' : '',
47 | v.days ? v.days + 'D' : '',
48 | 'T',
49 | v.hours ? v.hours + 'H' : '',
50 | v.minutes ? v.minutes + 'M' : '',
51 | v.seconds ? v.seconds + 'S' : '',
52 | ].join('');
53 | },
54 | };
55 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/enums.ts:
--------------------------------------------------------------------------------
1 | export const Enums = {
2 | names(enums: E): string[] {
3 | return Object.values(enums).filter((v) => typeof v === 'string');
4 | },
5 |
6 | values(enums: E): number[] {
7 | return Object.values(enums).filter((v) => typeof v === 'number');
8 | },
9 |
10 | toValue(
11 | enums: E,
12 | value: any,
13 | ): number | undefined {
14 | if (value in enums) return typeof value === 'string' ? enums[value] : value;
15 | return undefined;
16 | },
17 |
18 | toValues(enums: E, value: any): number[] {
19 | if (typeof value === 'number') {
20 | return this.values(enums).filter((v) => (value & v) === v);
21 | }
22 | if (typeof value === 'string') {
23 | value = value.split(',').map((o) => o.trim());
24 | }
25 | if (Array.isArray(value) && value.every((v) => v in enums)) {
26 | return value.map((o) => this.toValue(enums, o) as number);
27 | }
28 | return [];
29 | },
30 |
31 | toName(
32 | enums: E,
33 | value: any,
34 | ): string | undefined {
35 | if (value in enums) return typeof value === 'number' ? enums[value] : value;
36 | return undefined;
37 | },
38 |
39 | toNames(enums: E, value: any): string[] {
40 | if (typeof value === 'number') {
41 | return this.values(enums)
42 | .filter((v) => (value & v) === v)
43 | .map((v) => this.toName(enums, v) as string);
44 | }
45 | if (typeof value === 'string') {
46 | value = value.split(',').map((o) => o.trim());
47 | }
48 | if (Array.isArray(value) && value.every((v) => v in enums)) {
49 | return value.map((o) => this.toName(enums, o) as string);
50 | }
51 | return [];
52 | },
53 |
54 | toFlags(enums: E, value: any): string[] {
55 | if (typeof value === 'number') {
56 | return this.values(enums)
57 | .filter((v) => v !== 0 && (value & v) === v)
58 | .map((v) => this.toName(enums, v) as string);
59 | }
60 | if (typeof value === 'string') {
61 | value = value.split(',').map((o) => o.trim());
62 | }
63 | if (Array.isArray(value) && value.every((v) => v in enums)) {
64 | return value
65 | .filter((v) => enums[v])
66 | .map((v) => this.toName(enums, v) as string);
67 | }
68 | return [];
69 | },
70 | };
71 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/http.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import { Http } from './http';
3 |
4 | describe('Http', () => {
5 | it('should merge headers', () => {
6 | const headers = Http.mergeHttpHeaders(
7 | {
8 | 'Content-Type': 'application/json',
9 | },
10 | {
11 | Authorization: 'Bearer token',
12 | 'Content-Type': '*/*',
13 | },
14 | );
15 | expect(headers.get('Authorization')).toEqual('Bearer token');
16 | expect(headers.getAll('Content-Type')).toEqual(['application/json', '*/*']);
17 | });
18 |
19 | it('should merge params', () => {
20 | const params = Http.mergeHttpParams(
21 | {
22 | param1: 'value1',
23 | param2: 'value2',
24 | params: ['value1'],
25 | },
26 | {
27 | param3: 'value3',
28 | params: ['value2', 'value3', 'value4'],
29 | },
30 | {
31 | params: ['value5', 'value6'],
32 | param4: 'value4',
33 | },
34 | );
35 | expect(params.toString()).toEqual(
36 | 'param1=value1¶m2=value2¶ms=value1¶ms=value2¶ms=value3¶ms=value4¶ms=value5¶ms=value6¶m3=value3¶m4=value4',
37 | );
38 | });
39 |
40 | it('should split params', () => {
41 | const params = Http.mergeHttpParams(
42 | {
43 | param1: 'value1',
44 | param2: 'value2',
45 | params: ['value1'],
46 | },
47 | {
48 | param3: 'value3',
49 | params: ['value2', 'value3', 'value4'],
50 | },
51 | {
52 | params: ['value5', 'value6'],
53 | param4: 'value4',
54 | },
55 | );
56 | let [param1, param2] = Http.splitHttpParams(params, ['param1', 'param2']);
57 | expect(param1.toString()).toEqual(
58 | 'params=value1¶ms=value2¶ms=value3¶ms=value4¶ms=value5¶ms=value6¶m3=value3¶m4=value4',
59 | );
60 | expect(param2.toString()).toEqual('param1=value1¶m2=value2');
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from './dates';
2 | export * from './durations';
3 | export * from './enums';
4 | export * from './http';
5 | export * from './objects';
6 | export * from './odata';
7 | export * from './strings';
8 | export * from './types';
9 | export * from './urls';
10 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/odata.ts:
--------------------------------------------------------------------------------
1 | import { CALLABLE_BINDING_PARAMETER } from '../constants';
2 | import { ODataCallableConfig } from '../types';
3 | import { Objects } from './objects';
4 |
5 | export const OData = {
6 | // Merge callables parameters
7 | mergeCallableParameters(
8 | callables: ODataCallableConfig[],
9 | ): ODataCallableConfig[] {
10 | const areEqual = (a: ODataCallableConfig, b: ODataCallableConfig) =>
11 | a.name === b.name &&
12 | Objects.equal(
13 | (a.parameters || {})[CALLABLE_BINDING_PARAMETER] || {},
14 | (b.parameters || {})[CALLABLE_BINDING_PARAMETER] || {},
15 | );
16 | return callables.reduce((acc: ODataCallableConfig[], config) => {
17 | if (acc.every((c) => !areEqual(c, config))) {
18 | config = callables
19 | .filter((c) => areEqual(c, config))
20 | .reduce((acc, c) => {
21 | acc.parameters = Object.assign(
22 | acc.parameters || {},
23 | c.parameters || {},
24 | );
25 | return acc;
26 | }, config);
27 | return [...acc, config];
28 | }
29 | return acc;
30 | }, [] as ODataCallableConfig[]);
31 | },
32 | };
33 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/strings.spec.ts:
--------------------------------------------------------------------------------
1 | import { Strings } from './strings';
2 |
3 | describe('Strings', () => {
4 | it('should convert to title case', () => {
5 | expect(Strings.titleCase('hiWorld')).toEqual('Hi World');
6 | expect(Strings.titleCase('world')).toEqual('World');
7 | expect(Strings.titleCase('anitaLavaLaTina')).toEqual('Anita Lava La Tina');
8 | expect(Strings.titleCase('PascalCase')).toEqual('Pascal Case');
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/strings.ts:
--------------------------------------------------------------------------------
1 | // From https://github.com/adamhalasz/uniqid
2 | var glast: number;
3 | function now() {
4 | let time = Date.now();
5 | let last = glast || time;
6 | return (glast = time > last ? time : last + 1);
7 | }
8 | export const Strings = {
9 | uniqueId({
10 | prefix,
11 | suffix,
12 | }: { prefix?: string; suffix?: string } = {}): string {
13 | return (prefix ? prefix : '') + now().toString(36) + (suffix ? suffix : '');
14 | },
15 |
16 | titleCase(text: string): string {
17 | const result = text.replace(/([a-z])([A-Z])/g, '$1 $2');
18 | return result
19 | .split(' ')
20 | .map((p) => p.charAt(0).toUpperCase() + p.slice(1))
21 | .join(' ');
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/lib/utils/urls.ts:
--------------------------------------------------------------------------------
1 | import { PARAM_SEPARATOR, VALUE_SEPARATOR } from '../constants';
2 |
3 | export const Urls = {
4 | parseQueryString(query: string) {
5 | return query.split(PARAM_SEPARATOR).reduce((acc, param: string) => {
6 | let index = param.indexOf(VALUE_SEPARATOR);
7 | if (index !== -1)
8 | Object.assign(acc, {
9 | [param.substring(0, index)]: param.substring(index + 1),
10 | });
11 | return acc;
12 | }, {});
13 | },
14 | escapeIllegalChars(string: string) {
15 | string = string.replace(/%/g, '%25');
16 | string = string.replace(/\+/g, '%2B');
17 | string = string.replace(/\//g, '%2F');
18 | string = string.replace(/\?/g, '%3F');
19 | string = string.replace(/#/g, '%23');
20 | string = string.replace(/&/g, '%26');
21 | string = string.replace(/'/g, "''");
22 | return string;
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/projects/angular-odata/src/public-api.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of angular-odata
3 | */
4 |
5 | export * from './lib';
6 |
--------------------------------------------------------------------------------
/projects/angular-odata/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
3 | {
4 | "extends": "../../tsconfig.json",
5 | "compilerOptions": {
6 | "outDir": "../../out-tsc/lib",
7 | "declaration": true,
8 | "declarationMap": true,
9 | "inlineSources": true,
10 | "types": []
11 | },
12 | "exclude": [
13 | "**/*.spec.ts"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/projects/angular-odata/tsconfig.lib.prod.json:
--------------------------------------------------------------------------------
1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
3 | {
4 | "extends": "./tsconfig.lib.json",
5 | "compilerOptions": {
6 | "declarationMap": false
7 | },
8 | "angularCompilerOptions": {
9 | "compilationMode": "partial"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/projects/angular-odata/tsconfig.schematics.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "lib": [
5 | "es2018",
6 | "dom"
7 | ],
8 | "declaration": true,
9 | "module": "commonjs",
10 | "moduleResolution": "node",
11 | "noEmitOnError": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "noImplicitAny": true,
14 | "noImplicitThis": true,
15 | "noUnusedParameters": false,
16 | "noUnusedLocals": false,
17 | "rootDir": "schematics",
18 | "outDir": "../../dist/angular-odata/schematics",
19 | "skipDefaultLibCheck": true,
20 | "skipLibCheck": true,
21 | "sourceMap": true,
22 | "strictNullChecks": true,
23 | "target": "es6",
24 | "types": [
25 | "jasmine",
26 | "node"
27 | ]
28 | },
29 | "include": [
30 | "schematics/**/*"
31 | ],
32 | "exclude": [
33 | "schematics/*/files/**/*"
34 | ]
35 | }
--------------------------------------------------------------------------------
/projects/angular-odata/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
3 | {
4 | "extends": "../../tsconfig.json",
5 | "compilerOptions": {
6 | "outDir": "../../out-tsc/spec",
7 | "types": [
8 | "jasmine"
9 | ]
10 | },
11 | "include": [
12 | "**/*.spec.ts",
13 | "**/*.d.ts"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
3 | {
4 | "compileOnSave": false,
5 | "compilerOptions": {
6 | "paths": {
7 | "angular-odata": [
8 | "./dist/angular-odata"
9 | ]
10 | },
11 | "outDir": "./dist/out-tsc",
12 | "strict": true,
13 | "noImplicitOverride": true,
14 | "noPropertyAccessFromIndexSignature": true,
15 | "noImplicitReturns": true,
16 | "noFallthroughCasesInSwitch": true,
17 | "skipLibCheck": true,
18 | "isolatedModules": true,
19 | "esModuleInterop": true,
20 | "experimentalDecorators": true,
21 | "moduleResolution": "bundler",
22 | "importHelpers": true,
23 | "target": "ES2022",
24 | "module": "ES2022"
25 | },
26 | "angularCompilerOptions": {
27 | "enableI18nLegacyMessageIdFormat": false,
28 | "strictInjectionParameters": true,
29 | "strictInputAccessModifiers": true,
30 | "strictTemplates": true
31 | }
32 | }
33 |
--------------------------------------------------------------------------------