mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-16 16:39:19 +02:00
* OData and Office365 REST API support
git-svn-id: trunk@34097 -
This commit is contained in:
parent
1606976cfa
commit
9115dc2521
32
.gitattributes
vendored
32
.gitattributes
vendored
@ -6222,6 +6222,38 @@ packages/objcrtl/src/objcrtl20.pas svneol=native#text/plain
|
|||||||
packages/objcrtl/src/objcrtliphoneos.pas svneol=native#text/plain
|
packages/objcrtl/src/objcrtliphoneos.pas svneol=native#text/plain
|
||||||
packages/objcrtl/src/objcrtlmacosx.pas svneol=native#text/plain
|
packages/objcrtl/src/objcrtlmacosx.pas svneol=native#text/plain
|
||||||
packages/objcrtl/src/objcrtlutils.pas svneol=native#text/plain
|
packages/objcrtl/src/objcrtlutils.pas svneol=native#text/plain
|
||||||
|
packages/odata/Makefile svneol=native#text/plain
|
||||||
|
packages/odata/Makefile.fpc svneol=native#text/plain
|
||||||
|
packages/odata/examples/README.txt svneol=native#text/plain
|
||||||
|
packages/odata/examples/groups/demousersgroups.lpi svneol=native#text/plain
|
||||||
|
packages/odata/examples/groups/demousersgroups.pp svneol=native#text/plain
|
||||||
|
packages/odata/examples/groups/msgraph.ini svneol=native#text/plain
|
||||||
|
packages/odata/examples/onedrive/demoonedrive.lpi svneol=native#text/plain
|
||||||
|
packages/odata/examples/onedrive/demoonedrive.pp svneol=native#text/plain
|
||||||
|
packages/odata/examples/onedrive/msgraph.ini svneol=native#text/plain
|
||||||
|
packages/odata/examples/v4/testv4.lpi svneol=native#text/plain
|
||||||
|
packages/odata/examples/v4/testv4.pp svneol=native#text/plain
|
||||||
|
packages/odata/examples/v4/v4sample.pas svneol=native#text/plain
|
||||||
|
packages/odata/examples/v4/v4sample.xml svneol=native#text/plain
|
||||||
|
packages/odata/fpmake.pp svneol=native#text/plain
|
||||||
|
packages/odata/regen.sh svneol=native#text/plain
|
||||||
|
packages/odata/src/msgraph.pp svneol=native#text/plain
|
||||||
|
packages/odata/src/odatabase.pp svneol=native#text/plain
|
||||||
|
packages/odata/src/odataservice.pp svneol=native#text/plain
|
||||||
|
packages/odata/src/office365client.pp svneol=native#text/plain
|
||||||
|
packages/odata/src/sharepoint.pp svneol=native#text/plain
|
||||||
|
packages/odata/utils/README.txt svneol=native#text/plain
|
||||||
|
packages/odata/utils/cgs.pas svneol=native#text/plain
|
||||||
|
packages/odata/utils/convertedmx.lpi svneol=native#text/plain
|
||||||
|
packages/odata/utils/convertedmx.pp svneol=native#text/plain
|
||||||
|
packages/odata/utils/csdl.pp svneol=native#text/plain
|
||||||
|
packages/odata/utils/csdl2pas.pp svneol=native#text/plain
|
||||||
|
packages/odata/utils/edm.pas svneol=native#text/plain
|
||||||
|
packages/odata/utils/edmx2pas.pp svneol=native#text/plain
|
||||||
|
packages/odata/utils/odatacodegen.pp svneol=native#text/plain
|
||||||
|
packages/odata/utils/ras.pas svneol=native#text/plain
|
||||||
|
packages/odata/xml/msgraph.xml svneol=native#text/plain
|
||||||
|
packages/odata/xml/sharepoint.xml svneol=native#text/plain
|
||||||
packages/odbc/Makefile svneol=native#text/plain
|
packages/odbc/Makefile svneol=native#text/plain
|
||||||
packages/odbc/Makefile.fpc svneol=native#text/plain
|
packages/odbc/Makefile.fpc svneol=native#text/plain
|
||||||
packages/odbc/Makefile.fpc.fpcmake svneol=native#text/plain
|
packages/odbc/Makefile.fpc.fpcmake svneol=native#text/plain
|
||||||
|
@ -127,4 +127,6 @@
|
|||||||
add_libenet(ADirectory+IncludeTrailingPathDelimiter('libenet'));
|
add_libenet(ADirectory+IncludeTrailingPathDelimiter('libenet'));
|
||||||
add_zorba(ADirectory+IncludeTrailingPathDelimiter('zorba'));
|
add_zorba(ADirectory+IncludeTrailingPathDelimiter('zorba'));
|
||||||
add_Google(ADirectory+IncludeTrailingPathDelimiter('googleapi'));
|
add_Google(ADirectory+IncludeTrailingPathDelimiter('googleapi'));
|
||||||
add_fcl_pdf(ADirectory+IncludeTrailingPathDelimiter('fcl-pdf'));
|
add_fcl_pdf(ADirectory+IncludeTrailingPathDelimiter('fcl-pdf'));
|
||||||
|
add_odata(ADirectory+IncludeTrailingPathDelimiter('odata'));
|
||||||
|
|
@ -736,3 +736,5 @@ begin
|
|||||||
with Installer do
|
with Installer do
|
||||||
{$include fcl-pdf/fpmake.pp}
|
{$include fcl-pdf/fpmake.pp}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{$include odata/fpmake.pp}
|
||||||
|
2713
packages/odata/Makefile
Normal file
2713
packages/odata/Makefile
Normal file
File diff suppressed because it is too large
Load Diff
102
packages/odata/Makefile.fpc
Normal file
102
packages/odata/Makefile.fpc
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#
|
||||||
|
# Makefile.fpc for running fpmake
|
||||||
|
#
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name=odata
|
||||||
|
version=3.1.1
|
||||||
|
|
||||||
|
[require]
|
||||||
|
packages=rtl fpmkunit fcl-base fcl-web
|
||||||
|
|
||||||
|
[install]
|
||||||
|
fpcpackage=y
|
||||||
|
|
||||||
|
[default]
|
||||||
|
fpcdir=../..
|
||||||
|
|
||||||
|
[prerules]
|
||||||
|
FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT))
|
||||||
|
ifdef OS_TARGET
|
||||||
|
FPC_TARGETOPT+=--os=$(OS_TARGET)
|
||||||
|
endif
|
||||||
|
ifdef CPU_TARGET
|
||||||
|
FPC_TARGETOPT+=--cpu=$(CPU_TARGET)
|
||||||
|
endif
|
||||||
|
LOCALFPMAKE=./fpmake$(SRCEXEEXT)
|
||||||
|
|
||||||
|
[rules]
|
||||||
|
# Do not pass the Makefile's unit and binary target locations. Fpmake uses it's own.
|
||||||
|
override FPCOPT:=$(filter-out -FU%,$(FPCOPT))
|
||||||
|
override FPCOPT:=$(filter-out -FE%,$(FPCOPT))
|
||||||
|
# Do not pass the package-unitdirectories. Fpmake adds those and this way they don't apear in the .fpm
|
||||||
|
override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters
|
||||||
|
# Compose general fpmake-parameters
|
||||||
|
ifdef FPMAKEOPT
|
||||||
|
FPMAKE_OPT+=$(FPMAKEOPT)
|
||||||
|
endif
|
||||||
|
FPMAKE_OPT+=--localunitdir=../..
|
||||||
|
FPMAKE_OPT+=--globalunitdir=..
|
||||||
|
FPMAKE_OPT+=$(FPC_TARGETOPT)
|
||||||
|
FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT))
|
||||||
|
FPMAKE_OPT+=--compiler=$(FPC)
|
||||||
|
FPMAKE_OPT+=-bu
|
||||||
|
.NOTPARALLEL:
|
||||||
|
|
||||||
|
fpmake$(SRCEXEEXT): fpmake.pp
|
||||||
|
$(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT)
|
||||||
|
all: fpmake$(SRCEXEEXT)
|
||||||
|
$(LOCALFPMAKE) compile $(FPMAKE_OPT)
|
||||||
|
smart: fpmake$(SRCEXEEXT)
|
||||||
|
$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX
|
||||||
|
release: fpmake$(SRCEXEEXT)
|
||||||
|
$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE
|
||||||
|
debug: fpmake$(SRCEXEEXT)
|
||||||
|
$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG
|
||||||
|
# If no fpmake exists and (dist)clean is called, do not try to build fpmake, it will
|
||||||
|
# most often fail because the dependencies are cleared.
|
||||||
|
# In case of a clean, simply do nothing
|
||||||
|
ifeq ($(FPMAKE_BIN_CLEAN),)
|
||||||
|
clean:
|
||||||
|
else
|
||||||
|
clean:
|
||||||
|
$(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT)
|
||||||
|
endif
|
||||||
|
# In case of a distclean, perform an 'old'-style distclean. This to avoid problems
|
||||||
|
# when the package is compiled using fpcmake prior to running this clean using fpmake
|
||||||
|
ifeq ($(FPMAKE_BIN_CLEAN),)
|
||||||
|
distclean: $(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall
|
||||||
|
else
|
||||||
|
distclean:
|
||||||
|
ifdef inUnix
|
||||||
|
{ $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi; }
|
||||||
|
else
|
||||||
|
$(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT)
|
||||||
|
endif
|
||||||
|
-$(DEL) $(LOCALFPMAKE)
|
||||||
|
endif
|
||||||
|
cleanall: distclean
|
||||||
|
install: fpmake$(SRCEXEEXT)
|
||||||
|
ifdef UNIXHier
|
||||||
|
$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR)
|
||||||
|
else
|
||||||
|
$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR)
|
||||||
|
endif
|
||||||
|
# distinstall also installs the example-sources and omits the location of the source-
|
||||||
|
# files from the fpunits.cfg files.
|
||||||
|
distinstall: fpmake$(SRCEXEEXT)
|
||||||
|
ifdef UNIXHier
|
||||||
|
$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
|
||||||
|
else
|
||||||
|
$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
|
||||||
|
endif
|
||||||
|
zipinstall: fpmake$(SRCEXEEXT)
|
||||||
|
$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX)
|
||||||
|
zipdistinstall: fpmake$(SRCEXEEXT)
|
||||||
|
$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0
|
||||||
|
zipsourceinstall: fpmake$(SRCEXEEXT)
|
||||||
|
ifdef UNIXHier
|
||||||
|
$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\)
|
||||||
|
else
|
||||||
|
$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\)
|
||||||
|
endif
|
21
packages/odata/examples/README.txt
Normal file
21
packages/odata/examples/README.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
group and onedrive demo
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
These demos demonstrate the new unified Office365 REST API.
|
||||||
|
|
||||||
|
For the group and onedrive demos to work, you need
|
||||||
|
- a Client ID
|
||||||
|
- a Secret key
|
||||||
|
- a hosted domain
|
||||||
|
All on Microsoft Office365 (Azure AD).
|
||||||
|
|
||||||
|
The ID and key can be obtained by registering your application in the Azure
|
||||||
|
AD of your hosted domain.
|
||||||
|
|
||||||
|
V4sample
|
||||||
|
--------
|
||||||
|
|
||||||
|
The V4Sample is a demonstration of the sample V4 service on www.odata.org
|
||||||
|
Not all calls are demonstrated, but enough to get an idea of how it works.
|
||||||
|
|
61
packages/odata/examples/groups/demousersgroups.lpi
Normal file
61
packages/odata/examples/groups/demousersgroups.lpi
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<Version Value="9"/>
|
||||||
|
<General>
|
||||||
|
<Flags>
|
||||||
|
<MainUnitHasCreateFormStatements Value="False"/>
|
||||||
|
</Flags>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
|
<MainUnit Value="0"/>
|
||||||
|
<Title Value="OneDrive Demo Command-line Application"/>
|
||||||
|
<UseAppBundle Value="False"/>
|
||||||
|
<ResourceType Value="res"/>
|
||||||
|
</General>
|
||||||
|
<VersionInfo>
|
||||||
|
<StringTable ProductVersion=""/>
|
||||||
|
</VersionInfo>
|
||||||
|
<BuildModes Count="1">
|
||||||
|
<Item1 Name="Default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<local>
|
||||||
|
<FormatVersion Value="1"/>
|
||||||
|
<CommandLineParams Value="-s 'robby@wisad.be'"/>
|
||||||
|
</local>
|
||||||
|
</RunParams>
|
||||||
|
<Units Count="1">
|
||||||
|
<Unit0>
|
||||||
|
<Filename Value="demousersgroups.pp"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit0>
|
||||||
|
</Units>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<Target>
|
||||||
|
<Filename Value="demousersgroups"/>
|
||||||
|
</Target>
|
||||||
|
<SearchPaths>
|
||||||
|
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||||
|
<OtherUnitFiles Value="../../units/$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
</SearchPaths>
|
||||||
|
</CompilerOptions>
|
||||||
|
<Debugging>
|
||||||
|
<Exceptions Count="3">
|
||||||
|
<Item1>
|
||||||
|
<Name Value="EAbort"/>
|
||||||
|
</Item1>
|
||||||
|
<Item2>
|
||||||
|
<Name Value="ECodetoolError"/>
|
||||||
|
</Item2>
|
||||||
|
<Item3>
|
||||||
|
<Name Value="EFOpenError"/>
|
||||||
|
</Item3>
|
||||||
|
</Exceptions>
|
||||||
|
</Debugging>
|
||||||
|
</CONFIG>
|
206
packages/odata/examples/groups/demousersgroups.pp
Normal file
206
packages/odata/examples/groups/demousersgroups.pp
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
program demousersgroups;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, CustApp, jsonparser, fphttpwebclient, fpoauth2ini,
|
||||||
|
restbase, odatabase, msgraph, office365client;
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TGroupsDemoApplication }
|
||||||
|
|
||||||
|
TGroupsDemoApplication = class(TCustomApplication)
|
||||||
|
private
|
||||||
|
FSession,
|
||||||
|
FLogFile,
|
||||||
|
FConfig : String;
|
||||||
|
FCLient : TOffice365Client;
|
||||||
|
FGS : TService;
|
||||||
|
FGraph : TGraphService;
|
||||||
|
FMaxLevel : Integer;
|
||||||
|
procedure EnsureService;
|
||||||
|
procedure GetUserGroups(AUser: String);
|
||||||
|
procedure GetGroupMembers(AGroup : String);
|
||||||
|
procedure ShowUsers;
|
||||||
|
procedure ShowGroups;
|
||||||
|
protected
|
||||||
|
procedure DoRun; override;
|
||||||
|
public
|
||||||
|
constructor Create(TheOwner: TComponent); override;
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure WriteHelp(Msg : String); virtual;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TGroupsDemoApplication.EnsureService;
|
||||||
|
|
||||||
|
Var
|
||||||
|
FIS : TFPOAuth2IniStore;
|
||||||
|
|
||||||
|
begin
|
||||||
|
// Auth client
|
||||||
|
FCLient:=TOffice365Client.Create(Self);
|
||||||
|
FClient.WebClient:=TFPHTTPWebClient.Create(Self);
|
||||||
|
FClient.WebClient.LogFile:=FLogFile;
|
||||||
|
FClient.AuthHandler:=TAzureADOAuth2Handler.Create(Self);
|
||||||
|
FIS:=TFPOAuth2IniStore.Create(Self);
|
||||||
|
|
||||||
|
FIS.ConfigFileName:=FConfig;
|
||||||
|
FIS.SessionFileName:=FConfig;
|
||||||
|
FClient.AuthHandler.Store:=FIS;
|
||||||
|
FClient.AuthHandler.LoadConfig();
|
||||||
|
FClient.AuthHandler.LoadSession(FSession);
|
||||||
|
FClient.AuthHandler.Config.AuthScope:='https://graph.microsoft.com/';
|
||||||
|
FClient.WebClient.RequestSigner:=FClient.AuthHandler;
|
||||||
|
FClient.AuthHandler.WebClient:=FClient.WebClient;
|
||||||
|
// Service
|
||||||
|
FGS:=TService.Create(Self);
|
||||||
|
FGS.ServiceURL:='https://graph.microsoft.com/v1.0/';
|
||||||
|
FGS.APINeedsAuth:=True;
|
||||||
|
FGS.WebClient:=FClient.WebClient;
|
||||||
|
// Default container
|
||||||
|
FGraph:=FGS.GraphService;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TGroupsDemoApplication.GetUserGroups(AUser: String);
|
||||||
|
|
||||||
|
Var
|
||||||
|
DOES : TdirectoryObjectsEntitySet;
|
||||||
|
L : TdirectoryObjectArray;
|
||||||
|
D : TdirectoryObject;
|
||||||
|
U : TUser;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if AUser='' then
|
||||||
|
U:=FGraph.me
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
U:=FGraph.users.Get(AUser);
|
||||||
|
U.BasePath:='/users/'+AUser;
|
||||||
|
end;
|
||||||
|
DOES:=U.memberOf(FGS);
|
||||||
|
L:=Does.ListAll('');
|
||||||
|
For D in L do
|
||||||
|
begin
|
||||||
|
Writeln('ID ',D.id,': ',D.additionalProperties.AsJSON);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TGroupsDemoApplication.GetGroupMembers(AGroup: String);
|
||||||
|
|
||||||
|
Var
|
||||||
|
G : TGroup;
|
||||||
|
DA : TDirectoryObjectArray;
|
||||||
|
D : TDirectoryObject;
|
||||||
|
|
||||||
|
begin
|
||||||
|
G:=FGraph.groups.get(agroup);
|
||||||
|
G.BasePath:='/groups/'+G.Id;
|
||||||
|
DA:=G.members(FGS).ListAll('');
|
||||||
|
for D in DA do
|
||||||
|
begin
|
||||||
|
Writeln('Member ',D.Id,': ',D.additionalProperties.AsJSON);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TGroupsDemoApplication }
|
||||||
|
|
||||||
|
procedure TGroupsDemoApplication.DoRun;
|
||||||
|
var
|
||||||
|
FUser,ErrorMsg: String;
|
||||||
|
begin
|
||||||
|
// quick check parameters
|
||||||
|
ErrorMsg:=CheckOptions('hl:r:c:s:u:UGg',['help','recurse:','logfile:','config:','session:','user:','users','groups','group']);
|
||||||
|
if (ErrorMsg<>'') or HasOption('h', 'help') then
|
||||||
|
WriteHelp(ErrorMsg);
|
||||||
|
FLogFile:=GetOptionValue('l','logfile');
|
||||||
|
if FLogFile='' then
|
||||||
|
FLogFile:=ExtractFilePath(ParamStr(0))+'requests.log';
|
||||||
|
FConfig:=GetOptionValue('c','config');
|
||||||
|
if FConfig='' then
|
||||||
|
FConfig:=ExtractFilePath(ParamStr(0))+'msgraph.ini';
|
||||||
|
FMaxLevel:=StrToIntDef(GetOptionValue('r','recurse'),3);
|
||||||
|
FSession:=GetOptionValue('s','session');
|
||||||
|
FUser:=getOptionValue('u','user');
|
||||||
|
if (FSession='') then
|
||||||
|
WriteHelp('Need session');
|
||||||
|
If FMaxLevel<2 then
|
||||||
|
FMaxLevel:=2;
|
||||||
|
EnsureService;
|
||||||
|
if HasOption('G','groups') then
|
||||||
|
ShowGroups
|
||||||
|
else if HasOption('U','users') then
|
||||||
|
ShowUsers
|
||||||
|
else if HasOption('g','group') then
|
||||||
|
GetGroupMembers(GetOptionValue('g','group'))
|
||||||
|
else
|
||||||
|
GetUserGroups(FUser);
|
||||||
|
Terminate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TGroupsDemoApplication.ShowUsers;
|
||||||
|
|
||||||
|
Var
|
||||||
|
L : TUserArray;
|
||||||
|
U : TUser;
|
||||||
|
|
||||||
|
begin
|
||||||
|
L:=FGraph.users.ListAll('');
|
||||||
|
for U in L do
|
||||||
|
begin
|
||||||
|
Writeln('User ',U.Id,' : ',U.DisplayName,', givenName:',U.givenName,', email: ',U.mail);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TGroupsDemoApplication.ShowGroups;
|
||||||
|
|
||||||
|
Var
|
||||||
|
L : TGroupArray;
|
||||||
|
G : TGroup;
|
||||||
|
|
||||||
|
begin
|
||||||
|
L:=FGraph.groups.ListAll('');
|
||||||
|
for G in L do
|
||||||
|
begin
|
||||||
|
Writeln('Group ',G.Id,' : ',G.DisplayName,', Mail:',G.mail);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TGroupsDemoApplication.Create(TheOwner: TComponent);
|
||||||
|
begin
|
||||||
|
inherited Create(TheOwner);
|
||||||
|
StopOnException:=True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TGroupsDemoApplication.Destroy;
|
||||||
|
begin
|
||||||
|
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TGroupsDemoApplication.WriteHelp(Msg: String);
|
||||||
|
begin
|
||||||
|
If Msg<>'' then
|
||||||
|
Writeln('Error : ',Msg);
|
||||||
|
Writeln('Usage: ', ExeName, ' -s session [options]');
|
||||||
|
Writeln('Where options : ');
|
||||||
|
Writeln('-h --help this help');
|
||||||
|
Writeln('-c --config config file with session and client data (default msgraph.ini)');
|
||||||
|
Writeln('-l --logfile config file with session and client data (default requests.log)');
|
||||||
|
Writeln('-s --session=name session to load from config file');
|
||||||
|
Writeln('-r --recurse=level maximum recursion level (defult 2)');
|
||||||
|
Halt(Ord(Msg<>''));
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
Application: TGroupsDemoApplication;
|
||||||
|
begin
|
||||||
|
Application:=TGroupsDemoApplication.Create(nil);
|
||||||
|
Application.Title:='OneDrive Demo Command-line Application';
|
||||||
|
Application.Run;
|
||||||
|
Application.Free;
|
||||||
|
end.
|
||||||
|
|
23
packages/odata/examples/groups/msgraph.ini
Normal file
23
packages/odata/examples/groups/msgraph.ini
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[Application]
|
||||||
|
; Enter your client_id here. You must get it from the AZure AD page where you registered the application
|
||||||
|
;client_id=
|
||||||
|
; Enter your client secret (secret key) here. You must get it from the AZure AD page where you registered the application
|
||||||
|
;client_secret=
|
||||||
|
redirect_uri=http://localhost:8080/Redirect
|
||||||
|
DeveloperKey=
|
||||||
|
OpenIDRealm=
|
||||||
|
access_type=atOnline
|
||||||
|
|
||||||
|
[Provider]
|
||||||
|
; Enter your HOSTED DOMAIN here, this is the domain registered in Microsoft Azure AD.
|
||||||
|
HostedDomain=
|
||||||
|
TokenURL=https://login.windows.net/%HostedDomain%/oauth2/token
|
||||||
|
AuthURL=https://login.windows.net/%HostedDomain%/oauth2/authorize
|
||||||
|
AuthScope=https://graph.microsoft.com/
|
||||||
|
|
||||||
|
[session_anonymous]
|
||||||
|
login_hint=
|
||||||
|
; You can enter an access token or refresh token here.
|
||||||
|
access_token=
|
||||||
|
refresh_token=
|
||||||
|
token_type=Bearer
|
61
packages/odata/examples/onedrive/demoonedrive.lpi
Normal file
61
packages/odata/examples/onedrive/demoonedrive.lpi
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<Version Value="9"/>
|
||||||
|
<General>
|
||||||
|
<Flags>
|
||||||
|
<MainUnitHasCreateFormStatements Value="False"/>
|
||||||
|
</Flags>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
|
<MainUnit Value="0"/>
|
||||||
|
<Title Value="OneDrive Demo Command-line Application"/>
|
||||||
|
<UseAppBundle Value="False"/>
|
||||||
|
<ResourceType Value="res"/>
|
||||||
|
</General>
|
||||||
|
<VersionInfo>
|
||||||
|
<StringTable ProductVersion=""/>
|
||||||
|
</VersionInfo>
|
||||||
|
<BuildModes Count="1">
|
||||||
|
<Item1 Name="Default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<local>
|
||||||
|
<FormatVersion Value="1"/>
|
||||||
|
<CommandLineParams Value="-s 'robby@wisad.be'"/>
|
||||||
|
</local>
|
||||||
|
</RunParams>
|
||||||
|
<Units Count="1">
|
||||||
|
<Unit0>
|
||||||
|
<Filename Value="demoonedrive.pp"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit0>
|
||||||
|
</Units>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<Target>
|
||||||
|
<Filename Value="demoonedrive"/>
|
||||||
|
</Target>
|
||||||
|
<SearchPaths>
|
||||||
|
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||||
|
<OtherUnitFiles Value="../../units/$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
</SearchPaths>
|
||||||
|
</CompilerOptions>
|
||||||
|
<Debugging>
|
||||||
|
<Exceptions Count="3">
|
||||||
|
<Item1>
|
||||||
|
<Name Value="EAbort"/>
|
||||||
|
</Item1>
|
||||||
|
<Item2>
|
||||||
|
<Name Value="ECodetoolError"/>
|
||||||
|
</Item2>
|
||||||
|
<Item3>
|
||||||
|
<Name Value="EFOpenError"/>
|
||||||
|
</Item3>
|
||||||
|
</Exceptions>
|
||||||
|
</Debugging>
|
||||||
|
</CONFIG>
|
212
packages/odata/examples/onedrive/demoonedrive.pp
Normal file
212
packages/odata/examples/onedrive/demoonedrive.pp
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
program demoonedrive;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, CustApp, jsonparser, fphttpwebclient, fpoauth2ini,
|
||||||
|
restbase, odatabase, msgraph, office365client;
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TOneDriveDemoApplication }
|
||||||
|
|
||||||
|
TOneDriveDemoApplication = class(TCustomApplication)
|
||||||
|
private
|
||||||
|
FSession,
|
||||||
|
FLogFile,
|
||||||
|
FConfig : String;
|
||||||
|
FGS : TService;
|
||||||
|
FGraph : TGraphService;
|
||||||
|
FDrive : TDrive;
|
||||||
|
FMaxLevel : Integer;
|
||||||
|
FClient : TOffice365Client;
|
||||||
|
Procedure DriveItemToTree(ALevel: Integer; AItem: TDriveItem);
|
||||||
|
procedure EnsureService;
|
||||||
|
procedure GetItemChildren(ALevel: Integer; R: TDriveItem);
|
||||||
|
procedure GetDriveItems;
|
||||||
|
procedure GetShareableLink(D: TDriveItem);
|
||||||
|
protected
|
||||||
|
procedure DoRun; override;
|
||||||
|
public
|
||||||
|
constructor Create(TheOwner: TComponent); override;
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure WriteHelp(Msg : String); virtual;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TOneDriveDemoApplication.EnsureService;
|
||||||
|
|
||||||
|
Var
|
||||||
|
FIS : TFPOAuth2IniStore;
|
||||||
|
|
||||||
|
begin
|
||||||
|
// Auth client
|
||||||
|
FClient:=TOffice365Client.Create(Self);
|
||||||
|
FClient.WebClient:=TFPHTTPWebClient.Create(Self);
|
||||||
|
FClient.WebClient.LogFile:=FLogFile;
|
||||||
|
FClient.AuthHandler:=TAzureADOAuth2Handler.Create(Self);
|
||||||
|
FIS:=TFPOAuth2IniStore.Create(Self);
|
||||||
|
|
||||||
|
FIS.ConfigFileName:=FConfig;
|
||||||
|
FIS.SessionFileName:=FConfig;
|
||||||
|
FClient.AuthHandler.Store:=FIS;
|
||||||
|
FClient.AuthHandler.LoadConfig();
|
||||||
|
FClient.AuthHandler.LoadSession(FSession);
|
||||||
|
FClient.AuthHandler.Config.AuthScope:='https://graph.microsoft.com/';
|
||||||
|
FClient.WebClient.RequestSigner:=FClient.AuthHandler;
|
||||||
|
FClient.AuthHandler.WebClient:=FClient.WebClient;
|
||||||
|
// Service
|
||||||
|
FGS:=TService.Create(Self);
|
||||||
|
FGS.ServiceURL:='https://graph.microsoft.com/v1.0/';
|
||||||
|
FGS.APINeedsAuth:=True;
|
||||||
|
FGS.WebClient:=FClient.WebClient;
|
||||||
|
// Default container
|
||||||
|
FGraph:=FGS.GraphService;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TOneDriveDemoApplication.DriveItemToTree(ALevel : Integer; AItem : TDriveItem) ;
|
||||||
|
|
||||||
|
Var
|
||||||
|
S : String;
|
||||||
|
I : integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
S:='';
|
||||||
|
For I:=1 to Alevel do
|
||||||
|
S:=S+' ';
|
||||||
|
if Assigned(AItem.folder) then
|
||||||
|
S:=S+'*- '
|
||||||
|
else
|
||||||
|
S:=S+'+- ';
|
||||||
|
Writeln(S,AItem.Name+' (URL: '+AItem.webUrl+')');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TOneDriveDemoApplication.GetItemChildren(ALevel: Integer;
|
||||||
|
R: TDriveItem);
|
||||||
|
|
||||||
|
Var
|
||||||
|
AR : TDriveItemArray;
|
||||||
|
I : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if Assigned(R.folder) and (R.folder.childCount>0) then
|
||||||
|
begin
|
||||||
|
AR:=FDrive.items(FGS).Get(R.id).children(FGS).ListAll('');
|
||||||
|
For I:=0 to Length(AR)-1 do
|
||||||
|
begin
|
||||||
|
DriveItemToTree(ALevel,AR[I]);
|
||||||
|
if (ALevel<FMaxLevel) then
|
||||||
|
GetItemChildren(ALevel+1,AR[I]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TOneDriveDemoApplication.GetDriveItems;
|
||||||
|
|
||||||
|
Var
|
||||||
|
Me : TUser;
|
||||||
|
R : TDriveItem;
|
||||||
|
AR : TDriveItemArray;
|
||||||
|
I,L : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Me:=FGraph.me;
|
||||||
|
FDrive:=Me.drive(FGS);
|
||||||
|
R:=FDrive.root(FGS);
|
||||||
|
DriveItemToTree(0,R);
|
||||||
|
// AR:=TDriveItemArray(FGS.ArrayServiceCall(FGS.ServiceURL+'me/drive/root/children',TdriveItem).Data);
|
||||||
|
AR:=R.children(FGS).ListAll('');
|
||||||
|
L:=Length(AR);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
begin
|
||||||
|
DriveItemToTree(1,AR[I]);
|
||||||
|
if Assigned(AR[I].folder) and (AR[I].folder.childCount>0) then
|
||||||
|
GetItemChildren(2,AR[I]);
|
||||||
|
end;
|
||||||
|
if L>0 then
|
||||||
|
GetShareableLink(AR[L-1]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TOneDriveDemoApplication.GetShareableLink(D : TDriveItem);
|
||||||
|
|
||||||
|
Var
|
||||||
|
P : Tpermission;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Writeln('Getting shareable link for item(',D.id, ') : ',D.name);
|
||||||
|
// By default, the Office365 API doesn't return @odata.id,
|
||||||
|
// and drive items are contained (i.e. not directly accessible through a entityset)
|
||||||
|
// so we set the base path manually.
|
||||||
|
D.BasePath:='/me/drive/items/'+D.ID;
|
||||||
|
P:=D.createLink(FGS,'view','organization');
|
||||||
|
try
|
||||||
|
if not Assigned(P.link) then
|
||||||
|
Writeln('No permissions link created')
|
||||||
|
else
|
||||||
|
Writeln('Shareable URL: ',P.link.webUrl);
|
||||||
|
finally
|
||||||
|
P.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TOneDriveDemoApplication }
|
||||||
|
|
||||||
|
procedure TOneDriveDemoApplication.DoRun;
|
||||||
|
var
|
||||||
|
ErrorMsg: String;
|
||||||
|
begin
|
||||||
|
// quick check parameters
|
||||||
|
ErrorMsg:=CheckOptions('hl:r:c:s:',['help','recurse:','logfile:','config:','session:']);
|
||||||
|
if (ErrorMsg<>'') or HasOption('h', 'help') then
|
||||||
|
WriteHelp(ErrorMsg);
|
||||||
|
FLogFile:=GetOptionValue('l','logfile');
|
||||||
|
if FLogFile='' then
|
||||||
|
FLogFile:=ExtractFilePath(ParamStr(0))+'requests.log';
|
||||||
|
FConfig:=GetOptionValue('c','config');
|
||||||
|
if FConfig='' then
|
||||||
|
FConfig:=ExtractFilePath(ParamStr(0))+'msgraph.ini';
|
||||||
|
FMaxLevel:=StrToIntDef(GetOptionValue('r','recurse'),3);
|
||||||
|
FSession:=GetOptionValue('s','session');
|
||||||
|
if (FSession='') then
|
||||||
|
WriteHelp('Need session');
|
||||||
|
If FMaxLevel<2 then
|
||||||
|
FMaxLevel:=2;
|
||||||
|
EnsureService;
|
||||||
|
GetDriveItems;
|
||||||
|
Terminate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TOneDriveDemoApplication.Create(TheOwner: TComponent);
|
||||||
|
begin
|
||||||
|
inherited Create(TheOwner);
|
||||||
|
StopOnException:=True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TOneDriveDemoApplication.Destroy;
|
||||||
|
begin
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TOneDriveDemoApplication.WriteHelp(Msg: String);
|
||||||
|
begin
|
||||||
|
If Msg<>'' then
|
||||||
|
Writeln('Error : ',Msg);
|
||||||
|
Writeln('Usage: ', ExeName, ' -s session [options]');
|
||||||
|
Writeln('Where options : ');
|
||||||
|
Writeln('-h --help this help');
|
||||||
|
Writeln('-c --config config file with session and client data (default msgraph.ini)');
|
||||||
|
Writeln('-l --logfile config file with session and client data (default requests.log)');
|
||||||
|
Writeln('-s --session=name session to load from config file');
|
||||||
|
Writeln('-r --recurse=level maximum recursion level (defult 2)');
|
||||||
|
Halt(Ord(Msg<>''));
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
Application: TOneDriveDemoApplication;
|
||||||
|
begin
|
||||||
|
Application:=TOneDriveDemoApplication.Create(nil);
|
||||||
|
Application.Title:='OneDrive Demo Command-line Application';
|
||||||
|
Application.Run;
|
||||||
|
Application.Free;
|
||||||
|
end.
|
||||||
|
|
23
packages/odata/examples/onedrive/msgraph.ini
Normal file
23
packages/odata/examples/onedrive/msgraph.ini
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[Application]
|
||||||
|
; Enter your client_id here. You must get it from the AZure AD page where you registered the application
|
||||||
|
;client_id=
|
||||||
|
; Enter your client secret (secret key) here. You must get it from the AZure AD page where you registered the application
|
||||||
|
;client_secret=
|
||||||
|
redirect_uri=http://localhost:8080/Redirect
|
||||||
|
DeveloperKey=
|
||||||
|
OpenIDRealm=
|
||||||
|
access_type=atOnline
|
||||||
|
|
||||||
|
[Provider]
|
||||||
|
; Enter your HOSTED DOMAIN here, this is the domain registered in Microsoft Azure AD.
|
||||||
|
HostedDomain=
|
||||||
|
TokenURL=https://login.windows.net/%HostedDomain%/oauth2/token
|
||||||
|
AuthURL=https://login.windows.net/%HostedDomain%/oauth2/authorize
|
||||||
|
AuthScope=https://graph.microsoft.com/
|
||||||
|
|
||||||
|
[session_anonymous]
|
||||||
|
login_hint=
|
||||||
|
; You can enter an access token or refresh token here.
|
||||||
|
access_token=
|
||||||
|
refresh_token=
|
||||||
|
token_type=Bearer
|
70
packages/odata/examples/v4/testv4.lpi
Normal file
70
packages/odata/examples/v4/testv4.lpi
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<Version Value="9"/>
|
||||||
|
<General>
|
||||||
|
<Flags>
|
||||||
|
<MainUnitHasCreateFormStatements Value="False"/>
|
||||||
|
<MainUnitHasTitleStatement Value="False"/>
|
||||||
|
</Flags>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
|
<MainUnit Value="0"/>
|
||||||
|
<Title Value="testv4"/>
|
||||||
|
<UseAppBundle Value="False"/>
|
||||||
|
<ResourceType Value="res"/>
|
||||||
|
</General>
|
||||||
|
<VersionInfo>
|
||||||
|
<StringTable ProductVersion=""/>
|
||||||
|
</VersionInfo>
|
||||||
|
<BuildModes Count="1">
|
||||||
|
<Item1 Name="Default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<local>
|
||||||
|
<FormatVersion Value="1"/>
|
||||||
|
</local>
|
||||||
|
</RunParams>
|
||||||
|
<Units Count="2">
|
||||||
|
<Unit0>
|
||||||
|
<Filename Value="testv4.pp"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit0>
|
||||||
|
<Unit1>
|
||||||
|
<Filename Value="v4sample.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit1>
|
||||||
|
</Units>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<Target>
|
||||||
|
<Filename Value="testv4"/>
|
||||||
|
</Target>
|
||||||
|
<SearchPaths>
|
||||||
|
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||||
|
<OtherUnitFiles Value="../../units/$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
</SearchPaths>
|
||||||
|
<Linking>
|
||||||
|
<Debugging>
|
||||||
|
<UseHeaptrc Value="True"/>
|
||||||
|
</Debugging>
|
||||||
|
</Linking>
|
||||||
|
</CompilerOptions>
|
||||||
|
<Debugging>
|
||||||
|
<Exceptions Count="3">
|
||||||
|
<Item1>
|
||||||
|
<Name Value="EAbort"/>
|
||||||
|
</Item1>
|
||||||
|
<Item2>
|
||||||
|
<Name Value="ECodetoolError"/>
|
||||||
|
</Item2>
|
||||||
|
<Item3>
|
||||||
|
<Name Value="EFOpenError"/>
|
||||||
|
</Item3>
|
||||||
|
</Exceptions>
|
||||||
|
</Debugging>
|
||||||
|
</CONFIG>
|
337
packages/odata/examples/v4/testv4.pp
Normal file
337
packages/odata/examples/v4/testv4.pp
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
program testv4;
|
||||||
|
|
||||||
|
uses classes, sysutils, jsonparser, odatabase, fpjson, fphttpwebclient, custapp, v4sample;
|
||||||
|
|
||||||
|
Type
|
||||||
|
|
||||||
|
{ TODataV4SampleServiceClientApp }
|
||||||
|
|
||||||
|
TODataV4SampleServiceClientApp = Class(TCustomApplication)
|
||||||
|
Private
|
||||||
|
FShowExtra : Boolean;
|
||||||
|
FDoDelete : Boolean;
|
||||||
|
FSavePhoto : Boolean;
|
||||||
|
FService:TService;
|
||||||
|
Protected
|
||||||
|
Procedure RunDemo;
|
||||||
|
// Unbound action
|
||||||
|
Procedure DoResetDataSource;
|
||||||
|
// Entityset
|
||||||
|
Procedure DoDumpAirLines;
|
||||||
|
// Contained entity, GetStream
|
||||||
|
Procedure DoPhoto(APerson: TPerson; DoSave: Boolean);
|
||||||
|
// Contained entityset
|
||||||
|
Procedure DoListFriends(P: TPerson; DeleteLast: Boolean);
|
||||||
|
// Delete
|
||||||
|
Procedure DoDeletePerson(P: TPerson);
|
||||||
|
// Bound Function
|
||||||
|
Procedure ShowFavoriteAirline(P: TPerson);
|
||||||
|
// Bound Function
|
||||||
|
Procedure ShowFriendsTrips(P: TPerson);
|
||||||
|
// Unbound Function
|
||||||
|
Procedure ShowNearestAirPort(ALat, ALon: Integer);
|
||||||
|
Public
|
||||||
|
Constructor Create(AOwner :TComponent); override;
|
||||||
|
Destructor Destroy; override;
|
||||||
|
procedure DoServiceLog(Sender: TObject; const Msg: String);
|
||||||
|
Procedure DumpExtra(A : TODataObject);
|
||||||
|
Procedure DoRun; override;
|
||||||
|
Procedure Usage(Const Msg : String);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Constructor TODataV4SampleServiceClientApp.Create(AOwner: TComponent);
|
||||||
|
begin
|
||||||
|
inherited Create(AOwner);
|
||||||
|
FService:=TService.Create(Self);
|
||||||
|
FService.WebClient:=TFPHTTPWebClient.Create(Self);
|
||||||
|
StopOnException:=True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Destructor TODataV4SampleServiceClientApp.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FService);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TODataV4SampleServiceClientApp.DoServiceLog(Sender: TObject;
|
||||||
|
const Msg: String);
|
||||||
|
begin
|
||||||
|
Writeln(StdErr,'Service log: ',Msg);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.DumpExtra(A : TODataObject);
|
||||||
|
|
||||||
|
Var
|
||||||
|
I : Integer;
|
||||||
|
|
||||||
|
Function PJ(J : TJSONData) : String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if J.JSONType in [jtArray,jtObject] then
|
||||||
|
Result:=J.FormatJSON
|
||||||
|
else
|
||||||
|
Result:=J.AsString;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if not FShowExtra then
|
||||||
|
exit;
|
||||||
|
if Assigned(A.additionalProperties) and (A.additionalProperties.Count>0) then
|
||||||
|
begin
|
||||||
|
Writeln(' Additional properties : ');
|
||||||
|
Writeln(' '+PJ(A.additionalProperties));
|
||||||
|
end;
|
||||||
|
if (A.ODataAnnotationCount>0) then
|
||||||
|
begin
|
||||||
|
Writeln(' Annotations:');
|
||||||
|
For I:=0 to A.ODataAnnotationCount-1 do
|
||||||
|
Writeln(' '+A.ODataAnnotations[i].Key,' : ',PJ(A.ODataAnnotations[i].Value));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.DoResetDataSource;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Writeln('Resetting data source');
|
||||||
|
FService.DefaultContainer.ResetDataSource;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.DoDumpAirLines;
|
||||||
|
|
||||||
|
Var
|
||||||
|
A : TAirline;
|
||||||
|
AA : TAirlineArray;
|
||||||
|
I : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
AA:=FService.DefaultContainer.Airlines.ListAll('');
|
||||||
|
try
|
||||||
|
Writeln('Number of arlines: ',Length(AA));
|
||||||
|
For I:=0 to Length(AA)-1 do
|
||||||
|
begin
|
||||||
|
A:=AA[i];
|
||||||
|
// Writeln('Base URL : ',A.BaseURL(FService));
|
||||||
|
Writeln('Airline ',I+1,' code : ',A.AirlineCode);
|
||||||
|
Writeln('Airline ',I+1,' name : ',A.Name);
|
||||||
|
DumpExtra(A);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
For I:=0 to Length(AA)-1 do
|
||||||
|
FreeAndNil(AA[i]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.DoDeletePerson(P : TPerson);
|
||||||
|
|
||||||
|
begin
|
||||||
|
Writeln('Attempting to delete person:');
|
||||||
|
try
|
||||||
|
Writeln(P.Delete(FService));
|
||||||
|
except
|
||||||
|
On EO : EOData do
|
||||||
|
begin
|
||||||
|
Writeln('OData error : ',EO.Message);
|
||||||
|
Writeln('Status code : ',EO.StatusCode,', text : ',EO.StatusText);
|
||||||
|
If Assigned(EO.Error) then
|
||||||
|
begin
|
||||||
|
Writeln('OData error code : ',EO.Error.Code,', message : ',EO.Error.Message);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
On E : Exception do
|
||||||
|
begin
|
||||||
|
Writeln('General Error : ',E.Message)
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.DoListFriends(P : TPerson; DeleteLast : Boolean);
|
||||||
|
|
||||||
|
Var
|
||||||
|
FES : TPeopleEntitySet;
|
||||||
|
PA : TPersonArray;
|
||||||
|
FL : TPerson;
|
||||||
|
I : integer;
|
||||||
|
F : TPerson;
|
||||||
|
|
||||||
|
begin
|
||||||
|
FES:=P.Friends(FService);
|
||||||
|
try
|
||||||
|
PA:=FES.ListAll('');
|
||||||
|
I:=0;
|
||||||
|
for F in PA do
|
||||||
|
begin
|
||||||
|
Inc(i);
|
||||||
|
Writeln('Friend ',I,': FirstName: ',F.FirstName,', LastName: ',F.LastName);
|
||||||
|
DumpExtra(F);
|
||||||
|
FL:=F;
|
||||||
|
end;
|
||||||
|
If DeleteLast and (FL<>Nil) then
|
||||||
|
DoDeletePerson(FL);
|
||||||
|
finally
|
||||||
|
For I:=0 to Length(PA)-1 do
|
||||||
|
FreeAndNil(PA[i]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.DoPhoto(APerson : TPerson; DoSave: Boolean);
|
||||||
|
|
||||||
|
Var
|
||||||
|
P : TPHoto;
|
||||||
|
PF : TFileStream;
|
||||||
|
|
||||||
|
begin
|
||||||
|
PF:=Nil;
|
||||||
|
P:=APerson.Photo(FService);
|
||||||
|
try
|
||||||
|
Writeln('Photo ID : ',P.Id,', name : ', P.Name);
|
||||||
|
DumpExtra(p);
|
||||||
|
if DoSave then
|
||||||
|
begin
|
||||||
|
PF:=TFileStream.Create('photo.jpg',fmCreate);
|
||||||
|
P.GetStream(FService,'image/jpeg',PF);
|
||||||
|
Writeln('Saved profile photo to photo.jpg');
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
P.Free;
|
||||||
|
PF.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.ShowFavoriteAirline(P : TPerson);
|
||||||
|
|
||||||
|
Var
|
||||||
|
A : TAirLine;
|
||||||
|
|
||||||
|
begin
|
||||||
|
A:=P.GetFavoriteAirline(FService);
|
||||||
|
try
|
||||||
|
Writeln('Favorite Airline:');
|
||||||
|
Writeln('Code: ',A.AirlineCode);
|
||||||
|
Writeln('Name: ',A.Name);
|
||||||
|
DumpExtra(A);
|
||||||
|
finally
|
||||||
|
A.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.ShowFriendsTrips(P : TPerson);
|
||||||
|
|
||||||
|
Var
|
||||||
|
TA : TTripArray;
|
||||||
|
I : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
TA:=P.GetFriendsTrips(FService,'russellwhyte');
|
||||||
|
try
|
||||||
|
For I:=0 to Length(TA)-1 do
|
||||||
|
Writeln('Trip [',i,'] : ',TA[i].Name);
|
||||||
|
finally
|
||||||
|
For I:=0 to Length(TA)-1 do
|
||||||
|
FreeAndNil(TA[i]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.ShowNearestAirPort(ALat,ALon : Integer);
|
||||||
|
|
||||||
|
Var
|
||||||
|
AP : TAirPort;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
Writeln('Nearest airport for (',alat,',',alon,') : ');
|
||||||
|
AP:=FService.DefaultContainer.GetNearestAirPort(Alat,ALon);
|
||||||
|
try
|
||||||
|
Writeln('Name : ',AP.Name);
|
||||||
|
Writeln('IATA code : ',AP.IataCode);
|
||||||
|
Writeln('ICAO code : ',AP.IcaoCode);
|
||||||
|
if Assigned(AP.Location) then
|
||||||
|
begin
|
||||||
|
Writeln('Address : ',AP.Location.Address);
|
||||||
|
Writeln('City : ',AP.Location.City.Name,' (Country: ',AP.Location.City.CountryRegion,', Region: ',AP.Location.City.Region,')');
|
||||||
|
if Assigned(AP.Location.Loc) then
|
||||||
|
With AP.Location.Loc do
|
||||||
|
Writeln('Location : ',Coordinates[0],',',Coordinates[1]);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
AP.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.DoRun;
|
||||||
|
|
||||||
|
Var
|
||||||
|
S : string;
|
||||||
|
|
||||||
|
begin
|
||||||
|
S:=CheckOptions('hdepl::u:D',['help','log::','delete','extra','photo','url:','debug']);
|
||||||
|
if (S<>'') or HasOption('h','help') then
|
||||||
|
Usage(S);
|
||||||
|
FShowExtra:=HasOption('e','extra');
|
||||||
|
FDoDelete:=HasOption('d','delete');
|
||||||
|
FSavePhoto:=HasOption('p','photo');
|
||||||
|
if HasOption('l','log') then
|
||||||
|
begin
|
||||||
|
S:=GetOptionValue('l','log');
|
||||||
|
if S='' then
|
||||||
|
S:='requests.log';
|
||||||
|
FService.WebClient.LogFile:=S;
|
||||||
|
end;
|
||||||
|
S:=GetOptionValue('u','url');
|
||||||
|
if S='' then
|
||||||
|
S:='http://services.odata.org/V4/TripPinServiceRW/';
|
||||||
|
FService.ServiceURL:=S;
|
||||||
|
if HasOption('D','debug') then
|
||||||
|
FService.OnLog:=@DoServiceLog;
|
||||||
|
RunDemo;
|
||||||
|
Terminate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.RunDemo;
|
||||||
|
|
||||||
|
Var
|
||||||
|
Me : TPerson;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Me:=Nil;
|
||||||
|
try
|
||||||
|
DoResetDataSource;
|
||||||
|
DoDumpAirLines;
|
||||||
|
Me:=FService.DefaultContainer.Me;
|
||||||
|
Writeln('Me.FirstName: ',Me.FirstName);
|
||||||
|
Writeln('Me.LastName: ',Me.LastName);
|
||||||
|
DumpExtra(Me);
|
||||||
|
DoListFriends(Me,FDoDelete);
|
||||||
|
DoPhoto(Me,FSavePhoto);
|
||||||
|
ShowFavoriteAirLine(Me);
|
||||||
|
ShowFriendsTrips(Me);
|
||||||
|
ShowNearestAirPort(40,45);
|
||||||
|
finally
|
||||||
|
FreeAndNil(Me);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataV4SampleServiceClientApp.Usage(Const Msg: String);
|
||||||
|
begin
|
||||||
|
Writeln('Error : ',Msg);
|
||||||
|
Writeln('Usage : ',ExeName,' [options]');
|
||||||
|
Writeln('Where options is one or more of:');
|
||||||
|
Writeln('-h --help This help');
|
||||||
|
Writeln('-d --delete Execute delete call on friend');
|
||||||
|
Writeln('-e --extra Show extra OData information');
|
||||||
|
Writeln('-l --log[=file] Dump requests and return to file (default is requests.log)');
|
||||||
|
Writeln('-p --photo Save pictore to photo.jpg');
|
||||||
|
Writeln('-u --url=URL Set Service url.');
|
||||||
|
Writeln('-D --debug Debug output');
|
||||||
|
Halt(Ord(Msg<>''));
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
With TODataV4SampleServiceClientApp.Create(Nil) do
|
||||||
|
try
|
||||||
|
Initialize;
|
||||||
|
Run;
|
||||||
|
finally
|
||||||
|
Free;
|
||||||
|
end;
|
||||||
|
end.
|
||||||
|
|
1808
packages/odata/examples/v4/v4sample.pas
Normal file
1808
packages/odata/examples/v4/v4sample.pas
Normal file
File diff suppressed because it is too large
Load Diff
335
packages/odata/examples/v4/v4sample.xml
Normal file
335
packages/odata/examples/v4/v4sample.xml
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
|
||||||
|
<edmx:DataServices>
|
||||||
|
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Microsoft.OData.SampleService.Models.TripPin">
|
||||||
|
<EnumType Name="PersonGender">
|
||||||
|
<Member Name="Male" Value="0"/>
|
||||||
|
<Member Name="Female" Value="1"/>
|
||||||
|
<Member Name="Unknown" Value="2"/>
|
||||||
|
</EnumType>
|
||||||
|
<ComplexType Name="City">
|
||||||
|
<Property Name="CountryRegion" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Property Name="Name" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Property Name="Region" Type="Edm.String" Nullable="false"/>
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Location" OpenType="true">
|
||||||
|
<Property Name="Address" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Property Name="City" Type="Microsoft.OData.SampleService.Models.TripPin.City" Nullable="false"/>
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="EventLocation" BaseType="Microsoft.OData.SampleService.Models.TripPin.Location" OpenType="true">
|
||||||
|
<Property Name="BuildingInfo" Type="Edm.String"/>
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="AirportLocation" BaseType="Microsoft.OData.SampleService.Models.TripPin.Location" OpenType="true">
|
||||||
|
<Property Name="Loc" Type="Edm.GeographyPoint" Nullable="false" SRID="4326"/>
|
||||||
|
</ComplexType>
|
||||||
|
<EntityType Name="Photo" HasStream="true">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="Id"/>
|
||||||
|
</Key>
|
||||||
|
<Property Name="Id" Type="Edm.Int64" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="Name" Type="Edm.String"/>
|
||||||
|
<Annotation Term="Org.OData.Core.V1.AcceptableMediaTypes">
|
||||||
|
<Collection>
|
||||||
|
<String>image/jpeg</String>
|
||||||
|
</Collection>
|
||||||
|
</Annotation>
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Person" OpenType="true">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="UserName"/>
|
||||||
|
</Key>
|
||||||
|
<Property Name="UserName" Type="Edm.String" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="FirstName" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Property Name="LastName" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Property Name="Emails" Type="Collection(Edm.String)"/>
|
||||||
|
<Property Name="AddressInfo" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Location)"/>
|
||||||
|
<Property Name="Gender" Type="Microsoft.OData.SampleService.Models.TripPin.PersonGender"/>
|
||||||
|
<Property Name="Concurrency" Type="Edm.Int64" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Computed" Bool="true"/>
|
||||||
|
</Property>
|
||||||
|
<NavigationProperty Name="Friends" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Person)"/>
|
||||||
|
<NavigationProperty Name="Trips" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Trip)" ContainsTarget="true"/>
|
||||||
|
<NavigationProperty Name="Photo" Type="Microsoft.OData.SampleService.Models.TripPin.Photo"/>
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Airline">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="AirlineCode"/>
|
||||||
|
</Key>
|
||||||
|
<Property Name="AirlineCode" Type="Edm.String" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="Name" Type="Edm.String" Nullable="false"/>
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Airport">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="IcaoCode"/>
|
||||||
|
</Key>
|
||||||
|
<Property Name="IcaoCode" Type="Edm.String" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="Name" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Property Name="IataCode" Type="Edm.String" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Immutable" Bool="true"/>
|
||||||
|
</Property>
|
||||||
|
<Property Name="Location" Type="Microsoft.OData.SampleService.Models.TripPin.AirportLocation" Nullable="false"/>
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="PlanItem">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="PlanItemId"/>
|
||||||
|
</Key>
|
||||||
|
<Property Name="PlanItemId" Type="Edm.Int32" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="ConfirmationCode" Type="Edm.String"/>
|
||||||
|
<Property Name="StartsAt" Type="Edm.DateTimeOffset"/>
|
||||||
|
<Property Name="EndsAt" Type="Edm.DateTimeOffset"/>
|
||||||
|
<Property Name="Duration" Type="Edm.Duration"/>
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="PublicTransportation" BaseType="Microsoft.OData.SampleService.Models.TripPin.PlanItem">
|
||||||
|
<Property Name="SeatNumber" Type="Edm.String"/>
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Flight" BaseType="Microsoft.OData.SampleService.Models.TripPin.PublicTransportation">
|
||||||
|
<Property Name="FlightNumber" Type="Edm.String" Nullable="false"/>
|
||||||
|
<NavigationProperty Name="From" Type="Microsoft.OData.SampleService.Models.TripPin.Airport" Nullable="false"/>
|
||||||
|
<NavigationProperty Name="To" Type="Microsoft.OData.SampleService.Models.TripPin.Airport" Nullable="false"/>
|
||||||
|
<NavigationProperty Name="Airline" Type="Microsoft.OData.SampleService.Models.TripPin.Airline" Nullable="false"/>
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Event" BaseType="Microsoft.OData.SampleService.Models.TripPin.PlanItem" OpenType="true">
|
||||||
|
<Property Name="Description" Type="Edm.String"/>
|
||||||
|
<Property Name="OccursAt" Type="Microsoft.OData.SampleService.Models.TripPin.EventLocation" Nullable="false"/>
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Trip">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="TripId"/>
|
||||||
|
</Key>
|
||||||
|
<Property Name="TripId" Type="Edm.Int32" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="ShareId" Type="Edm.Guid"/>
|
||||||
|
<Property Name="Description" Type="Edm.String"/>
|
||||||
|
<Property Name="Name" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Property Name="Budget" Type="Edm.Single" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Measures.V1.ISOCurrency" String="USD"/>
|
||||||
|
<Annotation Term="Org.OData.Measures.V1.Scale" Int="2"/>
|
||||||
|
</Property>
|
||||||
|
<Property Name="StartsAt" Type="Edm.DateTimeOffset" Nullable="false"/>
|
||||||
|
<Property Name="EndsAt" Type="Edm.DateTimeOffset" Nullable="false"/>
|
||||||
|
<Property Name="Tags" Type="Collection(Edm.String)" Nullable="false"/>
|
||||||
|
<NavigationProperty Name="Photos" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Photo)"/>
|
||||||
|
<NavigationProperty Name="PlanItems" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.PlanItem)" ContainsTarget="true"/>
|
||||||
|
</EntityType>
|
||||||
|
<Function Name="GetFavoriteAirline" IsBound="true" EntitySetPath="person/Trips/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Flight/Airline" IsComposable="true">
|
||||||
|
<Parameter Name="person" Type="Microsoft.OData.SampleService.Models.TripPin.Person" Nullable="false"/>
|
||||||
|
<ReturnType Type="Microsoft.OData.SampleService.Models.TripPin.Airline" Nullable="false"/>
|
||||||
|
</Function>
|
||||||
|
<Function Name="GetInvolvedPeople" IsBound="true" IsComposable="true">
|
||||||
|
<Parameter Name="trip" Type="Microsoft.OData.SampleService.Models.TripPin.Trip" Nullable="false"/>
|
||||||
|
<ReturnType Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Person)" Nullable="false"/>
|
||||||
|
</Function>
|
||||||
|
<Function Name="GetFriendsTrips" IsBound="true" EntitySetPath="person/Friends/Trips" IsComposable="true">
|
||||||
|
<Parameter Name="person" Type="Microsoft.OData.SampleService.Models.TripPin.Person" Nullable="false"/>
|
||||||
|
<Parameter Name="userName" Type="Edm.String" Nullable="false"/>
|
||||||
|
<ReturnType Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Trip)" Nullable="false"/>
|
||||||
|
</Function>
|
||||||
|
<Function Name="GetNearestAirport" IsComposable="true">
|
||||||
|
<Parameter Name="lat" Type="Edm.Double" Nullable="false"/>
|
||||||
|
<Parameter Name="lon" Type="Edm.Double" Nullable="false"/>
|
||||||
|
<ReturnType Type="Microsoft.OData.SampleService.Models.TripPin.Airport" Nullable="false"/>
|
||||||
|
</Function>
|
||||||
|
<Action Name="ResetDataSource"/>
|
||||||
|
<Action Name="ShareTrip" IsBound="true">
|
||||||
|
<Parameter Name="person" Type="Microsoft.OData.SampleService.Models.TripPin.Person" Nullable="false"/>
|
||||||
|
<Parameter Name="userName" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Parameter Name="tripId" Type="Edm.Int32" Nullable="false"/>
|
||||||
|
</Action>
|
||||||
|
<EntityContainer Name="DefaultContainer">
|
||||||
|
<EntitySet Name="Photos" EntityType="Microsoft.OData.SampleService.Models.TripPin.Photo">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Photos"/>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Searchable" Bool="true"/>
|
||||||
|
<PropertyValue Property="UnsupportedExpressions">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Insertable" Bool="true"/>
|
||||||
|
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||||
|
<Collection/>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
</EntitySet>
|
||||||
|
<EntitySet Name="People" EntityType="Microsoft.OData.SampleService.Models.TripPin.Person">
|
||||||
|
<NavigationPropertyBinding Path="Friends" Target="People"/>
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/Airline" Target="Airlines"/>
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/From" Target="Airports"/>
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/To" Target="Airports"/>
|
||||||
|
<NavigationPropertyBinding Path="Photo" Target="Photos"/>
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Trip/Photos" Target="Photos"/>
|
||||||
|
<Annotation Term="Org.OData.Core.V1.OptimisticConcurrency">
|
||||||
|
<Collection>
|
||||||
|
<PropertyPath>Concurrency</PropertyPath>
|
||||||
|
</Collection>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="People"/>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.NavigationRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Navigability">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.NavigationType/None</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
<PropertyValue Property="RestrictedProperties">
|
||||||
|
<Collection>
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="NavigationProperty" NavigationPropertyPath="Friends"/>
|
||||||
|
<PropertyValue Property="Navigability">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.NavigationType/Recursive</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Collection>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Searchable" Bool="true"/>
|
||||||
|
<PropertyValue Property="UnsupportedExpressions">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Insertable" Bool="true"/>
|
||||||
|
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||||
|
<Collection>
|
||||||
|
<NavigationPropertyPath>Trips</NavigationPropertyPath>
|
||||||
|
<NavigationPropertyPath>Friends</NavigationPropertyPath>
|
||||||
|
</Collection>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
</EntitySet>
|
||||||
|
<EntitySet Name="Airlines" EntityType="Microsoft.OData.SampleService.Models.TripPin.Airline">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Airlines"/>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Searchable" Bool="true"/>
|
||||||
|
<PropertyValue Property="UnsupportedExpressions">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Insertable" Bool="true"/>
|
||||||
|
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||||
|
<Collection/>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
</EntitySet>
|
||||||
|
<EntitySet Name="Airports" EntityType="Microsoft.OData.SampleService.Models.TripPin.Airport">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Airports"/>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Searchable" Bool="true"/>
|
||||||
|
<PropertyValue Property="UnsupportedExpressions">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Insertable" Bool="false"/>
|
||||||
|
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||||
|
<Collection/>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.DeleteRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Deletable" Bool="false"/>
|
||||||
|
<PropertyValue Property="NonDeletableNavigationProperties">
|
||||||
|
<Collection/>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
</EntitySet>
|
||||||
|
<Singleton Name="Me" Type="Microsoft.OData.SampleService.Models.TripPin.Person">
|
||||||
|
<NavigationPropertyBinding Path="Friends" Target="People"/>
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/Airline" Target="Airlines"/>
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/From" Target="Airports"/>
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/To" Target="Airports"/>
|
||||||
|
<NavigationPropertyBinding Path="Photo" Target="Photos"/>
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Trip/Photos" Target="Photos"/>
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Me"/>
|
||||||
|
</Singleton>
|
||||||
|
<FunctionImport Name="GetNearestAirport" Function="Microsoft.OData.SampleService.Models.TripPin.GetNearestAirport" EntitySet="Airports" IncludeInServiceDocument="true">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Microsoft.OData.SampleService.Models.TripPin.GetNearestAirport"/>
|
||||||
|
</FunctionImport>
|
||||||
|
<ActionImport Name="ResetDataSource" Action="Microsoft.OData.SampleService.Models.TripPin.ResetDataSource"/>
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Description" String="TripPin service is a sample service for OData V4."/>
|
||||||
|
</EntityContainer>
|
||||||
|
<Annotations Target="Microsoft.OData.SampleService.Models.TripPin.DefaultContainer">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.DereferenceableIDs" Bool="true"/>
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ConventionalIDs" Bool="true"/>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.ConformanceLevel">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.ConformanceLevelType/Advanced</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.SupportedFormats">
|
||||||
|
<Collection>
|
||||||
|
<String>application/json;odata.metadata=full;IEEE754Compatible=false;odata.streaming=true</String>
|
||||||
|
<String>application/json;odata.metadata=minimal;IEEE754Compatible=false;odata.streaming=true</String>
|
||||||
|
<String>application/json;odata.metadata=none;IEEE754Compatible=false;odata.streaming=true</String>
|
||||||
|
</Collection>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.AsynchronousRequestsSupported" Bool="true"/>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.BatchContinueOnErrorSupported" Bool="false"/>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.FilterFunctions">
|
||||||
|
<Collection>
|
||||||
|
<String>contains</String>
|
||||||
|
<String>endswith</String>
|
||||||
|
<String>startswith</String>
|
||||||
|
<String>length</String>
|
||||||
|
<String>indexof</String>
|
||||||
|
<String>substring</String>
|
||||||
|
<String>tolower</String>
|
||||||
|
<String>toupper</String>
|
||||||
|
<String>trim</String>
|
||||||
|
<String>concat</String>
|
||||||
|
<String>year</String>
|
||||||
|
<String>month</String>
|
||||||
|
<String>day</String>
|
||||||
|
<String>hour</String>
|
||||||
|
<String>minute</String>
|
||||||
|
<String>second</String>
|
||||||
|
<String>round</String>
|
||||||
|
<String>floor</String>
|
||||||
|
<String>ceiling</String>
|
||||||
|
<String>cast</String>
|
||||||
|
<String>isof</String>
|
||||||
|
</Collection>
|
||||||
|
</Annotation>
|
||||||
|
</Annotations>
|
||||||
|
</Schema>
|
||||||
|
</edmx:DataServices>
|
||||||
|
</edmx:Edmx>
|
56
packages/odata/fpmake.pp
Normal file
56
packages/odata/fpmake.pp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
{$ifndef ALLPACKAGES}
|
||||||
|
program fpmake;
|
||||||
|
|
||||||
|
{$mode objfpc}{$h+}
|
||||||
|
|
||||||
|
uses fpmkunit;
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
Procedure Add_OData(ADirectory : string);
|
||||||
|
|
||||||
|
function StdDep(T : TTarget) : TTarget;
|
||||||
|
begin
|
||||||
|
T.Dependencies.AddUnit('odatabase');
|
||||||
|
T.Dependencies.AddUnit('odataservice');
|
||||||
|
Result:=T;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Var
|
||||||
|
P : TPackage;
|
||||||
|
T : TTarget;
|
||||||
|
|
||||||
|
begin
|
||||||
|
With Installer do
|
||||||
|
begin
|
||||||
|
P:=AddPackage('odata');
|
||||||
|
P.ShortName:='odata';
|
||||||
|
P.Author := 'Michael Van Canneyt';
|
||||||
|
P.License := 'LGPL with modification, ';
|
||||||
|
P.HomepageURL := 'www.freepascal.org';
|
||||||
|
P.Email := '';
|
||||||
|
P.Description := 'OData client base libraries, Microsoft Office365 clients';
|
||||||
|
P.NeedLibC:= false;
|
||||||
|
P.OSes := [beos,haiku,freebsd,darwin,iphonesim,solaris,netbsd,openbsd,linux,win32,win64,wince,aix,amiga,aros,morphos,dragonfly];
|
||||||
|
P.Directory:=ADirectory;
|
||||||
|
P.Version:='3.1.1';
|
||||||
|
P.Dependencies.Add('fcl-base');
|
||||||
|
P.Dependencies.Add('rtl-extra');
|
||||||
|
P.Dependencies.Add('rtl-objpas');
|
||||||
|
P.Dependencies.Add('fcl-json');
|
||||||
|
P.Dependencies.Add('fcl-web');
|
||||||
|
P.SourcePath.Add('src');
|
||||||
|
T:=P.Targets.AddUnit('odatabase.pp');
|
||||||
|
T:=P.Targets.AddUnit('odataservice.pp');
|
||||||
|
T.Dependencies.AddUnit('odatabase');
|
||||||
|
T:=StdDep(P.Targets.AddUnit('msgraph.pp'));
|
||||||
|
T:=StdDep(P.Targets.AddUnit('sharepoint.pp'));
|
||||||
|
T:=P.Targets.AddUnit('office365client.pp');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$ifndef ALLPACKAGES}
|
||||||
|
begin
|
||||||
|
Add_OData('');
|
||||||
|
Installer.Run;
|
||||||
|
end.
|
||||||
|
{$endif ALLPACKAGES}
|
7
packages/odata/regen.sh
Normal file
7
packages/odata/regen.sh
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Command to regenerate the interface files.
|
||||||
|
# For this to work, the utils/convertedmx.lpi project must haven been compiled.
|
||||||
|
# That project needs WST (Webservice Toolkit)
|
||||||
|
utils/convertedmx -a 'microsoft.graph=' -d v4 -i xml/msgraph.xml -o src/msgraph.pp -x ''
|
||||||
|
utils/convertedmx -d v2 -i xml/sharepoint.xml -o src/sharepoint.pp -x ''
|
11515
packages/odata/src/msgraph.pp
Normal file
11515
packages/odata/src/msgraph.pp
Normal file
File diff suppressed because it is too large
Load Diff
458
packages/odata/src/odatabase.pp
Normal file
458
packages/odata/src/odatabase.pp
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
unit odatabase;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
TypInfo,Classes, SysUtils, fpjson, restbase;
|
||||||
|
|
||||||
|
Type
|
||||||
|
TInt16 = Type Smallint;
|
||||||
|
TInt32 = Type Integer;
|
||||||
|
SByte = Type Shortint;
|
||||||
|
TTimeOfDay = Type TDateTime;
|
||||||
|
TDateTimeOffset = Type TDateTime;
|
||||||
|
TGUIDString = Type string;
|
||||||
|
TBinary = Array of Byte;
|
||||||
|
|
||||||
|
TDuration = type string;
|
||||||
|
|
||||||
|
{ TGeography }
|
||||||
|
|
||||||
|
TGeography = Class(TBaseObject)
|
||||||
|
private
|
||||||
|
FType: String;
|
||||||
|
Public
|
||||||
|
Class function AllowAdditionalProperties: Boolean; override;
|
||||||
|
Published
|
||||||
|
Property _type : String Read FType Write FType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TGeographyPoint }
|
||||||
|
|
||||||
|
TGeographyPoint = Class(TGeography)
|
||||||
|
private
|
||||||
|
FCoordinates: TDoubleArray;
|
||||||
|
Procedure SetCoordinates(AIndex : integer; AValue : TDoubleArray);
|
||||||
|
Published
|
||||||
|
Property coordinates : TDoubleArray Index 8 Read FCoordinates Write SetCoordinates;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TDoubleArrayArray = Array of TDoubleArray;
|
||||||
|
|
||||||
|
{ TGeographyLineString }
|
||||||
|
|
||||||
|
TGeographyLineString = Class(TGeography)
|
||||||
|
private
|
||||||
|
FCoordinates: TDoubleArrayArray;
|
||||||
|
Published
|
||||||
|
Property coordinates : TDoubleArrayArray Read FCoordinates Write FCoordinates;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TGeographyPolygon = Class(TGeography)
|
||||||
|
end;
|
||||||
|
TGeographyMultiPoint = Class(TGeography)
|
||||||
|
end;
|
||||||
|
TGeographyMultiLineString = Class(TGeography)
|
||||||
|
end;
|
||||||
|
|
||||||
|
TSByteArray = Array of SByte;
|
||||||
|
TByteArray = Array of Byte;
|
||||||
|
TInt32Array = Array of TInt32;
|
||||||
|
TInt16Array = Array of TInt16;
|
||||||
|
|
||||||
|
TDurationArray = Array of TDuration;
|
||||||
|
TDateArray = Array of TDate;
|
||||||
|
TTimeArray = Array of TTime;
|
||||||
|
TTimeOfDayArray = Array of TTimeOfDay;
|
||||||
|
TDateTimeOffsetArray = Array of TDateTimeOffset;
|
||||||
|
TGUIDStringArray = Array of TGUIDString;
|
||||||
|
TBinaryArray = Array of TBinary;
|
||||||
|
TGeographyArray = Array of TGeography;
|
||||||
|
TGeographyPointArray = Array of TGeographyPoint;
|
||||||
|
TGeographyLineStringArray = Array of TGeographyLineString;
|
||||||
|
TGeographyPolygonArray = Array of TGeographyPolygon;
|
||||||
|
TGeographyMultiPointArray = Array of TGeographyMultiPoint;
|
||||||
|
TGeographyMultiLineStringArray = Array of TGeographyMultiLineString;
|
||||||
|
|
||||||
|
TAnnotation = TJSONEnum;
|
||||||
|
|
||||||
|
{ TODataObject }
|
||||||
|
|
||||||
|
TODataObject = Class(TBaseObject)
|
||||||
|
Private
|
||||||
|
FAns : TJSONObject;
|
||||||
|
function GetAnnotation(Index : Integer): TAnnotation;
|
||||||
|
function GetAnnotationValue(AName : String): TJSONData;
|
||||||
|
function GetDataAnnotationCount: Integer;
|
||||||
|
Protected
|
||||||
|
Procedure AddAnnotation(Const AName : String; AValue : TJSONData);
|
||||||
|
Class Function DynArrayToJSONArray(A : Pointer; AType : string; AClassType : TBaseObjectClass = Nil) : TJSONArray;
|
||||||
|
Class Function JSONArrayToDynArray(A : TJSONArray; AType : string; AClassType : TBaseObjectClass = Nil) : Pointer;
|
||||||
|
Public
|
||||||
|
Destructor Destroy; override;
|
||||||
|
Procedure LoadPropertyFromJSON(Const AName : String; JSON : TJSONData); override;
|
||||||
|
Class Function MakeKeyString(Const AKey : String) : String;
|
||||||
|
Class Function AllowAdditionalProperties : Boolean; override;
|
||||||
|
Property ODataAnnotations[Index : Integer] : TAnnotation Read GetAnnotation;
|
||||||
|
Property ODataAnnotationValues[AName : String] : TJSONData Read GetAnnotationValue;
|
||||||
|
Property ODataAnnotationCount : Integer Read GetDataAnnotationCount;
|
||||||
|
end;
|
||||||
|
TODataObjectClass = Class of TODataObject;
|
||||||
|
TODataObjectArray = Array of TODataObject;
|
||||||
|
|
||||||
|
TODataComplexType = Class(TODataObject);
|
||||||
|
TODataComplexTypeClass = Class of TODataComplexType;
|
||||||
|
|
||||||
|
{ TODataError }
|
||||||
|
TODataErrorDetail = Record
|
||||||
|
Code : String;
|
||||||
|
Message : String;
|
||||||
|
Target : String;
|
||||||
|
end;
|
||||||
|
TODataErrorDetails = Array of TODataErrorDetail;
|
||||||
|
|
||||||
|
TODataError = Class(TObject)
|
||||||
|
private
|
||||||
|
FCode: String;
|
||||||
|
FDetails: TODataErrorDetails;
|
||||||
|
FInnerError: String;
|
||||||
|
FMessage: String;
|
||||||
|
FTargetCode: String;
|
||||||
|
Public
|
||||||
|
Property Code : String Read FCode Write FCode;
|
||||||
|
Property Message : String Read FMessage Write FMessage;
|
||||||
|
Property Target : String Read FTargetCode Write FTargetCode;
|
||||||
|
Property Details : TODataErrorDetails Read FDetails Write FDetails;
|
||||||
|
// JSON
|
||||||
|
Property InnerError : String Read FInnerError Write FInnerError;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ EOData }
|
||||||
|
|
||||||
|
EOData =Class(Exception)
|
||||||
|
private
|
||||||
|
FError: TODataError;
|
||||||
|
FStatusCode: Integer;
|
||||||
|
FStatusText: String;
|
||||||
|
Public
|
||||||
|
Destructor Destroy; override;
|
||||||
|
Property StatusCode : Integer Read FStatusCode Write FStatusCode;
|
||||||
|
Property StatusText : String Read FStatusText Write FStatusText;
|
||||||
|
Property Error : TODataError Read FError Write FError;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Function BinaryToString(B : TBinary) : String;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
Function BinaryToString(B : TBinary) : String;
|
||||||
|
|
||||||
|
Var
|
||||||
|
E : Byte;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:='';
|
||||||
|
For E in B do
|
||||||
|
Result:=Result+HexStr(E,2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TGeographyPoint }
|
||||||
|
|
||||||
|
Procedure TGeographyPoint.SetCoordinates(AIndex: integer; AValue: TDoubleArray);
|
||||||
|
|
||||||
|
Var
|
||||||
|
D : Double;
|
||||||
|
|
||||||
|
begin
|
||||||
|
{ Writeln('Setting coordinates');
|
||||||
|
For d in AValue do
|
||||||
|
writeln('Got ',D);}
|
||||||
|
FCoordinates:=AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TGeography }
|
||||||
|
|
||||||
|
Class function TGeography.AllowAdditionalProperties: Boolean;
|
||||||
|
begin
|
||||||
|
Result:=True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ EOData }
|
||||||
|
|
||||||
|
Destructor EOData.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FError);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TODataObject }
|
||||||
|
|
||||||
|
function TODataObject.GetAnnotation(Index : Integer): TAnnotation;
|
||||||
|
begin
|
||||||
|
If Not Assigned(FAns) or (Index<0) or (Index>=FAns.Count) then
|
||||||
|
begin
|
||||||
|
Result.Key:='';
|
||||||
|
Result.KeyNum:=-1;
|
||||||
|
Result.Value:=Nil;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result.Key:=FAns.Names[Index];
|
||||||
|
Result.KeyNum:=Index;
|
||||||
|
Result.Value:=FAns.Items[Index];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataObject.GetAnnotationValue(AName : String): TJSONData;
|
||||||
|
|
||||||
|
Var
|
||||||
|
I : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:=Nil;
|
||||||
|
if Assigned(FAns) then
|
||||||
|
begin
|
||||||
|
I:=FAns.IndexOfName(AName);
|
||||||
|
if I<>-1 then
|
||||||
|
Result:=FAns.Items[i];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataObject.GetDataAnnotationCount: Integer;
|
||||||
|
begin
|
||||||
|
if Assigned(FAns) then
|
||||||
|
Result:=FAns.Count
|
||||||
|
else
|
||||||
|
Result:=0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataObject.AddAnnotation(Const AName: String; AValue: TJSONData);
|
||||||
|
begin
|
||||||
|
If Not Assigned(FAns) then
|
||||||
|
FAns:=TJSONObject.Create();
|
||||||
|
FAns.Add(AName,AValue.Clone);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Type
|
||||||
|
TShortIntArray = Array of ShortInt;
|
||||||
|
TSmallIntArray = Array of SmallInt;
|
||||||
|
TWordArray = Array of Word;
|
||||||
|
TCardinalArray = Array of Cardinal;
|
||||||
|
TQWordArray= Array of QWord;
|
||||||
|
TSingleArray = Array of Single;
|
||||||
|
|
||||||
|
Class Function TODataObject.DynArrayToJSONArray(A: Pointer; AType: string; AClassType : TBaseObjectClass = Nil): TJSONArray;
|
||||||
|
|
||||||
|
|
||||||
|
Var
|
||||||
|
I,L : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:=TJSONArray.Create;
|
||||||
|
L:=Length(TByteArray(A));
|
||||||
|
Case LowerCase(aType) of
|
||||||
|
'boolean':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TBooleanArray(A)[i]);
|
||||||
|
'byte',
|
||||||
|
'tsbyte':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TByteArray(A)[i]);
|
||||||
|
'shortint':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TShortIntArray(A)[i]);
|
||||||
|
'int16',
|
||||||
|
'tint16',
|
||||||
|
'smallint':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TSmallIntArray(A)[i]);
|
||||||
|
'word':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TWordArray(A)[i]);
|
||||||
|
'tint32',
|
||||||
|
'int32',
|
||||||
|
'integer':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TIntegerArray(A)[i]);
|
||||||
|
'cardinal',
|
||||||
|
'dword':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TCardinalArray(A)[i]);
|
||||||
|
'tint64',
|
||||||
|
'int64':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TInt64Array(A)[i]);
|
||||||
|
'qword':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
{$IFNDEF VER2_6}
|
||||||
|
Result.Add(TQWordArray(A)[i]);
|
||||||
|
{$else}
|
||||||
|
Result.Add(TInt64Array(A)[i]);
|
||||||
|
{$ENDIF}
|
||||||
|
'string':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TStringArray(A)[i]);
|
||||||
|
'tguidstring':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TStringArray(A)[i]);
|
||||||
|
'double':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TDoubleArray(A)[i]);
|
||||||
|
'single':
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
Result.Add(TSingleArray(A)[i]);
|
||||||
|
else
|
||||||
|
if Pos('array',lowerCase(atype))<>0 then
|
||||||
|
Raise EOData.Create('Cannot convert array of array: '+atype);
|
||||||
|
if (AClassType=Nil) then
|
||||||
|
Raise EOData.Create('Cannot convert array of object without class type');
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
if (TObjectArray(A)[i].InheritsFrom(AClassType)) then
|
||||||
|
Result.Add(TObjectArray(A)[i].SaveToJSON);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Class Function TODataObject.JSONArrayToDynArray(A: TJSONArray; AType: string; AClassType : TBaseObjectClass = Nil ): Pointer;
|
||||||
|
Var
|
||||||
|
I,L : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:=TJSONArray.Create;
|
||||||
|
L:=A.Count;
|
||||||
|
Case LowerCase(aType) of
|
||||||
|
'boolean':
|
||||||
|
begin
|
||||||
|
SetLength(TBooleanArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TBooleanArray(Result)[i]:=A.Booleans[i];
|
||||||
|
end;
|
||||||
|
'byte',
|
||||||
|
'tsbyte':
|
||||||
|
begin
|
||||||
|
SetLength(TByteArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TByteArray(Result)[i]:=A.Integers[i];
|
||||||
|
end;
|
||||||
|
'shortint':
|
||||||
|
begin
|
||||||
|
SetLength(TShortIntArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TShortIntArray(Result)[i]:=A.Integers[i];
|
||||||
|
end;
|
||||||
|
'int16',
|
||||||
|
'tint16',
|
||||||
|
'smallint':
|
||||||
|
begin
|
||||||
|
SetLength(TSmallIntArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TSmallIntArray(Result)[i]:=A.Integers[i];
|
||||||
|
end;
|
||||||
|
'word':
|
||||||
|
begin
|
||||||
|
SetLength(TWordArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TWordArray(Result)[i]:=A.Integers[i];
|
||||||
|
end;
|
||||||
|
'tint32',
|
||||||
|
'int32',
|
||||||
|
'integer':
|
||||||
|
begin
|
||||||
|
SetLength(TIntegerArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TIntegerArray(Result)[i]:=A.Integers[i];
|
||||||
|
end;
|
||||||
|
'cardinal',
|
||||||
|
'dword':
|
||||||
|
begin
|
||||||
|
SetLength(TCardinalArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TCardinalArray(Result)[i]:=A.Integers[i];
|
||||||
|
end;
|
||||||
|
'tint64',
|
||||||
|
'int64':
|
||||||
|
begin
|
||||||
|
SetLength(TInt64Array(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TInt64Array(Result)[i]:=A.Int64s[i];
|
||||||
|
end;
|
||||||
|
'qword':
|
||||||
|
begin
|
||||||
|
SetLength(TQWordArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
{$IFDEF VER2_6}
|
||||||
|
TInt64Array(Result)[i]:=A.Int64s[i];
|
||||||
|
{$ELSE}
|
||||||
|
TQWordArray(Result)[i]:=A.QWords[i];
|
||||||
|
{$ENDIF}
|
||||||
|
end;
|
||||||
|
'tstring',
|
||||||
|
'string':
|
||||||
|
begin
|
||||||
|
SetLength(TStringArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TStringArray(Result)[i]:=A.Strings[i];
|
||||||
|
end;
|
||||||
|
'guidstring',
|
||||||
|
'tguidstring':
|
||||||
|
begin
|
||||||
|
SetLength(TStringArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TStringArray(Result)[i]:=A.Strings[i];
|
||||||
|
end;
|
||||||
|
'double':
|
||||||
|
begin
|
||||||
|
SetLength(TDoubleArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TDoubleArray(Result)[i]:=A.Floats[i];
|
||||||
|
end;
|
||||||
|
'single':
|
||||||
|
begin
|
||||||
|
SetLength(TSingleArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
TSingleArray(Result)[i]:=A.Floats[i];
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
if (Pos('array',lowercase(atype))<>0) then
|
||||||
|
Raise EOData.Create('Cannot convert array of array: '+atype);
|
||||||
|
if (AClassType=Nil) then
|
||||||
|
Raise EOData.Create('Cannot convert array of object without class type');
|
||||||
|
SetLength(TObjectArray(Result),L);
|
||||||
|
For I:=0 to L-1 do
|
||||||
|
begin
|
||||||
|
if A.Types[i]<>jtObject then
|
||||||
|
Raise EOData.CreateFmt('Element %d of array is not an object: %s',[I,A.Items[i].AsJSON]);
|
||||||
|
TObjectArray(Result)[i]:=AClassType.Create;
|
||||||
|
TObjectArray(Result)[i].LoadFromJSON(A.Objects[i]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Destructor TODataObject.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FAns);
|
||||||
|
Inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TODataObject.LoadPropertyFromJSON(Const AName: String; JSON: TJSONData
|
||||||
|
);
|
||||||
|
begin
|
||||||
|
if (AName<>'') and (AName[1]='@') then
|
||||||
|
AddAnnotation(AName,JSON)
|
||||||
|
else
|
||||||
|
inherited LoadPropertyFromJSON(AName, JSON);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Class Function TODataObject.MakeKeyString(Const AKey: String): String;
|
||||||
|
begin
|
||||||
|
Result:=''''+AKey+'''';
|
||||||
|
end;
|
||||||
|
|
||||||
|
Class Function TODataObject.AllowAdditionalProperties: Boolean;
|
||||||
|
begin
|
||||||
|
Result:=True; // So we catch annnotations
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
1392
packages/odata/src/odataservice.pp
Normal file
1392
packages/odata/src/odataservice.pp
Normal file
File diff suppressed because it is too large
Load Diff
288
packages/odata/src/office365client.pp
Normal file
288
packages/odata/src/office365client.pp
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
unit office365client;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, fpwebclient, fpoauth2, fpjwt;
|
||||||
|
|
||||||
|
Type
|
||||||
|
TAuthMethod = (amOAuth2);
|
||||||
|
|
||||||
|
{ TAzureADClaims }
|
||||||
|
// Claims returned by Azure AD.
|
||||||
|
|
||||||
|
TAzureADClaims = Class(TClaims)
|
||||||
|
private
|
||||||
|
FFamilyName: String;
|
||||||
|
FGivenName: String;
|
||||||
|
FOID: String;
|
||||||
|
Fpwd_exp: string;
|
||||||
|
Fpwd_url: string;
|
||||||
|
FTid: String;
|
||||||
|
FUniqueName: string;
|
||||||
|
Fupn: String;
|
||||||
|
Fver: String;
|
||||||
|
Published
|
||||||
|
Property unique_name : string read FUniqueName Write FUniqueName;
|
||||||
|
Property family_name : String read FFamilyName Write FFamilyName;
|
||||||
|
Property given_name : String read FGivenName Write FGivenName;
|
||||||
|
Property pwd_exp : string Read Fpwd_exp Write Fpwd_exp;
|
||||||
|
Property pwd_url : string Read Fpwd_url Write Fpwd_url;
|
||||||
|
Property tid : String Read FTid Write FTID; // GUID
|
||||||
|
Property upn : String Read Fupn Write Fupn;
|
||||||
|
Property ver : String Read Fver Write Fver;
|
||||||
|
Property oid : String Read FOID Write FOID; // GUID
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TAzureIDToken }
|
||||||
|
|
||||||
|
TAzureIDToken = Class(TJWTIDtoken)
|
||||||
|
private
|
||||||
|
function GetAzureClaims: TAzureADClaims;
|
||||||
|
Protected
|
||||||
|
Function CreateClaims : TClaims; override;
|
||||||
|
Public
|
||||||
|
Constructor Create;
|
||||||
|
Function GetUniqueUserID : String; override;
|
||||||
|
Function GetUniqueUserName : String; override;
|
||||||
|
Function GetUserDisplayName : String; override;
|
||||||
|
Property AzureClaims : TAzureADClaims Read GetAzureClaims;
|
||||||
|
end;
|
||||||
|
{ TAzureADOAuth2Handler }
|
||||||
|
|
||||||
|
TAzureADOAuth2Handler = Class(TOAuth2Handler)
|
||||||
|
Protected
|
||||||
|
function CreateIDToken: TJWTIDToken;override;
|
||||||
|
Public
|
||||||
|
Constructor Create(AOwner : TComponent); override;
|
||||||
|
Class Function AuthScopeVariableName : String; override;
|
||||||
|
Class Function DefaultHostedDomain : String; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Authentication V2...
|
||||||
|
|
||||||
|
{ TAzureAD2OAuth2Handler }
|
||||||
|
|
||||||
|
TAzureAD2OAuth2Handler = Class(TAzureADOAuth2Handler)
|
||||||
|
Public
|
||||||
|
Constructor Create(AOwner : TComponent); override;
|
||||||
|
Class Function AuthScopeVariableName : String; override;
|
||||||
|
Class Function DefaultHostedDomain : String; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TOffice365Client = CLass(TComponent)
|
||||||
|
Private
|
||||||
|
FWebClient: TAbstractWebClient;
|
||||||
|
FAuthHandler : TOAuth2Handler;
|
||||||
|
function GetOnUserConsent: TUserConsentHandler;
|
||||||
|
procedure SetAuthHandler(AValue: TOAuth2Handler);
|
||||||
|
procedure SetClient(AValue: TAbstractWebClient);
|
||||||
|
procedure SetOnUserConsent(AValue: TUserConsentHandler);
|
||||||
|
Protected
|
||||||
|
Procedure CheckDefaults; virtual;
|
||||||
|
Public
|
||||||
|
Constructor Create(AOwner : TComponent); override;
|
||||||
|
Function GetAuthHandler : TOAuth2Handler;
|
||||||
|
Published
|
||||||
|
Property AuthHandler : TOAuth2Handler Read GetAuthHandler Write SetAuthHandler;
|
||||||
|
Property WebClient : TAbstractWebClient Read FWebClient Write SetClient;
|
||||||
|
Property OnUserConsent : TUserConsentHandler Read GetOnUserConsent Write SetOnUserConsent;
|
||||||
|
end;
|
||||||
|
|
||||||
|
EOffice365 = Class(Exception);
|
||||||
|
|
||||||
|
Const
|
||||||
|
DefAUTHURL = 'https://login.windows.net/%HostedDomain%/oauth2/authorize';
|
||||||
|
DefTOKENURL = 'https://login.windows.net/%HostedDomain%/oauth2/token';
|
||||||
|
|
||||||
|
DefAUTHURLV2 = 'https://login.microsoftonline.com/%HostedDomain%/oauth2/v2.0/authorize';
|
||||||
|
DefTOKENURLV2 = 'https://login.microsoftonline.com/%HostedDomain%/oauth2/v2.0/token';
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Function StringToAuthMethod (Const S : String) : TAuthMethod;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Case Lowercase(S) of
|
||||||
|
'oauth2' : Result:=amOAuth2;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Function StringToAccessType(const S : String) : TAccessType;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Case lowercase(S) of
|
||||||
|
'online' : Result:=atonline;
|
||||||
|
'offline' : Result:=atoffline;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TAzureAD2OAuth2Handler }
|
||||||
|
|
||||||
|
constructor TAzureAD2OAuth2Handler.Create(AOwner: TComponent);
|
||||||
|
|
||||||
|
begin
|
||||||
|
inherited Create(AOwner);
|
||||||
|
Config.TokenURL:=DefTOKENURLV2;
|
||||||
|
Config.AuthURL:=DefAuthURLV2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TAzureAD2OAuth2Handler.AuthScopeVariableName: String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:='scope';
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TAzureAD2OAuth2Handler.DefaultHostedDomain: String;
|
||||||
|
begin
|
||||||
|
Result:='common';
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TAzureIDToken }
|
||||||
|
|
||||||
|
function TAzureIDToken.GetAzureClaims: TAzureADClaims;
|
||||||
|
begin
|
||||||
|
if Claims is TAzureADClaims then
|
||||||
|
Result:=TAzureADClaims(Claims)
|
||||||
|
else
|
||||||
|
Result:=Nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TAzureIDToken.CreateClaims: TClaims;
|
||||||
|
begin
|
||||||
|
If ClaimsClass=Nil then
|
||||||
|
Result:=TAzureADClaims.Create
|
||||||
|
else
|
||||||
|
Result:=inherited CreateClaims;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TAzureIDToken.Create;
|
||||||
|
begin
|
||||||
|
Inherited CreateWithClasses(TAzureADClaims,Nil)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TAzureIDToken.GetUniqueUserID: String;
|
||||||
|
begin
|
||||||
|
if Assigned(AZureClaims) then
|
||||||
|
Result:=AZureClaims.upn
|
||||||
|
else
|
||||||
|
Result:=inherited GetUniqueUserID;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TAzureIDToken.GetUniqueUserName: String;
|
||||||
|
begin
|
||||||
|
if Assigned(AZureClaims) then
|
||||||
|
Result:=AZureClaims.unique_name
|
||||||
|
else
|
||||||
|
Result:=inherited GetUniqueUserName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TAzureIDToken.GetUserDisplayName: String;
|
||||||
|
begin
|
||||||
|
if Assigned(AZureClaims) then
|
||||||
|
Result:=AZureClaims.Given_Name+' '+AZureClaims.Family_Name
|
||||||
|
else
|
||||||
|
Result:=inherited GetUserDisplayName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TAzureOAuth2Handler }
|
||||||
|
|
||||||
|
function TAzureADOAuth2Handler.CreateIDToken: TJWTIDToken;
|
||||||
|
begin
|
||||||
|
Result:=TAzureIDToken.CreateWithClasses(TAzureADClaims,Nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Constructor TAzureADOAuth2Handler.Create(AOwner: TComponent);
|
||||||
|
begin
|
||||||
|
inherited Create(AOwner);
|
||||||
|
Config.TokenURL:=DefTOKENURL;
|
||||||
|
Config.AuthURL:=DefAuthURL;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Class Function TAzureADOAuth2Handler.AuthScopeVariableName: String;
|
||||||
|
begin
|
||||||
|
Result:='resource';
|
||||||
|
end;
|
||||||
|
|
||||||
|
Class Function TAzureADOAuth2Handler.DefaultHostedDomain: String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:='common';
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TOffice365Client }
|
||||||
|
|
||||||
|
procedure TOffice365Client.SetClient(AValue: TAbstractWebClient);
|
||||||
|
|
||||||
|
Var
|
||||||
|
AH : TOAuth2Handler;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if FWebClient=AValue then Exit;
|
||||||
|
if Assigned(FWebClient) then
|
||||||
|
FWebClient.RemoveFreeNotification(Self);
|
||||||
|
FWebClient:=AValue;
|
||||||
|
if Assigned(FWebClient) then
|
||||||
|
begin
|
||||||
|
FWebClient.FreeNotification(Self);
|
||||||
|
AH:=GetAuthHandler;
|
||||||
|
FWebClient.RequestSigner:=AH;
|
||||||
|
AH.WebClient:=FWebClient;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TOffice365Client.GetOnUserConsent: TUserConsentHandler;
|
||||||
|
begin
|
||||||
|
Result:=GetAuthHandler.OnUserConsent;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TOffice365Client.SetAuthHandler(AValue: TOAuth2Handler);
|
||||||
|
begin
|
||||||
|
if FAuthHandler=AValue then Exit;
|
||||||
|
FAuthHandler:=AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TOffice365Client.SetOnUserConsent(AValue: TUserConsentHandler);
|
||||||
|
begin
|
||||||
|
GetAuthHandler.OnUserConsent:=AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Constructor TOffice365Client.Create(AOwner: TComponent);
|
||||||
|
begin
|
||||||
|
inherited Create(AOwner);
|
||||||
|
CheckDefaults;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TOffice365Client.CheckDefaults;
|
||||||
|
|
||||||
|
begin
|
||||||
|
If (AuthHandler.Config.AuthURL='') then
|
||||||
|
AuthHandler.Config.AuthURL:=DefAuthURL;
|
||||||
|
If (AuthHandler.Config.TokenURL='') then
|
||||||
|
AuthHandler.Config.TokenURL:=DefTokenURL;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
Function TOffice365Client.GetAuthHandler: TOAuth2Handler;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
if (FAuthHandler=Nil) then
|
||||||
|
begin
|
||||||
|
FAuthHandler:=TAzureADOAuth2Handler.Create(Self);
|
||||||
|
if Assigned(FWebClient) then
|
||||||
|
begin
|
||||||
|
FWebClient.RequestSigner:=FAuthHandler;
|
||||||
|
FAuthHandler.WebClient:=FWebClient;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result:=FAuthHandler;
|
||||||
|
end;
|
||||||
|
end.
|
||||||
|
|
119212
packages/odata/src/sharepoint.pp
Normal file
119212
packages/odata/src/sharepoint.pp
Normal file
File diff suppressed because it is too large
Load Diff
86
packages/odata/utils/README.txt
Normal file
86
packages/odata/utils/README.txt
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
This program converts a ODATA service description to a pascal unit.
|
||||||
|
This is either CSDL (OData V2) or EDMX (OData V4) document.
|
||||||
|
|
||||||
|
It needs the WST (Web Services Toolkit) to compile, you will need to
|
||||||
|
download this separately from the Lazarus-CCR:
|
||||||
|
https://svn.code.sf.net/p/lazarus-ccr/svn/wst/trunk
|
||||||
|
|
||||||
|
------------------
|
||||||
|
About the sources:
|
||||||
|
------------------
|
||||||
|
The sources use a small trick to treat v4 and v2 OData formats: EDMX and CSDL.
|
||||||
|
|
||||||
|
While describing virtually the same thing, the underlying EDMX and CSDL
|
||||||
|
are nonetheless quite different at times.
|
||||||
|
|
||||||
|
To cater for this, a single unit is made (edmx2pas) which uses a define USECSDL
|
||||||
|
to differentiate between V2 (USECSDL defined) and V4 (USECSDL not defined).
|
||||||
|
The csdl2pas unit just sets the define and includes edmx2pas.
|
||||||
|
|
||||||
|
This trick may confuse your IDE (Lazarus in my case).
|
||||||
|
|
||||||
|
-----
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
Usage is explained by running the program
|
||||||
|
|
||||||
|
a --aliases=aliases Schema aliases as comma-separated name=value pairs.
|
||||||
|
The form @aliases reads from file "aliases", one alias per line.
|
||||||
|
|
||||||
|
an CSDL or EDMX data description uses a schema namespace.
|
||||||
|
This means a set of dotted names, used in all identifiers.
|
||||||
|
For example, the Microsoft Graph api uses microsoft.graph.
|
||||||
|
By default all dots are replaced by underscores, and the type or identifier name is appended to it.
|
||||||
|
You can instead specify microsoft.graph=X in which case the namespace is
|
||||||
|
reduced to X. This results in more readable identifiers (Note: X can be empty)
|
||||||
|
|
||||||
|
-b --basename=classname Name of class to use as base class.
|
||||||
|
|
||||||
|
By default, all classes descend from TODataObject. This can be changed.
|
||||||
|
|
||||||
|
|
||||||
|
-d --odata=version OData version to use: v2 or v4.
|
||||||
|
|
||||||
|
This determines what document is being converted. Note that not yet all
|
||||||
|
possibilities of V2 are supported.
|
||||||
|
|
||||||
|
-e --extraunits=extraunits Comma-separated list of unit names to add.
|
||||||
|
|
||||||
|
List of unit names to add to the uses clause of the generated unit.
|
||||||
|
|
||||||
|
-h --help This message.
|
||||||
|
|
||||||
|
Display help.
|
||||||
|
|
||||||
|
-i --input=filename Name of the file to use as input. Mandatory
|
||||||
|
|
||||||
|
The name of an CSDL or EDMX XML document.
|
||||||
|
|
||||||
|
-o --output=filename Name of the file to use as output.
|
||||||
|
(default: input file with extension changed to .pas)
|
||||||
|
|
||||||
|
This is the output filename name. By default the input filename will be
|
||||||
|
used, with the extension changed to .pas
|
||||||
|
|
||||||
|
-p --prefix=fieldprefix Text to use as field prefix (default: F)
|
||||||
|
|
||||||
|
All field names for properties start with F, followed by the property name.
|
||||||
|
You can change this here.
|
||||||
|
|
||||||
|
-u --enumerations=mode How to treat enumerations. Possible values: scoped, prefixtypename, plain
|
||||||
|
|
||||||
|
How to generate code for enumerations.
|
||||||
|
|
||||||
|
-x --servicesuffix=string When constructing type names, add this to schema name. Default is _
|
||||||
|
|
||||||
|
By default a type name is constructed by apending the schema name with _ and
|
||||||
|
then the type name. You can use this option to change the _ character.
|
||||||
|
|
||||||
|
-v --verbose Output some diagnostic messages
|
||||||
|
|
||||||
|
|
||||||
|
Enjoy,
|
||||||
|
|
||||||
|
Michael.
|
62
packages/odata/utils/cgs.pas
Normal file
62
packages/odata/utils/cgs.pas
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
This unit has been produced by ws_helper.
|
||||||
|
Input unit name : "System_Data_Resources_CodeGenerationSchema".
|
||||||
|
This unit name : "cgs".
|
||||||
|
Date : "12-5-16 15:37:59".
|
||||||
|
}
|
||||||
|
unit cgs;
|
||||||
|
{$IFDEF FPC}
|
||||||
|
{$mode objfpc} {$H+}
|
||||||
|
{$ENDIF}
|
||||||
|
{$DEFINE WST_RECORD_RTTI}
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses SysUtils, Classes, TypInfo, base_service_intf, service_intf;
|
||||||
|
|
||||||
|
const
|
||||||
|
sNAME_SPACE = 'http://schemas.microsoft.com/ado/2006/04/codegeneration';
|
||||||
|
sUNIT_NAME = 'System_Data_Resources_CodeGenerationSchema';
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
|
||||||
|
TAccess = (
|
||||||
|
TAccess_Public
|
||||||
|
,Internal
|
||||||
|
,TAccess_Protected
|
||||||
|
,TAccess_Private
|
||||||
|
);
|
||||||
|
|
||||||
|
TPublicOrInternalAccess = (
|
||||||
|
TPublicOrInternalAccess_Public
|
||||||
|
,TPublicOrInternalAccess_Internal
|
||||||
|
);
|
||||||
|
|
||||||
|
SetterAccess_Type = TAccess;
|
||||||
|
|
||||||
|
GetterAccess_Type = TAccess;
|
||||||
|
|
||||||
|
TypeAccess_Type = TPublicOrInternalAccess;
|
||||||
|
|
||||||
|
MethodAccess_Type = TAccess;
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
uses metadata_repository, record_rtti;
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
typeRegistryInstance : TTypeRegistry = nil;
|
||||||
|
initialization
|
||||||
|
typeRegistryInstance := GetTypeRegistry();
|
||||||
|
|
||||||
|
typeRegistryInstance.Register(sNAME_SPACE,TypeInfo(TAccess),'TAccess');
|
||||||
|
typeRegistryInstance.ItemByTypeInfo[TypeInfo(TAccess)].RegisterExternalPropertyName('TAccess_Public','Public');
|
||||||
|
typeRegistryInstance.ItemByTypeInfo[TypeInfo(TAccess)].RegisterExternalPropertyName('TAccess_Protected','Protected');
|
||||||
|
typeRegistryInstance.ItemByTypeInfo[TypeInfo(TAccess)].RegisterExternalPropertyName('TAccess_Private','Private');
|
||||||
|
typeRegistryInstance.Register(sNAME_SPACE,TypeInfo(TPublicOrInternalAccess),'TPublicOrInternalAccess');
|
||||||
|
typeRegistryInstance.ItemByTypeInfo[TypeInfo(TPublicOrInternalAccess)].RegisterExternalPropertyName('TPublicOrInternalAccess_Public','Public');
|
||||||
|
typeRegistryInstance.ItemByTypeInfo[TypeInfo(TPublicOrInternalAccess)].RegisterExternalPropertyName('TPublicOrInternalAccess_Internal','Internal');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
End.
|
101
packages/odata/utils/convertedmx.lpi
Normal file
101
packages/odata/utils/convertedmx.lpi
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<Version Value="9"/>
|
||||||
|
<General>
|
||||||
|
<Flags>
|
||||||
|
<SaveOnlyProjectUnits Value="True"/>
|
||||||
|
<MainUnitHasCreateFormStatements Value="False"/>
|
||||||
|
<MainUnitHasTitleStatement Value="False"/>
|
||||||
|
<SaveJumpHistory Value="False"/>
|
||||||
|
<SaveFoldState Value="False"/>
|
||||||
|
</Flags>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
|
<MainUnit Value="0"/>
|
||||||
|
<Title Value="convertedmx"/>
|
||||||
|
<UseAppBundle Value="False"/>
|
||||||
|
<ResourceType Value="res"/>
|
||||||
|
</General>
|
||||||
|
<i18n>
|
||||||
|
<EnableI18N LFM="False"/>
|
||||||
|
</i18n>
|
||||||
|
<VersionInfo>
|
||||||
|
<StringTable ProductVersion=""/>
|
||||||
|
</VersionInfo>
|
||||||
|
<BuildModes Count="1">
|
||||||
|
<Item1 Name="Default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<local>
|
||||||
|
<FormatVersion Value="1"/>
|
||||||
|
<CommandLineParams Value="-d v4 -i ../examples/v4/v4sample.xml -a Microsoft.OData.SampleService.Models.TripPin= -x ''"/>
|
||||||
|
</local>
|
||||||
|
</RunParams>
|
||||||
|
<RequiredPackages Count="1">
|
||||||
|
<Item1>
|
||||||
|
<PackageName Value="wst_core"/>
|
||||||
|
</Item1>
|
||||||
|
</RequiredPackages>
|
||||||
|
<Units Count="8">
|
||||||
|
<Unit0>
|
||||||
|
<Filename Value="convertedmx.pp"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit0>
|
||||||
|
<Unit1>
|
||||||
|
<Filename Value="edmx2pas.pp"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit1>
|
||||||
|
<Unit2>
|
||||||
|
<Filename Value="csdl.pp"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="CSDL"/>
|
||||||
|
</Unit2>
|
||||||
|
<Unit3>
|
||||||
|
<Filename Value="csdl2pas.pp"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit3>
|
||||||
|
<Unit4>
|
||||||
|
<Filename Value="odatacodegen.pp"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit4>
|
||||||
|
<Unit5>
|
||||||
|
<Filename Value="cgs.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit5>
|
||||||
|
<Unit6>
|
||||||
|
<Filename Value="edm.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit6>
|
||||||
|
<Unit7>
|
||||||
|
<Filename Value="ras.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit7>
|
||||||
|
</Units>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<Target>
|
||||||
|
<Filename Value="convertedmx"/>
|
||||||
|
</Target>
|
||||||
|
<SearchPaths>
|
||||||
|
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||||
|
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
</SearchPaths>
|
||||||
|
</CompilerOptions>
|
||||||
|
<Debugging>
|
||||||
|
<Exceptions Count="3">
|
||||||
|
<Item1>
|
||||||
|
<Name Value="EAbort"/>
|
||||||
|
</Item1>
|
||||||
|
<Item2>
|
||||||
|
<Name Value="ECodetoolError"/>
|
||||||
|
</Item2>
|
||||||
|
<Item3>
|
||||||
|
<Name Value="EFOpenError"/>
|
||||||
|
</Item3>
|
||||||
|
</Exceptions>
|
||||||
|
</Debugging>
|
||||||
|
</CONFIG>
|
124
packages/odata/utils/convertedmx.pp
Normal file
124
packages/odata/utils/convertedmx.pp
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
program convertedmx;
|
||||||
|
|
||||||
|
uses
|
||||||
|
classes, sysutils, csdl2pas, custapp, restcodegen,
|
||||||
|
edmx2pas, odatacodegen, cgs;
|
||||||
|
|
||||||
|
Type
|
||||||
|
|
||||||
|
{ TConvertEDMXApplication }
|
||||||
|
|
||||||
|
TConvertEDMXApplication = Class(TCustomApplication)
|
||||||
|
private
|
||||||
|
procedure Usage(Msg: String);
|
||||||
|
Protected
|
||||||
|
Procedure DoRun; override;
|
||||||
|
public
|
||||||
|
Procedure DoMyLog(Sender: TObject; LogType: TCodegenLogType; Const Msg: String);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TConvertEDMXApplication }
|
||||||
|
|
||||||
|
procedure TConvertEDMXApplication.Usage(Msg : String);
|
||||||
|
|
||||||
|
begin
|
||||||
|
If (Msg<>'') then
|
||||||
|
Writeln('Error: ',Msg);
|
||||||
|
Writeln('Usage : ',ExtractFileName(ParamStr(0)),' [options]');
|
||||||
|
Writeln('Where options is one or more of:');
|
||||||
|
Writeln('-a --aliases=aliases Schema aliases as comma-separated name=value pairs.');
|
||||||
|
Writeln(' The form @aliases reads from file "aliases", one alias per line.');
|
||||||
|
Writeln('-b --basename=classname Name of class to use as base class.');
|
||||||
|
Writeln('-d --odata=version OData version to use: v2 or v4.');
|
||||||
|
Writeln('-e --extraunits=extraunits Comma-separated list of unit names to add.');
|
||||||
|
Writeln('-h --help This message.');
|
||||||
|
Writeln('-i --input=filename Name of the file to use as input. Mandatory');
|
||||||
|
Writeln('-o --output=filename Name of the file to use as output.');
|
||||||
|
Writeln(' (default: input file with extension changed to .pas)');
|
||||||
|
Writeln('-p --prefix=fieldprefix Text to use as field prefix (default: F)');
|
||||||
|
Writeln('-u --enumerations=mode How to treat enumerations. Possible values: scoped, prefixtypename, plain');
|
||||||
|
Writeln('-x --servicesuffix=string When constructing type names, add this to schema name. Default is _');
|
||||||
|
Writeln('-v --verbose Output some diagnostic messages');
|
||||||
|
Halt(Ord(Msg<>''));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TConvertEDMXApplication.DoRun;
|
||||||
|
|
||||||
|
Var
|
||||||
|
FConverter : TODataCodeGenerator;
|
||||||
|
S,FInput,FOutput : String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
StopOnException:=True;
|
||||||
|
S:=CheckOptions('a:hd:i:o:nb:p:u:vx',['aliases','help','odata:','input:','output:','namespace','basename:','prefix:','verbose','enumerations','servicesuffix'],True);
|
||||||
|
if (S<>'') then
|
||||||
|
Usage(S);
|
||||||
|
if HasOption('h','help') then
|
||||||
|
Usage('');
|
||||||
|
FInput:=GetOptionValue('i','input');
|
||||||
|
FOutput:=GetOptionValue('o','output');
|
||||||
|
if (FInput='') then
|
||||||
|
Usage('Need input filename');
|
||||||
|
if (FOutput='') then
|
||||||
|
FOutput:=ChangeFileExt(FInput,'.pas');
|
||||||
|
Case lowercase(GetOptionValue('d','odata')) of
|
||||||
|
'v2' : FConverter:=csdl2pas.TEDMX2PasConverter.Create(Self);
|
||||||
|
'v4' : FConverter:=edmx2pas.TEDMX2PasConverter.Create(Self);
|
||||||
|
else
|
||||||
|
Usage('Unknown OData version :'+GetOptionValue('d','odata'));
|
||||||
|
end;
|
||||||
|
try
|
||||||
|
if HasOption('x','servicesuffix') then
|
||||||
|
FConverter.ServiceSuffix:=GetOptionValue('x','servicesuffix');
|
||||||
|
if HasOption('a','aliases') then
|
||||||
|
begin
|
||||||
|
S:=GetOptionValue('a','aliases');
|
||||||
|
if S<>'' then
|
||||||
|
if S[1]='@' then
|
||||||
|
FConverter.Aliases.LoadFromFile(Copy(S,2,Length(S)-1))
|
||||||
|
else
|
||||||
|
FConverter.Aliases.CommaText:=S;
|
||||||
|
end;
|
||||||
|
if HasOption('b','basename') then
|
||||||
|
FConverter.BaseClassName:=GetOptionValue('b','basename');
|
||||||
|
FConverter.ExtraUnits:=GetOptionValue('e','extraunits');
|
||||||
|
if HasOption('p','prefix') then
|
||||||
|
FConverter.FieldPrefix:=GetOptionValue('p','prefix');
|
||||||
|
if HasOption('u','enumerations') then
|
||||||
|
Case lowercase(GetOptionValue('u','enumerations')) of
|
||||||
|
'plain' : FConverter.EnumerationMode:=emPlain;
|
||||||
|
'scoped' : FConverter.EnumerationMode:=emScoped;
|
||||||
|
'prefixtypename' : FConverter.EnumerationMode:=emPrefixTypeName;
|
||||||
|
else
|
||||||
|
Usage('Unknown enumeration mode :'+GetOptionValue('u','enumerations'));
|
||||||
|
end;
|
||||||
|
if HasOption('v','verbose') then
|
||||||
|
FConverter.OnLog:=@DoMyLog;
|
||||||
|
// Go ahead
|
||||||
|
FConverter.LoadFromFile(FInput);
|
||||||
|
FConverter.OutputUnitName:=ChangeFileExt(ExtractFileName(Foutput),'');
|
||||||
|
FConverter.Execute;
|
||||||
|
FConverter.SaveToFile(FOutput);
|
||||||
|
finally
|
||||||
|
FConverter.Free;
|
||||||
|
end;
|
||||||
|
Terminate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure TConvertEDMXApplication.DoMyLog(Sender: TObject;
|
||||||
|
LogType: TCodegenLogType; Const Msg: String);
|
||||||
|
begin
|
||||||
|
Writeln('[',LogType,'] ',Msg);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
With TConvertEDMXApplication.Create(Nil) do
|
||||||
|
try
|
||||||
|
Initialize;
|
||||||
|
Run;
|
||||||
|
finally
|
||||||
|
Free;
|
||||||
|
end;
|
||||||
|
end.
|
||||||
|
|
6597
packages/odata/utils/csdl.pp
Normal file
6597
packages/odata/utils/csdl.pp
Normal file
File diff suppressed because it is too large
Load Diff
2
packages/odata/utils/csdl2pas.pp
Normal file
2
packages/odata/utils/csdl2pas.pp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
{$DEFINE USECSDL}
|
||||||
|
{$i edmx2pas.pp}
|
9845
packages/odata/utils/edm.pas
Normal file
9845
packages/odata/utils/edm.pas
Normal file
File diff suppressed because it is too large
Load Diff
2864
packages/odata/utils/edmx2pas.pp
Normal file
2864
packages/odata/utils/edmx2pas.pp
Normal file
File diff suppressed because it is too large
Load Diff
545
packages/odata/utils/odatacodegen.pp
Normal file
545
packages/odata/utils/odatacodegen.pp
Normal file
@ -0,0 +1,545 @@
|
|||||||
|
unit odatacodegen;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, pastree, restcodegen, inifiles;
|
||||||
|
|
||||||
|
Type
|
||||||
|
EEDMX2PasConverter = Class(Exception);
|
||||||
|
|
||||||
|
// Extra set of keywords to take into account when cleaning a property name.
|
||||||
|
TExtraKeyWords = (ekwNone,ekwObject,ekwEntity,ekwEntitySet,ekwEntityContainer,ekwservice);
|
||||||
|
|
||||||
|
TODataVersion = (ODataV2,ODataV4);
|
||||||
|
TEnumerationMode = (emScoped,emPrefixTypeName,emPlain);
|
||||||
|
|
||||||
|
{ TPropertySetter }
|
||||||
|
TPropertyFlag = (pfRequired,pfNavigation, pfIndexed, pfReadOnly, pfNeedSetter, pfNeedGetter, pfInkey);
|
||||||
|
TPropertyFlags = Set of TPropertyFlag;
|
||||||
|
|
||||||
|
TResultType = (rtNone,rtSimple,rtObject,rtArraySimple,rtArrayObject);
|
||||||
|
|
||||||
|
// Specialized TPasElement classes.
|
||||||
|
// Using these tells the code generator what kind of code it must generate for an identifier.
|
||||||
|
TPropertySetter = Class(TPasProcedure)
|
||||||
|
private
|
||||||
|
FProp: TPasElement;
|
||||||
|
Public
|
||||||
|
Property TheProperty : TPasElement Read FProp Write FProp;
|
||||||
|
end;
|
||||||
|
TPropertyGetter = Class(TPasFunction)
|
||||||
|
private
|
||||||
|
FProp: TPasElement;
|
||||||
|
Public
|
||||||
|
Property TheProperty : TPasElement Read FProp Write FProp;
|
||||||
|
end;
|
||||||
|
TGetRestKind = Class(TPasProcedure);
|
||||||
|
TObjectRestKind = Class(TPasClassFunction);
|
||||||
|
TExportPropertyName = class(TPasClassFunction);
|
||||||
|
TCreateContainer = Class(TPasFunction);
|
||||||
|
TCreateEntitySet = Class(TPasFunction);
|
||||||
|
TEntityClassFunction = Class(TPasClassFunction);
|
||||||
|
TGetNavigationProperty = Class(TPasFunction);
|
||||||
|
TGetSingleton = Class(TPasFunction);
|
||||||
|
TGetContainedSingleton = Class(TPasFunction);
|
||||||
|
TKeyAsURLPart = Class(TPasFunction);
|
||||||
|
TEntityMethod = Class(TPasFunction);
|
||||||
|
TSetArrayLength = Class(TPasProcedure);
|
||||||
|
TGetStream = Class(TPasProcedure);
|
||||||
|
TSetStream = Class(TPasProcedure);
|
||||||
|
TBoundFunction = Class(TPasFunction);
|
||||||
|
TBoundActionProc = Class(TPasProcedure);
|
||||||
|
TBoundActionFunc = Class(TPasFunction);
|
||||||
|
TUnBoundFunction = Class(TPasFunction)
|
||||||
|
private
|
||||||
|
FPath: STring;
|
||||||
|
Public
|
||||||
|
Property ExportPath : STring Read FPath Write FPath;
|
||||||
|
end;
|
||||||
|
TUnBoundActionFunc = Class(TPasFunction)
|
||||||
|
private
|
||||||
|
FPath: STring;
|
||||||
|
Public
|
||||||
|
Property ExportPath : STring Read FPath Write FPath;
|
||||||
|
end;
|
||||||
|
TUnBoundActionProc = Class(TPasProcedure)
|
||||||
|
private
|
||||||
|
FPath: STring;
|
||||||
|
Public
|
||||||
|
Property ExportPath : STring Read FPath Write FPath;
|
||||||
|
end;
|
||||||
|
TEntityGet = Class(TEntityMethod);
|
||||||
|
TEntityList = Class(TEntityMethod);
|
||||||
|
TEntityListAll = Class(TEntityList);
|
||||||
|
TEntityPut = Class(TEntityMethod);
|
||||||
|
TEntityPatch = Class(TEntityMethod);
|
||||||
|
TEntityPost = Class(TEntityMethod);
|
||||||
|
TEntityDelete = Class(TEntityMethod);
|
||||||
|
TServiceClass = Class(TPasClassType);
|
||||||
|
TComplexClass = Class(TPasClassType);
|
||||||
|
TEntityClass = Class(TPasClassType);
|
||||||
|
TEntityContainerClass = Class(TPasClassType);
|
||||||
|
TEntitySetClass = Class(TPasClassType);
|
||||||
|
|
||||||
|
{ TODataCodeGenerator }
|
||||||
|
|
||||||
|
TODataCodeGenerator = class(TRestCodeGenerator)
|
||||||
|
private
|
||||||
|
FAliases: TStrings;
|
||||||
|
FBaseComplexType: String;
|
||||||
|
FBaseEntityContainerType: String;
|
||||||
|
FBaseEntitySetType: String;
|
||||||
|
FBaseEntityType: String;
|
||||||
|
FBaseServiceType: String;
|
||||||
|
FEnumerationMode: TEnumerationMode;
|
||||||
|
FFieldPrefix: String;
|
||||||
|
FSchemaAncestor: String;
|
||||||
|
FServiceSuffix: String;
|
||||||
|
FReservedWords : TStringList;
|
||||||
|
FIdentifierMap : TStrings;
|
||||||
|
procedure SetAliases(AValue: TStrings);
|
||||||
|
function GetReservedWords: TStrings;
|
||||||
|
procedure SetReservedWords(AValue: TStrings);
|
||||||
|
Protected
|
||||||
|
procedure EmitOptions; virtual;
|
||||||
|
function ConvertTypeToStringExpr(const ExprName, ExprType: String): String;
|
||||||
|
Function GetResultType(Const aType: String; Out AElementType : String): TResultType;
|
||||||
|
function GetBaseClassName(El: TPasClassType): String;
|
||||||
|
Procedure RegisterBaseTypes; virtual;
|
||||||
|
function IsSimpleType(const aType: String): Boolean;
|
||||||
|
function FlattenName(const AName: String): String;
|
||||||
|
procedure WriteProcedureDecl(P: TPasProcedure);
|
||||||
|
function CleanPropertyName(const AName: String; UseExtra: TExtraKeyWords): string;
|
||||||
|
function CleanPropertyName(const AName: UnicodeString; UseExtra: TExtraKeyWords): string;
|
||||||
|
Function CountProperties(C: TPasClassType): Integer;
|
||||||
|
Property IdentifierMap : TStrings Read FIdentifierMap;
|
||||||
|
Public
|
||||||
|
Constructor Create(AOwner : TComponent); override;
|
||||||
|
Destructor destroy; override;
|
||||||
|
Class Function WTOA(Const S : UnicodeString) : String;
|
||||||
|
Function is26Only(P: TPasProcedure): Boolean;
|
||||||
|
Function BaseUnits : String; override;
|
||||||
|
Class function IndentStrings(S: TStrings; indent: Integer): string;
|
||||||
|
Class Function ODataVersion : TODataVersion; virtual; abstract;
|
||||||
|
Published
|
||||||
|
Property BaseComplexType : String Read FBaseComplexType Write FBaseComplexType;
|
||||||
|
Property BaseEntityType : String Read FBaseEntityType Write FBaseEntityType;
|
||||||
|
Property BaseEntityContainerType : String Read FBaseEntityContainerType Write FBaseEntityContainerType;
|
||||||
|
Property BaseServiceType : String Read FBaseServiceType Write FBaseServiceType;
|
||||||
|
Property BaseEntitySetType : String Read FBaseEntitySetType Write FBaseEntitySetType;
|
||||||
|
Property Aliases : TStrings Read FAliases Write SetAliases;
|
||||||
|
Property SchemaAncestor : String Read FSchemaAncestor Write FSchemaAncestor;
|
||||||
|
Property FieldPrefix: String Read FFieldPrefix Write FFieldPrefix;
|
||||||
|
Property ServiceSuffix : String Read FServiceSuffix Write FServiceSuffix;
|
||||||
|
property EnumerationMode : TEnumerationMode Read FEnumerationMode Write FEnumerationMode;
|
||||||
|
Property ReservedWords : TStrings Read GetReservedWords Write SetReservedWords;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{ TODataCodeGenerator }
|
||||||
|
|
||||||
|
procedure TODataCodeGenerator.SetAliases(AValue: TStrings);
|
||||||
|
begin
|
||||||
|
if FAliases=AValue then Exit;
|
||||||
|
FAliases.Assign(AValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TODataCodeGenerator.Create(AOwner: TComponent);
|
||||||
|
begin
|
||||||
|
inherited Create(AOwner);
|
||||||
|
BaseClassName:='TODataObject';
|
||||||
|
BaseComplexType:='TODataObject';
|
||||||
|
BaseEntityType:='TODataEntity';
|
||||||
|
BaseEntityContainerType:='TODataEntityContainer';
|
||||||
|
BaseServiceType:='TODataService';
|
||||||
|
BaseEntitySetType:='TODataEntitySet';
|
||||||
|
SchemaAncestor:='TObject';
|
||||||
|
FieldPrefix:='F';
|
||||||
|
ServiceSuffix:='_';
|
||||||
|
FAliases:=TStringlist.Create;
|
||||||
|
FIdentifierMap:=THashedStringList.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TODataCodeGenerator.destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FAliases);
|
||||||
|
FreeAndNil(FReservedWords);
|
||||||
|
FreeAndNil(FIdentifierMap);
|
||||||
|
Inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.BaseUnits: String;
|
||||||
|
begin
|
||||||
|
Result:='fpjson, restbase, odatabase, odataservice';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.GetReservedWords: TStrings;
|
||||||
|
begin
|
||||||
|
if (FReservedWords=Nil) then
|
||||||
|
begin
|
||||||
|
FReservedWords:=TStringList.Create;
|
||||||
|
FReservedWords.Sorted:=True;
|
||||||
|
end;
|
||||||
|
Result:=FReservedWords;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TODataCodeGenerator.SetReservedWords(AValue: TStrings);
|
||||||
|
|
||||||
|
begin
|
||||||
|
if AValue=FReservedwords then exit;
|
||||||
|
if AValue.Count=0 then
|
||||||
|
FreeAndNil(FReservedWords)
|
||||||
|
else
|
||||||
|
ReservedWords.Assign(AValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TODataCodeGenerator.WTOA(const S: UnicodeString): String;
|
||||||
|
begin
|
||||||
|
Result:=AnsiString(S);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.is26Only(P: TPasProcedure): Boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:=P is TSetArrayLength;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TODataCodeGenerator.IndentStrings(S: TStrings; indent: Integer
|
||||||
|
): string;
|
||||||
|
|
||||||
|
Var
|
||||||
|
I,CurrLen,CurrPos : Integer;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:='';
|
||||||
|
CurrLen:=0;
|
||||||
|
CurrPos:=0;
|
||||||
|
For I:=0 to S.Count-1 do
|
||||||
|
begin
|
||||||
|
CurrLen:=Length(S[i]);
|
||||||
|
If (CurrLen+CurrPos)>72 then
|
||||||
|
begin
|
||||||
|
Result:=Result+LineEnding+StringOfChar(' ',Indent);
|
||||||
|
CurrPos:=Indent;
|
||||||
|
end;
|
||||||
|
Result:=Result+S[i];
|
||||||
|
CurrPos:=CurrPos+CurrLen;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TODataCodeGenerator.WriteProcedureDecl(P : TPasProcedure);
|
||||||
|
|
||||||
|
Var
|
||||||
|
S : TStrings;
|
||||||
|
R: TPasResultElement;
|
||||||
|
T : String;
|
||||||
|
B : Boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
S:=TStringList.Create;
|
||||||
|
try
|
||||||
|
S.Add(P.TypeName+' '+P.Name);
|
||||||
|
P.ProcType.GetArguments(S);
|
||||||
|
if P.ProcType.InheritsFrom(TPasFunctionType) then
|
||||||
|
If Assigned(TPasFunctionType(P.ProcType).ResultEl) then
|
||||||
|
begin
|
||||||
|
R:=TPasFunctionType(P.ProcType).ResultEl;
|
||||||
|
T:=' : ';
|
||||||
|
If (R.ResultType.Name<>'') then
|
||||||
|
T:=T+R.ResultType.Name
|
||||||
|
else
|
||||||
|
T:=T+R.ResultType.GetDeclaration(False);
|
||||||
|
S.Add(T);
|
||||||
|
end;
|
||||||
|
P.GetModifiers(S);
|
||||||
|
B:=Is26Only(P);
|
||||||
|
if B then
|
||||||
|
AddLn('{$IFDEF VER2_6}');
|
||||||
|
AddLn(IndentStrings(S,Length(S[0]))+';');
|
||||||
|
if B then
|
||||||
|
AddLn('{$ENDIF VER2_6}');
|
||||||
|
finally
|
||||||
|
S.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.CleanPropertyName(const AName: String;
|
||||||
|
UseExtra: TExtraKeyWords): string;
|
||||||
|
Const
|
||||||
|
// Pascal keywords
|
||||||
|
KW=';absolute;and;array;asm;begin;case;const;constructor;destructor;div;do;'+
|
||||||
|
'downto;else;end;file;for;function;goto;if;implementation;in;inherited;'+
|
||||||
|
'inline;interface;label;mod;nil;not;object;of;on;operator;or;packed;'+
|
||||||
|
'procedure;program;record;reintroduce;repeat;self;set;shl;shr;string;then;'+
|
||||||
|
'to;type;unit;until;uses;var;while;with;xor;dispose;exit;false;new;true;'+
|
||||||
|
'as;class;dispinterface;except;exports;finalization;finally;initialization;'+
|
||||||
|
'inline;is;library;on;out;packed;property;raise;resourcestring;threadvar;try;'+
|
||||||
|
'private;published;length;setlength;result;';
|
||||||
|
// Reserved words (methods)
|
||||||
|
RWComponent = ';post;component;name;notification;componentcount;';
|
||||||
|
RWOdataObject = 'destroy;loadPropertyfromjson;makekeystring;allowadditionalproperties;odataannotations;odataannotationvalues;odataannotationcount;';
|
||||||
|
RWEntity = 'baseurl;keyasurlpart;delete;basepath;post;put;patch;';
|
||||||
|
RWEntitySet = RWComponent+'getbaseurl;checkservice;checkcontainer;notification;getsingle;getmulti;containerurl;containedpath;service;objectrestkind;entityclass;getservice;container;';
|
||||||
|
RWEntityContainer = RWComponent+'checkservice;objectrestkind;entitycontainername;defaultservice;createentityset;service;';
|
||||||
|
RWService = RWComponent+'dolog;composeurl;service;jsontoodataerror;resptoerror;objectrestkind;servicename;registerservice;registerentitycontainers;addtoquery;'+
|
||||||
|
'queryparamstostring;servicecall;getstream;setstream;arrayservicecall;getmulti;createentitycontainer;getentityclass;onlog;webclient;serviceurl;apineedsauth;'+
|
||||||
|
'odatarequestheaders;lastresponseheaders;odatametadata;';
|
||||||
|
|
||||||
|
|
||||||
|
Var
|
||||||
|
I : Integer;
|
||||||
|
RW : String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:=Aname;
|
||||||
|
For I:=Length(Result) downto 1 do
|
||||||
|
If Not ((Upcase(Result[i]) in ['_','A'..'Z'])
|
||||||
|
or ((I>1) and (Result[i] in (['0'..'9'])))) then
|
||||||
|
Delete(Result,i,1);
|
||||||
|
if Pos(';'+lowercase(Result)+';',KW)<>0 then
|
||||||
|
Result:='_'+Result;
|
||||||
|
if UseExtra<>ekwNone then
|
||||||
|
begin
|
||||||
|
Case useExtra of
|
||||||
|
ekwObject : RW:=RWOdataObject;
|
||||||
|
ekwEntity : RW:=RWEntity;
|
||||||
|
ekwEntitySet : RW:=RWEntitySet;
|
||||||
|
ekwEntityContainer : RW:=RWEntityContainer;
|
||||||
|
ekwservice : RW:=RWService;
|
||||||
|
end;
|
||||||
|
if Pos(';'+lowercase(Result)+';',RW)<>0 then
|
||||||
|
Result:='_'+Result;
|
||||||
|
if Assigned(FReservedWords) then
|
||||||
|
if FReservedWords.IndexOf(Result)<>-1 then
|
||||||
|
Result:='_'+Result;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.CleanPropertyName(const AName: UnicodeString;
|
||||||
|
UseExtra: TExtraKeyWords): string;
|
||||||
|
begin
|
||||||
|
Result:=CleanpropertyName(WTOA(AName),UseExtra);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.FlattenName(const AName: String): String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:=StringReplace(AName,'.','_',[rfReplaceAll]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.IsSimpleType(const aType: String): Boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Case LowerCase(aType) of
|
||||||
|
'boolean': Result:=True;
|
||||||
|
'byte' : Result:=True;
|
||||||
|
'tsbyte': Result:=True;
|
||||||
|
'shortint': Result:=True;
|
||||||
|
'int16': Result:=True;
|
||||||
|
'smallint': Result:=True;
|
||||||
|
'word': Result:=True;
|
||||||
|
'int32': Result:=True;
|
||||||
|
'integer': Result:=True;
|
||||||
|
'cardinal': Result:=True;
|
||||||
|
'dword': Result:=True;
|
||||||
|
'int64': Result:=True;
|
||||||
|
'qwordl': Result:=True;
|
||||||
|
'tint16': Result:=True;
|
||||||
|
'tint32': Result:=True;
|
||||||
|
'tint64': Result:=True;
|
||||||
|
'string': Result:=True;
|
||||||
|
'guidstring': Result:=True;
|
||||||
|
'tguidstring': Result:=True;
|
||||||
|
'double': Result:=True;
|
||||||
|
'single': Result:=True;
|
||||||
|
else
|
||||||
|
Result:=False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TODataCodeGenerator.RegisterBaseTypes;
|
||||||
|
|
||||||
|
Const
|
||||||
|
TypeCount = 68;
|
||||||
|
|
||||||
|
BaseTypes : Array[1..TypeCount,1..2] of String =
|
||||||
|
(('Edm.Byte','Byte'), ('Collection(Edm.Byte)','TByteArray'),
|
||||||
|
('Edm.SByte','TSByte'), ('Collection(Edm.SByte)','TShortintArray'),
|
||||||
|
('Edm.int16','TInt16'), ('Collection(Edm.int16)','TInt16Array'),
|
||||||
|
('Edm.int32','TInt32'), ('Collection(Edm.int32)','TInt32Array'),
|
||||||
|
('Edm.int64','int64'), ('Collection(Edm.int64)','TInt64Array'),
|
||||||
|
('Edm.string','string'), ('Collection(Edm.string)','TStringArray'),
|
||||||
|
('Edm.Guid','TGUIDString'), ('Collection(Edm.guid)','TGuidStringArray'),
|
||||||
|
('Edm.Duration','TDuration'), ('Collection(Edm.Duration)','TStringArray'),
|
||||||
|
('Edm.Boolean','boolean'), ('Collection(Edm.boolean)','TBooleanArray'),
|
||||||
|
('Edm.Date','TDate'), ('Collection(Edm.Date)','TDateArray'),
|
||||||
|
('Edm.DateTime','TDateTime'), ('Collection(Edm.DateTime)','TDateTimeArray'),
|
||||||
|
('Edm.Time','TTime'), ('Collection(Edm.Time)','TTimeArray'),
|
||||||
|
('Edm.TimeOfDay','TTimeOfDay'), ('Collection(Edm.TimeOfDay)','TTimeOfDayArray'),
|
||||||
|
('Edm.DateTimeOffset','TDateTime'), ('Collection(Edm.DateTimeOffcset)','TDateTimeArray'),
|
||||||
|
('Edm.Decimal','double'), ('Collection(Edm.Decimal)','TDoubleArray'),
|
||||||
|
('Edm.Double','Double'), ('Collection(Edm.Double)','TDoubleArray'),
|
||||||
|
('Edm.Single','Single'), ('Collection(Edm.Single)','TSingleArray'),
|
||||||
|
('Edm.Binary','TBinary'), ('Collection(Edm.Binary)','TBinaryArray'),
|
||||||
|
('Edm.Stream','TStream'), ('Collection(Edm.Stream)','TByteArrayArray'),
|
||||||
|
('Edm.Geography','TGeography'), ('Collection(Edm.Geography)','TGeographyArray'),
|
||||||
|
('Edm.GeographyPoint','TGeographyPoint'), ('Collection(Edm.GeographyPoint)','TGeographyPointArray'),
|
||||||
|
('Edm.GeographyPolygon','TGeographyPolygon'), ('Collection(Edm.GeographyPolygon)','TGeographyPolygonArray'),
|
||||||
|
('Edm.GeographyLineString','TGeographyLineString'), ('Collection(Edm.GeographyLineString)','TGeographyLineStringArray'),
|
||||||
|
('Edm.GeographyMultiPoint','TGeographyMultiPoint'), ('Collection(Edm.GeographyMultiPoint)','TGeographyMultiPointArray'),
|
||||||
|
('Edm.GeographyMultiString','TGeographyMultiLineString'), ('Collection(Edm.GeographyMultiLineString)','TGeographyMultiLineStringArray'),
|
||||||
|
('Edm.GeographyMultiPolygon','TGeographyMultiPolygon'), ('Collection(Edm.GeographyMultiPolygon)','TGeographyMultiPolygonArray'),
|
||||||
|
('Edm.Geometry','TGeometry'), ('Collection(Edm.Geometry)','TGeometryArray'),
|
||||||
|
('Edm.GeometryPoint','TGeometryPoint'), ('Collection(Edm.GeometryPoint)','TGeometryPointArray'),
|
||||||
|
('Edm.GeometryPolygon','TGeometryPolygon'), ('Collection(Edm.GeometryPolygon)','TGeometryPolygonArray'),
|
||||||
|
('Edm.GeometryLineString','TGeometryLineString'), ('Collection(Edm.GeometryLineString)','TGeometryLineStringArray'),
|
||||||
|
('Edm.GeometryMultiPoint','TGeometryMultiPoint'), ('Collection(Edm.GeometryMultiPoint)','TGeometryMultiPointArray'),
|
||||||
|
('Edm.GeometryMultiString','TGeometryMultiLineString'), ('Collection(Edm.GeometryMultiLineString)','TGeometryMultiLineStringArray'),
|
||||||
|
('Edm.GeometryMultiPolygon','TGeometryMultiPolygon'), ('Collection(Edm.GeometryMultiPolygon)','TGeometryMultiPolygonArray'),
|
||||||
|
('Edm.GeographyCollection','TGeographyArray'), ('Edm.GeometryCollection','TGeometryArray')
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
Var
|
||||||
|
I : integer;
|
||||||
|
begin
|
||||||
|
For I:=1 to TypeCount do
|
||||||
|
FIdentifierMap.Add(LowerCase(BaseTypes[I,1])+'='+BaseTypes[I,2]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.GetBaseClassName(El: TPasClassType): String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:='';
|
||||||
|
if Assigned(EL.AncestorType) then
|
||||||
|
Result:=EL.AncestorType.Name;
|
||||||
|
if (Result='') then
|
||||||
|
begin
|
||||||
|
if EL.InheritsFrom(TServiceClass) then
|
||||||
|
Result:=BaseServiceType
|
||||||
|
else if EL.InheritsFrom(TEntityContainerClass) then
|
||||||
|
Result:=BaseEntityContainerType
|
||||||
|
else if EL.InheritsFrom(TEntitySetClass) then
|
||||||
|
Result:=BaseEntitySetType
|
||||||
|
else if EL.InheritsFrom(TEntityClass) then
|
||||||
|
Result:=BaseEntityType
|
||||||
|
else if EL.InheritsFrom(TComplexClass) then
|
||||||
|
Result:=BaseComplexType
|
||||||
|
else
|
||||||
|
Result:=BaseClassName;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.CountProperties(C: TPasClassType): Integer;
|
||||||
|
|
||||||
|
Var
|
||||||
|
I : Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result:=0;
|
||||||
|
While (C<>Nil) do
|
||||||
|
begin
|
||||||
|
For I:=0 to C.Members.Count-1 do
|
||||||
|
If TObject(C.Members[i]) is TPasProperty then
|
||||||
|
Inc(Result);
|
||||||
|
if C.AncestorType is TPasClassType then
|
||||||
|
C:=C.AncestorType as TPasClassType
|
||||||
|
else
|
||||||
|
C:=Nil;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.GetResultType(const aType: String; out
|
||||||
|
AElementType: String): TResultType;
|
||||||
|
|
||||||
|
Var
|
||||||
|
P : Integer;
|
||||||
|
EN : String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
P:=Pos('array',lowercase(aType));
|
||||||
|
if (aType='') then
|
||||||
|
Result:=rtNone
|
||||||
|
else if IsSimpleType(AType) then
|
||||||
|
Result:=rtSimple
|
||||||
|
else if P>0 then
|
||||||
|
begin
|
||||||
|
AElementType:=Copy(atype,1,P-1);
|
||||||
|
EN:=AElementType;
|
||||||
|
if (EN<>'') and (EN[1]='T') then
|
||||||
|
Delete(EN,1,1);
|
||||||
|
if IsSimpleType(EN) then
|
||||||
|
begin
|
||||||
|
Result:=rtArraySimple;
|
||||||
|
AElementType:=EN;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result:=rtArrayObject;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result:=rtObject;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TODataCodeGenerator.ConvertTypeToStringExpr(const ExprName,
|
||||||
|
ExprType: String): String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Case LowerCase(ExprType) of
|
||||||
|
'boolean' : Result:='BoolToStr('+ExprName+',''true'',''false'')';
|
||||||
|
'byte' : Result:='IntToStr('+ExprName+')';
|
||||||
|
'tsbyte': Result:='IntToStr('+ExprName+')';
|
||||||
|
'int16': Result:='IntToStr('+ExprName+')';
|
||||||
|
'int32': Result:='IntToStr('+ExprName+')';
|
||||||
|
'int64': Result:='IntToStr('+ExprName+')';
|
||||||
|
'tint16': Result:='IntToStr('+ExprName+')';
|
||||||
|
'tint32': Result:='IntToStr('+ExprName+')';
|
||||||
|
'tint64': Result:='IntToStr('+ExprName+')';
|
||||||
|
'string': Result:='TODataObject.MakeKeyString('+ExprName+')';
|
||||||
|
'tguidstring': Result:='TODataObject.MakeKeyString('+ExprName+')';
|
||||||
|
'tdatetime': Result:='FormatDateTime(''yyyy-mm-dd"T"hhmmss'','+ExprName+')';
|
||||||
|
'double': Result:='FloatToStr('+ExprName+')';
|
||||||
|
'single': Result:='FloatToStr('+ExprName+')';
|
||||||
|
'tbinary' : Result:='BinaryToString('+ExprName+')';
|
||||||
|
else
|
||||||
|
Raise EEDMX2PasConverter.CreateFmt('GET : Unsupported key type "%s" for %s',[ExprType,ExprName]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TODataCodeGenerator.EmitOptions;
|
||||||
|
|
||||||
|
Var
|
||||||
|
I : Integer;
|
||||||
|
S : String;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
Addln('(*');
|
||||||
|
IncIndent;
|
||||||
|
Addln('Options used to generate: ');
|
||||||
|
Str(ODataVersion,S);
|
||||||
|
Addln('OData version : '+S);
|
||||||
|
Addln('BasecomplexType : '+BaseComplexType);
|
||||||
|
Addln('BaseEntityType : '+BaseEntityType);
|
||||||
|
Addln('BaseEntityContainerType : '+BaseEntityContainerType);
|
||||||
|
Addln('BaseServiceType : '+BaseServiceType);
|
||||||
|
Addln('BaseEntitySetType : '+BaseEntitySetType);
|
||||||
|
For I:=0 to Aliases.Count-1 do
|
||||||
|
Addln('Aliases[%d] : %s',[i,Aliases[i]]);
|
||||||
|
Addln('SchemaAncestor : '+SchemaAncestor);
|
||||||
|
Addln('FieldPrefix : '+FieldPrefix);
|
||||||
|
Addln('ServiceSuffix : '+ServiceSuffix);
|
||||||
|
Str(EnumerationMode,S);
|
||||||
|
Addln('EnumerationMode : '+S);
|
||||||
|
decIndent;
|
||||||
|
Addln('*)');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
46
packages/odata/utils/ras.pas
Normal file
46
packages/odata/utils/ras.pas
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
This unit has been produced by ws_helper.
|
||||||
|
Input unit name : "System_Data_Resources_AnnotationSchema".
|
||||||
|
This unit name : "ras".
|
||||||
|
Date : "12-5-16 15:37:59".
|
||||||
|
}
|
||||||
|
unit ras;
|
||||||
|
{$IFDEF FPC}
|
||||||
|
{$mode objfpc} {$H+}
|
||||||
|
{$ENDIF}
|
||||||
|
{$DEFINE WST_RECORD_RTTI}
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses SysUtils, Classes, TypInfo, base_service_intf, service_intf;
|
||||||
|
|
||||||
|
const
|
||||||
|
sNAME_SPACE = 'http://schemas.microsoft.com/ado/2009/02/edm/annotation';
|
||||||
|
sUNIT_NAME = 'System_Data_Resources_AnnotationSchema';
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
|
||||||
|
TStoreGeneratedPattern = (
|
||||||
|
None
|
||||||
|
,Identity
|
||||||
|
,Computed
|
||||||
|
);
|
||||||
|
|
||||||
|
StoreGeneratedPattern_Type = TStoreGeneratedPattern;
|
||||||
|
|
||||||
|
LazyLoadingEnabled_Type = boolean;
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
uses metadata_repository, record_rtti;
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
typeRegistryInstance : TTypeRegistry = nil;
|
||||||
|
initialization
|
||||||
|
typeRegistryInstance := GetTypeRegistry();
|
||||||
|
|
||||||
|
typeRegistryInstance.Register(sNAME_SPACE,TypeInfo(TStoreGeneratedPattern),'TStoreGeneratedPattern');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
End.
|
1047
packages/odata/xml/msgraph.xml
Normal file
1047
packages/odata/xml/msgraph.xml
Normal file
File diff suppressed because it is too large
Load Diff
15696
packages/odata/xml/sharepoint.xml
Normal file
15696
packages/odata/xml/sharepoint.xml
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user