
Purpose: Framework Core Low-Level Variants / TDocVariant process
- this unit is a part of the Open Source Synopse mORMot framework 2, licensed under a MPL/GPL/LGPL three license - see LICENSE.md
| Unit Name | Description | |
|---|---|---|
| mormot.core.base | Framework Core Shared Types and RTL-like Functions | |
| mormot.core.buffers | Framework Core Low-Level Memory Buffer Process | |
| mormot.core.data | Framework Core Low-Level Data Processing Functions | |
| mormot.core.json | Framework Core Low-Level JSON Processing | |
| mormot.core.os | Framework Core Low-Level Wrappers to the Operating-System API | |
| mormot.core.rtti | Framework Core Low-Level Cross-Compiler RTTI Definitions | |
| mormot.core.text | Framework Core Low-Level Text Processing | |
| mormot.core.unicode | Framework Core Low-Level Unicode UTF-8 UTF-16 Ansi Conversion |
| Objects | Description | |
|---|---|---|
| EDocDict | Exception raised by IDocDict | |
| EDocList | Exception raised by IDocList | |
| EDocVariant | Exception class associated to TDocVariant JSON/BSON document | |
| ESynVariant | Exception class raised by this unit during raw Variant process | |
| IDocAny | Abstract parent with common methods to IDocList/IDocDict wrappers | |
| IDocDict | A Dictionary, used to store key:value pairs | |
| IDocList | A List, used to store multiple values | |
| TDocVariant | A custom variant type used to store any JSON/BSON document-based content | |
| TDocVariantData | Memory structure used for TDocVariant storage of any JSON/BSON document-based content as variant | |
| TSynInvokeableVariantType | Custom variant handler with easier/faster access of variant properties, and JSON serialization support |
ESynVariant = class(ESynException)
Exception class raised by this unit during raw Variant process
TSynInvokeableVariantType = class(TInvokeableVariantType)
Custom variant handler with easier/faster access of variant properties, and JSON serialization support
- default GetProperty/SetProperty methods are called via some protected virtual IntGet/IntSet methods, with less overhead (to be overriden)
- these kind of custom variants will be faster than the default TInvokeableVariantType for properties getter/setter, but you should manually register each type by calling SynRegisterCustomVariantType()
- also feature custom JSON parsing, via TryJsonToVariant() protected method
constructor Create; virtual;
Virtual constructor which should set the custom type Options
function CompareOp(const Left, Right: TVarData; const Operation: TVarOp): boolean; override;
Compare two items - this overriden method will redirect to Compare()
- Delphi RTL does this redirection, where FPC does not (but should)
function FindSynVariantType(aVarType: cardinal): TSynInvokeableVariantType; overload;
Search of a registered custom variant type from its low-level VarType
- will first compare with its own VarType for efficiency
function FindSynVariantType(aVarType: cardinal; out CustomType: TSynInvokeableVariantType): boolean; overload;
Search of a registered custom variant type from its low-level VarType
- will first compare with its own VarType for efficiency
- returns true and set the matching CustomType if found, false otherwise
function IntCompare(const Instance, Another: TVarData; CaseInsensitive: boolean): integer; virtual;
Override this method if default VariantCompAsText() call is not optimal
function IntGet(var Dest: TVarData; const Instance: TVarData; Name: PAnsiChar; NameLen: PtrInt; NoException: boolean): boolean; virtual;
Override this abstract method for actual getter by name implementation
function IntSet(const Instance, Value: TVarData; Name: PAnsiChar; NameLen: PtrInt): boolean; virtual;
Override this abstract method for actual setter by name implementation
function IsOfType(const V: variant): boolean;
Returns TRUE if the supplied variant is of the exact custom type
function IsVoid(const V: TVarData): boolean; virtual;
Returns TRUE if the supplied custom variant is void
- e.g. returns true for a TDocVariant or TBsonVariant with Count = 0
- caller should have ensured that it is of the exact custom type
function IterateCount(const V: TVarData; GetObjectAsValues: boolean): integer; virtual;
Will check if the value is an array, and return the number of items
- if the document is an array, will return the items count (0 meaning void array) - used e.g. by TSynMustacheContextVariant
- this default implementation will return -1 (meaning this is not an array)
- overridden method could implement it, e.g. for TDocVariant of kind dvArray - or dvObject (ignoring names) if GetObjectAsValues is true
function TryJsonToVariant(var Json: PUtf8Char; var Value: variant; EndOfObject: PUtf8Char): boolean; virtual;
Customization of JSON parsing into variants
- is enabled only if the sioHasTryJsonToVariant option is set
- will be called by e.g. by VariantLoadJson() or GetVariantFromJsonField() with Options: PDocVariantOptions parameter not nil
- this default implementation will always returns FALSE, meaning that the supplied JSON is not to be handled by this custom (abstract) variant type
- this method could be overridden to identify any custom JSON content and convert it into a dedicated variant instance, then return TRUE
- warning: should NOT modify JSON buffer in-place, unless it returns true
procedure Clear(var V: TVarData); override;
Clear the content
- this default implementation will set VType := varEmpty
- override it if your custom type needs to manage its internal memory
procedure Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult); override;
Compare two items - overriden method calling case-sensitive IntCompare()
procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: boolean); override;
Copy two variant content
- this default implementation will copy the TVarData memory
- override it if your custom type needs to manage its internal structure
procedure CopyByValue(var Dest: TVarData; const Source: TVarData); virtual;
Copy two variant content by value
- this default implementation will call the Copy() method
- override it if your custom types may use a by reference copy pattern
procedure Iterate(var Dest: TVarData; const V: TVarData; Index: integer); virtual;
Allow to loop over an array document
- Index should be in 0..IterateCount-1 range
- this default implementation will do nothing
procedure Lookup(var Dest: TVarData; const Instance: TVarData; FullName: PUtf8Char; PathDelim: AnsiChar = '.');
This method will allow to look for dotted name spaces, e.g. 'parent.child'
- return Unassigned (varEmpty) if the FullName does not match any value
- will identify TDocVariant storage, or resolve and call the generic TSynInvokeableVariantType.IntGet() method until nested value match
- you can set e.g. PathDelim = '/' to search e.g. for 'parent/child'
procedure ToJson(W: TJsonWriter; Value: PVarData); overload; virtual;
Customization of variant into JSON serialization
procedure ToJson(Value: PVarData; var Json: RawUtf8; const Prefix: RawUtf8 = ''; const Suffix: RawUtf8 = ''; Format: TTextWriterJsonFormat = jsonCompact); overload; virtual;
Save a variant as UTF-8 encoded JSON
- implemented as a wrapper around ToJson()
property Options: TSynInvokeableVariantTypeOptions read fOptions;
Identify how this custom type behave
- as set by the class constructor, to avoid calling any virtual method
EDocVariant = class(ESynException)
Exception class associated to TDocVariant JSON/BSON document
TDocVariant = class(TSynInvokeableVariantType)
A custom variant type used to store any JSON/BSON document-based content
- i.e. name/value pairs for objects, or an array of values (including nested documents), stored in a TDocVariantData memory structure
- you can use _Obj()/_ObjFast() _Arr()/_ArrFast() _Json()/_JsonFast() or _JsonFmt()/_JsonFastFmt() functions to create instances of such variants
- property access may be done via late-binding - with some restrictions for older versions of FPC, e.g. allowing to write:
TDocVariant.NewFast(aVariant); aVariant.Name := 'John'; aVariant.Age := 35; writeln(aVariant.Name,' is ',aVariant.Age,' years old');
- it also supports a small set of pseudo-properties or pseudo-methods:
aVariant._Count = DocVariantData(aVariant).Count aVariant._Kind = ord(DocVariantData(aVariant).Kind) aVariant._JSON = DocVariantData(aVariant).JSON aVariant._(i) = DocVariantData(aVariant).Value[i] aVariant.Value(i) = DocVariantData(aVariant).Value[i] aVariant.Value(aName) = DocVariantData(aVariant).Value[aName] aVariant.Name(i) = DocVariantData(aVariant).Name[i] aVariant.Add(aItem) = DocVariantData(aVariant).AddItem(aItem) aVariant._ := aItem = DocVariantData(aVariant).AddItem(aItem) aVariant.Add(aName,aValue) = DocVariantData(aVariant).AddValue(aName,aValue) aVariant.Exists(aName) = DocVariantData(aVariant).GetValueIndex(aName)>=0 aVariant.Delete(i) = DocVariantData(aVariant).Delete(i) aVariant.Delete(aName) = DocVariantData(aVariant).Delete(aName) aVariant.NameIndex(aName) = DocVariantData(aVariant).GetValueIndex(aName)
- it features direct JSON serialization/unserialization, e.g.:
assert(_Json('["one",2,3]')._JSON='["one",2,3]');
- it features direct trans-typing into a string encoded as JSON, e.g.:
assert(_Json('["one",2,3]')='["one",2,3]');
destructor Destroy; override;
Finalize the stored information
function DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): boolean; override;
Low-level callback to access internal pseudo-methods
- mainly the _(Index: integer): variant method to retrieve an item if the document is an array
function DoProcedure(const V: TVarData; const Name: string; const Arguments: TVarDataArray): boolean; override;
Low-level callback to access internal pseudo-methods
function IntCompare(const Instance, Another: TVarData; CaseInsensitive: boolean): integer; override;
Overriden method redirecting to TDocVariantData.Compare()
function InternNames: TRawUtf8Interning;
Used by dvoInternNames for string interning of all Names[] values
function InternValues: TRawUtf8Interning;
Used by dvoInternValues for string interning of all RawUtf8 Values[]
function IntGet(var Dest: TVarData; const Instance: TVarData; Name: PAnsiChar; NameLen: PtrInt; NoException: boolean): boolean; override;
Overriden method for actual getter by name implementation
function IntSet(const Instance, Value: TVarData; Name: PAnsiChar; NameLen: PtrInt): boolean; override;
Overriden method for actual setter by name implementation
function IsVoid(const V: TVarData): boolean; override;
Returns true if this document has Count = 0
function IterateCount(const V: TVarData; GetObjectAsValues: boolean): integer; override;
Will check if the value is an array, and return the number of items
- if the document is an array, will return the items count (0 meaning void array) - used e.g. by TSynMustacheContextVariant
- this overridden method will implement it for dvArray instance kind
class function New(Options: TDocVariantOptions = []): variant; overload;
Initialize a variant instance to store some document-based content
- you can use this function to create a variant, which can be nested into another document, e.g.:
aVariant := TDocVariant.New; aVariant.id := 10;
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set Options=[dvoValueCopiedByReference] will increase the process speed a lot
- in practice, you should better use _Obj()/_ObjFast() _Arr()/_ArrFast() functions or TDocVariant.NewFast()
class function NewArray(const Items: array of const; Options: TDocVariantOptions = []): variant; overload;
Initialize a variant instance to store some document-based array content
- array will be initialized with data supplied as parameters, e.g.
aVariant := TDocVariant.NewArray(['one',2,3.0]);
which is the same as:
TDocVariant.New(aVariant); TDocVariantData(aVariant).AddItem('one'); TDocVariantData(aVariant).AddItem(2); TDocVariantData(aVariant).AddItem(3.0);
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set aOptions=[dvoValueCopiedByReference] will increase the process speed a lot
- in practice, you should better use the function _Arr() which is a wrapper around this class method
class function NewArray(const Items: TVariantDynArray; Options: TDocVariantOptions = []): variant; overload;
Initialize a variant instance to store some document-based array content
- array will be initialized with data supplied dynamic array of variants
class function NewJson(const Json: RawUtf8; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]): variant;
Initialize a variant instance to store some document-based object content from a supplied (extended) JSON content
- in addition to the JSON RFC specification strict mode, this method will handle some BSON-like extensions, e.g. unquoted field names
- a private copy of the incoming JSON buffer will be used, then it will call the TDocVariantData.InitJsonInPlace() method
- to be used e.g. as:
var V: variant; begin V := TDocVariant.NewJson('{"id":10,"doc":{"name":"John","birthyear":1972}}'); assert(V.id=10); assert(V.doc.name='John'); assert(V.doc.birthYear=1972); // and also some pseudo-properties: assert(V._count=2); assert(V.doc._kind=ord(dvObject));
- or with a JSON array:
V := TDocVariant.NewJson('["one",2,3]'); assert(V._kind=ord(dvArray)); for i := 0 to V._count-1 do writeln(V._(i));
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, add dvoValueCopiedByReference in Options will increase the process speed a lot
- in practice, you should better use the function _Json()/_JsonFast() which are handy wrappers around this class method
class function NewObject(const NameValuePairs: array of const; Options: TDocVariantOptions = []): variant;
Initialize a variant instance to store some document-based object content
- object will be initialized with data supplied two by two, as Name,Value pairs, e.g.
aVariant := TDocVariant.NewObject(['name','John','year',1972]);
which is the same as:
TDocVariant.New(aVariant); TDocVariantData(aVariant).AddValue('name','John'); TDocVariantData(aVariant).AddValue('year',1972);
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set Options=[dvoValueCopiedByReference] will increase the process speed a lot
- in practice, you should better use the function _Obj() which is a wrapper around this class method
class function NewUnique(const SourceDocVariant: variant; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]): variant;
Initialize a variant instance to store some document-based object content from a supplied existing TDocVariant instance
- use it on a value returned as varByRef (e.g. by _() pseudo-method), to ensure the returned variant will behave as a stand-alone value
- for instance, the following:
oSeasons := TDocVariant.NewUnique(o.Seasons);
is the same as:
_Unique(oSeasons);
or even:
oSeasons := _Copy(o.Seasons);
procedure Cast(var Dest: TVarData; const Source: TVarData); override;
Handle type conversion
- only types processed by now are string/OleStr/UnicodeString/date
procedure CastTo(var Dest: TVarData; const Source: TVarData; const AVarType: TVarType); override;
Handle type conversion
- only types processed by now are string/OleStr/UnicodeString/date
procedure Clear(var V: TVarData); override;
Low-level callback to clear the content
procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: boolean); override;
Low-level callback to copy two variant content
- such copy will by default be done by-value, for safety
- if you are sure you will use the variants as read-only, you can set the dvoValueCopiedByReference Option to use faster by-reference copy
procedure CopyByValue(var Dest: TVarData; const Source: TVarData); override;
Copy two variant content by value
- overridden method since instance may use a by-reference copy pattern
class procedure GetSingleOrDefault(const docVariantArray, default: variant; var result: variant);
Will return the unique element of a TDocVariant array or a default
- if the value is a dvArray with one single item, returns this value
- if the value is not a TDocVariant nor a dvArray with one single item, it wil return the default value
class procedure IsOfTypeOrNewFast(var aValue: variant);
Ensure a variant is a TDocVariant instance
- if aValue is not a TDocVariant, will create a new JSON_FAST
procedure Iterate(var Dest: TVarData; const V: TVarData; Index: integer); override;
Allow to loop over an array document
- Index should be in 0..IterateCount-1 range
- this default implementation will do handle dvArray instance kind
class procedure New(out aValue: variant; aOptions: TDocVariantOptions = []); overload;
Initialize a variant instance to store some document-based content
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set aOptions=[dvoValueCopiedByReference] will increase the process speed a lot
class procedure NewFast(const aValues: array of PDocVariantData; aKind: TDocVariantKind = dvUndefined); overload;
Initialize several variant instances to store document-based content
- replace several calls to TDocVariantData.InitFast
- to be used e.g. as
var v1, v2, v3: TDocVariantData; begin TDocVariant.NewFast([@v1,@v2,@v3]); ...
class procedure NewFast(out aValue: variant; aKind: TDocVariantKind = dvUndefined); overload;
Initialize a variant instance to store per-reference document-based content
- same as New(aValue, JSON_FAST);
- to be used e.g. as
var v: variant; begin TDocVariant.NewFast(v); ...
procedure ToJson(W: TJsonWriter; Value: PVarData); override;
This implementation will write the content as JSON object or array
TDocVariantData = object(TObject)
Memory structure used for TDocVariant storage of any JSON/BSON document-based content as variant
- i.e. name/value pairs for objects, or an array of values (including nested documents)
- you can use _Obj()/_ObjFast() _Arr()/_ArrFast() _Json()/_JsonFast() or _JsonFmt()/_JsonFastFmt() functions to create instances of such variants
- you can transtype such an allocated variant into TDocVariantData to access directly its internals (like Count or Values[]/Names[]):
aVariantObject := TDocVariant.NewObject(['name','John','year',1972]); aVariantObject := _ObjFast(['name','John','year',1972]); with _Safe(aVariantObject)^ do for i := 0 to Count-1 do writeln(Names[i],'=',Values[i]); // for an object aVariantArray := TDocVariant.NewArray(['one',2,3.0]); aVariantArray := _JsonFast('["one",2,3.0]'); with _Safe(aVariantArray)^ do for i := 0 to Count-1 do writeln(Values[i]); // for an array
- use "with _Safe(...)^ do" and not "with TDocVariantData(...) do" as the former will handle internal variant redirection (varByRef), e.g. from late binding or assigned another TDocVariant
- Delphi "object" is buggy on stack -> also defined as record with methods
function AddItem(const aValue: variant; aIndex: integer = -1): integer; overload;
Add a value to this document, handled as array
- if instance's Kind is dvObject, it will raise an EDocVariant exception
- you can therefore write e.g.:
TDocVariant.New(aVariant); Assert(TDocVariantData(aVariant).Kind=dvUndefined); TDocVariantData(aVariant).AddItem('one'); Assert(TDocVariantData(aVariant).Kind=dvArray);
- you can specify an optional index in the array where to insert
- returns the index of the corresponding newly added item
function AddItem(const aValue: TDocVariantData; aIndex: integer = -1): integer; overload;
Add a TDocVariant value to this document, handled as array
function AddItemFromText(const aValue: RawUtf8; aIndex: integer = -1): integer;
Add a value to this document, handled as array, from its text representation
- this function expects a UTF-8 text for the value, which would be converted to a variant number, if possible (as varInt/varInt64/varCurrency and/or as varDouble is dvoAllowDoubleValue option is set)
- if instance's Kind is dvObject, it will raise an EDocVariant exception
- you can specify an optional index in the array where to insert
- returns the index of the corresponding newly added item
function AddItemText(const aValue: RawUtf8; aIndex: integer = -1): integer;
Add a RawUtf8 value to this document, handled as array
- if instance's Kind is dvObject, it will raise an EDocVariant exception
- you can specify an optional index in the array where to insert
- returns the index of the corresponding newly added item
function AddOrUpdateValue(const aName: RawUtf8; const aValue: variant; wasAdded: PBoolean = nil; OnlyAddMissing: boolean = false): integer;
Add a value in this document, or update an existing entry
- if instance's Kind is dvArray, it will raise an EDocVariant exception
- any existing Name would be updated with the new Value, unless OnlyAddMissing is set to TRUE, in which case existing values would remain
- returns the index of the corresponding value, which may be just added
function AddValue(aName: PUtf8Char; aNameLen: integer; const aValue: variant; aValueOwned: boolean = false; aIndex: integer = -1): integer; overload;
Add a value in this document
- overloaded function accepting a UTF-8 encoded buffer for the name
function AddValue(const aName: RawUtf8; const aValue: variant; aValueOwned: boolean = false; aIndex: integer = -1): integer; overload;
Add a value in this document
- if aName is set, if dvoCheckForDuplicatedNames option is set, any existing duplicated aName will raise an EDocVariant; if instance's kind is dvArray and aName is defined, it will raise an EDocVariant
- aName may be '' e.g. if you want to store an array: in this case, dvoCheckForDuplicatedNames option should not be set; if instance's Kind is dvObject, it will raise an EDocVariant exception
- if aValueOwned is true, then the supplied aValue will be assigned to the internal values - by default, it will use SetVariantByValue()
- you can therefore write e.g.:
TDocVariant.New(aVariant); Assert(TDocVariantData(aVariant).Kind=dvUndefined); TDocVariantData(aVariant).AddValue('name','John'); Assert(TDocVariantData(aVariant).Kind=dvObject);
- you can specify an optional index in the array where to insert
- returns the index of the corresponding newly added value
function AddValueFromText(const aName, aValue: RawUtf8; DoUpdate: boolean = false): integer;
Add a value in this document, from its text representation
- this function expects a UTF-8 text for the value, which would be converted to a variant number, if possible (as varInt/varInt64/varCurrency and/or as varDouble is dvoAllowDoubleValue option is set)
- if Update=TRUE, will set the property, even if it is existing
function Compare(const Another: TDocVariantData; CaseInsensitive: boolean = false): integer; overload;
Efficient comparison of two TDocVariantData content
- will return the same result than JSON comparison, but more efficiently
function Compare(const aName: RawUtf8; const aValue: variant; aCaseInsensitive: boolean = false): integer; overload;
Compare a TTDocVariantData object property with a given value
- returns -1 if this instance is not a dvObject or has no aName property
function CompareObject(const ObjFields: array of RawUtf8; const Another: TDocVariantData; CaseInsensitive: boolean = false): integer;
Efficient comparison of two TDocVariantData objects
- will always ensure that both this instance and Another are Objects
- will compare all supplied Fields values in their specified order
- if ObjFields is void, will fallback to regular Compare()
function CountItemByValue(const aValue: Variant; CaseInsensitive: boolean = false; StartIndex: integer = 0): integer;
Search and count occurences of one value in this document, handled as array
function Delete(Index: PtrInt): boolean; overload;
Delete a value/item in this document, from its index
- return TRUE on success, FALSE if the supplied index is not correct
function Delete(const aNames: array of RawUtf8): integer; overload;
Delete/filter some values/items in this document, from their name
- return the number of deleted items
function Delete(const aName: RawUtf8; aValue: PVariant = nil): boolean; overload;
Delete a value/item in this document, from its name
- return TRUE on success, FALSE if the supplied name does not exist
function DeleteByPath(const aPath: RawUtf8; aPathDelim: AnsiChar = '.'; aDeletedValue: PVariant = nil): boolean;
Delete a value/item in this document, from its name
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- return TRUE on success, FALSE if the supplied name does not exist
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'
function DeleteByProp(const aPropName, aPropValue: RawUtf8; aPropValueCaseSensitive: boolean): boolean;
Delete a value in this document, by property name match
- {aPropName:aPropValue} will be searched within the stored array or object, and the corresponding item will be deleted, on match
- returns FALSE if no match is found, TRUE if found and deleted
- will call VariantEquals() for value comparison
function DeleteByStartName(aStartName: PUtf8Char; aStartNameLen: integer): integer;
Delete all values matching the first characters of a property name
- returns the number of deleted items
- returns 0 if the document is not a dvObject, or if no match was found
- will use IdemPChar(), so search would be case-insensitive
function DeleteByValue(const aValue: Variant; CaseInsensitive: boolean = false): integer;
Delete one or several value/item in this document, from its value
- returns the number of deleted items
- returns 0 if the document is not a dvObject, or if no match was found
- if the value exists several times, all occurrences would be removed
- is optimized for DeleteByValue(null) call
function Equals(const aName: RawUtf8; const aValue: variant; aCaseInsensitive: boolean = false): boolean; overload;
Efficient equality comparison a TTDocVariantData object property
function Equals(const Another: TDocVariantData; CaseInsensitive: boolean = false): boolean; overload;
Efficient equality comparison of two TDocVariantData content
- just a wrapper around Compare(Another)=0
function Exists(const aName: RawUtf8): boolean;
Search if a given Name do exists in this document
- just a wrapper around GetValueIndex(aName) >= 0
function Extract(aIndex: integer; var aValue: variant; aName: PRawUtf8 = nil): boolean;
Retrieve a value at a given index, and delete it from the array
- negative aIndex are from VCount, i.e. Extract(-1) pop the last item
function FlattenAsNestedObject(const aObjectPropName: RawUtf8): boolean;
Map {"obj.prop1"..,"obj.prop2":..} into {"obj":{"prop1":..,"prop2":...}}
- the supplied aObjectPropName should match the incoming dotted value of all properties (e.g. 'obj' for "obj.prop1")
- if any of the incoming property is not of "obj.prop#" form, the whole process would be ignored
- return FALSE if the TDocVariant did not change
- return TRUE if the TDocVariant has been flattened
function GetAsArray(const aName: RawUtf8; out aArray: PDocVariantData; aSortedCompare: TUtf8Compare = nil): boolean;
Find a non-void array item in this document, and returns its value
- return false if aName is not found, or if not a TDocVariant array
- return true if the name was found as non-void array and set to aArray
- after a SortByName(aSortedCompare), could use faster binary search
function GetAsBoolean(const aName: RawUtf8; out aValue: boolean; aSortedCompare: TUtf8Compare = nil): boolean;
Find an item in this document, and returns its value as boolean
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found, and aValue stores the value
- after a SortByName(aSortedCompare), could use faster binary search
- consider using B[] property if you want simple read/write typed access
function GetAsDocVariant(const aName: RawUtf8; out aValue: PDocVariantData; aSortedCompare: TUtf8Compare = nil): boolean;
Find an item in this document, and returns its value as a TDocVariantData
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found and points to a TDocVariant: then aValue stores a pointer to the value
- after a SortByName(aSortedCompare), could use faster binary search
function GetAsDocVariantSafe(const aName: RawUtf8; aSortedCompare: TUtf8Compare = nil): PDocVariantData;
Find an item in this document, and returns its value as a TDocVariantData
- returns a void TDocVariant if aName is not a document
- after a SortByName(aSortedCompare), could use faster binary search
- consider using O[] or A[] properties if you want simple read-only access, or O_[] or A_[] properties if you want the ability to add a missing object or array in the document
function GetAsDouble(const aName: RawUtf8; out aValue: double; aSortedCompare: TUtf8Compare = nil): boolean;
Find an item in this document, and returns its value as floating point
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found, and aValue stores the value
- after a SortByName(aSortedCompare), could use faster binary search
- consider using D[] property if you want simple read/write typed access
function GetAsInt64(const aName: RawUtf8; out aValue: Int64; aSortedCompare: TUtf8Compare = nil): boolean;
Find an item in this document, and returns its value as integer
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found, and aValue stores the value
- after a SortByName(aSortedCompare), could use faster binary search
- consider using I[] property if you want simple read/write typed access
function GetAsInteger(const aName: RawUtf8; out aValue: integer; aSortedCompare: TUtf8Compare = nil): boolean;
Find an item in this document, and returns its value as integer
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found, and aValue stores the value
- after a SortByName(aSortedCompare), could use faster binary search
- consider using I[] property if you want simple read/write typed access
function GetAsObject(const aName: RawUtf8; out aObject: PDocVariantData; aSortedCompare: TUtf8Compare = nil): boolean;
Find a non-void object item in this document, and returns its value
- return false if aName is not found, or if not a TDocVariant object
- return true if the name was found as non-void object and set to aObject
- after a SortByName(aSortedCompare), could use faster binary search
function GetAsPVariant(aName: PUtf8Char; aNameLen: PtrInt): PVariant; overload;
Find an item in this document, and returns pointer to its value
- lookup the value by aName/aNameLen for an object document, or accept an integer text as index for an array document
- return nil if aName is not found, or if the instance is not a TDocVariant
- return a pointer to the stored variant, if the name has been found
function GetAsPVariant(const aName: RawUtf8; out aValue: PVariant; aSortedCompare: TUtf8Compare = nil): boolean; overload;
Find an item in this document, and returns pointer to its value
- return false if aName is not found
- return true if the name has been found: then aValue stores a pointer to the value
- after a SortByName(aSortedCompare), could use faster binary search
function GetAsRawUtf8(const aName: RawUtf8; out aValue: RawUtf8; aSortedCompare: TUtf8Compare = nil): boolean;
Find an item in this document, and returns its value as RawUtf8
- return false if aName is not found, or if the instance is not a TDocVariant
- return true if the name has been found, and aValue stores the value
- after a SortByName(aSortedCompare), could use faster binary search
- consider using U[] property if you want simple read/write typed access
function GetDocVariantByPath(const aPath: RawUtf8; out aValue: PDocVariantData; aPathDelim: AnsiChar = '.'): boolean;
Retrieve a reference to a TDocVariant, given its path
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- if the supplied aPath does not match any object, it will return false
- if aPath stores a valid TDocVariant, returns true and a pointer to it
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'
function GetDocVariantByProp(const aPropName, aPropValue: RawUtf8; aPropValueCaseSensitive: boolean; out Dest: PDocVariantData): boolean;
Retrieve a reference to a dvObject in the dvArray, from a property value
- {aPropName:aPropValue} will be searched within the stored array, and the corresponding item will be copied into Dest, on match
- returns FALSE if no match is found, TRUE if found and copied by reference
function GetItemByProp(const aPropName, aPropValue: RawUtf8; aPropValueCaseSensitive: boolean; var Dest: variant; DestByRef: boolean = false): boolean;
Retrieve a dvObject in the dvArray, from a property value
- {aPropName:aPropValue} will be searched within the stored array, and the corresponding item will be copied into Dest, on match
- returns FALSE if no match is found, TRUE if found and copied
- create a copy of the variant by default, unless DestByRef is TRUE
- will call VariantEquals() for value comparison
function GetJsonByStartName(const aStartName: RawUtf8): RawUtf8;
Returns a JSON object containing all properties matching the first characters of the supplied property name
- returns null if the document is not a dvObject
- will use IdemPChar(), so search would be case-insensitive
function GetModel(out model: TDocVariantModel): boolean;
Guess the TDocVariantModel corresponding to the current document Options
- returns true if model has been found and set
- returns false if no JSON_[] matches the current options
function GetNames: TRawUtf8DynArray;
Return a dynamic array with all dvObject Names, and length() = Count
- since length(Names) = Capacity, you can use this method to retrieve all the object keys
- consider using FieldNames iterator or Names[0..Count-1] if you need to iterate on the key names
- will internally force length(Names)=length(Values)=Capacity=Count and return the Names[] instance with no memory (re)allocation
- if the document is not a dvObject, will return nil
function GetPVariantByPath(const aPath: RawUtf8; aPathDelim: AnsiChar = '.'): PVariant;
Retrieve a reference to a value, given its path
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- if the supplied aPath does not match any object, it will return nil
- if aPath is found, returns a pointer to the corresponding value
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'
function GetPVariantExistingByPath(const aPath: RawUtf8; aPathDelim: AnsiChar = '.'): PVariant;
Retrieve a reference to a value, given its path
- if the supplied aPath does not match any object, it will follow dvoReturnNullForUnknownProperty option
function GetValueByPath( const aPath: RawUtf8; aPathDelim: AnsiChar = '.'): variant; overload;
Retrieve a value, given its path
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- return Unassigned (varEmpty) if there is no item at the supplied aPath
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'
- see also the P[] property if the default aPathDelim = '.' is enough
function GetValueByPath(const aPath: RawUtf8; out aValue: variant; aPathDelim: AnsiChar = '.'): boolean; overload;
Retrieve a value, given its path
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- returns FALSE if there is no item at the supplied aPath
- returns TRUE and set the found value in aValue
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'
- see also the P[] property if the default aPathDelim = '.' is enough
function GetValueByPath(const aDocVariantPath: array of RawUtf8): variant; overload;
Retrieve a value, given its path
- path is defined as a list of names, e.g. ['doc','glossary','title']
- return Unassigned (varEmpty) if there is no item at the supplied aPath
- this method will only handle nested TDocVariant values: use the slightly slower GetValueByPath() overloaded method, if any nested object may be of another type (e.g. a TBsonVariant)
function GetValueEnumerate(const aName: RawUtf8; aTypeInfo: PRttiInfo; out aValue; aDeleteFoundEntry: boolean = false): boolean;
Find an item in this document, and returns its value as enumerate
- return false if aName is not found, if the instance is not a TDocVariant, or if the value is not a string corresponding to the supplied enumerate
- return true if the name has been found, and aValue stores the value
- will call Delete() on the found entry, if aDeleteFoundEntry is true
function GetValueIndex(aName: PUtf8Char; aNameLen: PtrInt; aCaseSensitive: boolean): integer; overload;
Find an item index in this document from its name
- lookup the value by name for an object document, or accept an integer text as index for an array document
- returns -1 if not found
function GetValueIndex(const aName: RawUtf8): integer; overload;
Find an item index in this document from its name
- search will follow dvoNameCaseSensitive option of this document
- lookup the value by name for an object document, or accept an integer text as index for an array document
- returns -1 if not found
function GetValueOrDefault(const aName: RawUtf8; const aDefault: variant): variant;
Find an item in this document, and returns its value
- return the supplied default if aName is not found, or if the instance is not a TDocVariant
function GetValueOrEmpty(const aName: RawUtf8): variant;
Find an item in this document, and returns its value
- return a cleared variant if aName is not found, or if the instance is not a TDocVariant
function GetValueOrNull(const aName: RawUtf8): variant;
Find an item in this document, and returns its value
- return null if aName is not found, or if the instance is not a TDocVariant
function GetValueOrRaiseException(const aName: RawUtf8): variant;
Find an item in this document, and returns its value
- raise an EDocVariant if not found and dvoReturnNullForUnknownProperty is not set in Options (in this case, it will return Null)
function GetValuesByStartName(const aStartName: RawUtf8; TrimLeftStartName: boolean = false): variant;
Returns a TDocVariant object containing all properties matching the first characters of the supplied property name
- returns null if the document is not a dvObject
- will use IdemPChar(), so search would be case-insensitive
function GetVarData(const aName: RawUtf8; aSortedCompare: TUtf8Compare = nil; aFoundIndex: PInteger = nil): PVarData; overload;
Find an item in this document, and returns its value as TVarData pointer
- return nil if aName is not found, or if the instance is not a TDocVariant
- return a pointer to the value if the name has been found, and optionally fill aFoundIndex^ with its index in Values[]
- after a SortByName(aSortedCompare), could use faster binary search
function GetVarData(const aName: RawUtf8; var aValue: TVarData; aSortedCompare: TUtf8Compare = nil): boolean; overload;
Find an item in this document, and returns its value as TVarData
- return false if aName is not found, or if the instance is not a TDocVariant
- return true and set aValue if the name has been found
- will use simple loop lookup to identify the name, unless aSortedCompare is set, and would let use a faster O(log(n)) binary search after a SortByName()
function InitArrayFromResults(const Json: RawUtf8; aModel: TDocVariantModel): boolean; overload;
Fill a TDocVariant array from standard or non-expanded JSON ORM/DB result
- accept the ORM/DB results dual formats as recognized by TOrmTableJson
- about 2x (expanded) or 3x (non-expanded) faster than Doc.InitJson()
- will also use less memory, because all object field names will be shared
- in expanded mode, the fields order won't be checked, as with TOrmTableJson
- a private copy of the incoming JSON buffer will be used before parsing
function InitArrayFromResults(const Json: RawUtf8; aOptions: TDocVariantOptions = JSON_FAST_FLOAT): boolean; overload;
Fill a TDocVariant array from standard or non-expanded JSON ORM/DB result
- accept the ORM/DB results dual formats as recognized by TOrmTableJson
- about 2x (expanded) or 3x (non-expanded) faster than Doc.InitJson()
- will also use less memory, because all object field names will be shared
- in expanded mode, the fields order won't be checked, as with TOrmTableJson
- a private copy of the incoming JSON buffer will be used before parsing
function InitArrayFromResults(Json: PUtf8Char; JsonLen: PtrInt; aOptions: TDocVariantOptions = JSON_FAST_FLOAT): boolean; overload;
Fill a TDocVariant array from standard or non-expanded JSON ORM/DB result
- accept the ORM/DB results dual formats as recognized by TOrmTableJson, i.e. both [{"f1":"1v1","f2":1v2},{"f2":"2v1","f2":2v2}...] and {"fieldCount":2,"values":["f1","f2","1v1",1v2,"2v1",2v2...],"rowCount":20}
- about 2x (expanded) or 3x (non-expanded) faster than Doc.InitJsonInPlace()
- will also use less memory, because all object field names will be shared
- in expanded mode, the fields order won't be checked, as with TOrmTableJson
- warning: the incoming JSON buffer will be modified in-place: so you should make a private copy before running this method, as overloaded procedures do
- some numbers on a Core i5-13500, extracted from our regression tests:
TDocVariant InitJsonInPlace in 72.91ms i.e. 2.1M rows/s, 268.8 MB/s TDocVariant InitJsonInPlace no guess in 69.49ms i.e. 2.2M rows/s, 282 MB/s TDocVariant InitJsonInPlace dvoIntern in 68.41ms i.e. 2.2M rows/s, 286.5 MB/s TDocVariant FromResults exp in 31.69ms i.e. 4.9M rows/s, 618.6 MB/s TDocVariant FromResults not exp in 24.48ms i.e. 6.4M rows/s, 352.1 MB/s
function InitFrom(const CloneFrom: TDocVariantData; CloneValues: boolean; MakeUnique: boolean = false): PVariant;
Low-level copy a document-based variant with the very same options and count
- if you call Init*() methods in a row, ensure you call Clear in-between
- will copy Count and Names[] by reference, but Values[] only if CloneValues
- returns the first item in Values[]
function InitJson(const Json: RawUtf8; aModel: TDocVariantModel): boolean; overload;
Initialize a variant instance to store some document-based object content from a supplied JSON array or JSON object content
- use the options corresponding to the supplied TDocVariantModel
- a private copy of the incoming JSON buffer will be made
- if you call Init*() methods in a row, ensure you call Clear in-between
- handle only currency for floating point values unless you set mFastFloat
- consider the faster InitArrayFromResults() from ORM/SQL JSON results
function InitJson(const Json: RawUtf8; aOptions: TDocVariantOptions = []): boolean; overload;
Initialize a variant instance to store some document-based object content from a supplied JSON array or JSON object content
- a private copy of the incoming JSON buffer will be used, then it will call the other overloaded InitJsonInPlace() method
- this method is called e.g. by _Json() and _JsonFast() global functions
- if you call Init*() methods in a row, ensure you call Clear in-between
- handle only currency for floating point values: set JSON_FAST_FLOAT or dvoAllowDoubleValue option to support double, with potential precision loss
- consider the faster InitArrayFromResults() from ORM/SQL JSON results
function InitJsonFromFile(const FileName: TFileName; aOptions: TDocVariantOptions = []): boolean;
Initialize a variant instance to store some document-based object content from a file containing some JSON array or JSON object
- file may have been serialized using the SaveToJsonFile() method
- if you call Init*() methods in a row, ensure you call Clear in-between
- handle only currency for floating point values: set JSON_FAST_FLOAT or dvoAllowDoubleValue option to support double, with potential precision loss
- will assume text file with no BOM is already UTF-8 encoded
function InitJsonInPlace(Json: PUtf8Char; aOptions: TDocVariantOptions = []; aEndOfObject: PUtf8Char = nil): PUtf8Char;
Initialize a variant instance to store some document-based object content from a supplied JSON array or JSON object content
- warning: the incoming JSON buffer will be modified in-place: so you should make a private copy before running this method, as InitJson() does
- this method is called e.g. by _JsonFmt() _JsonFastFmt() global functions with a temporary JSON buffer content created from a set of parameters
- if you call Init*() methods in a row, ensure you call Clear in-between
- consider the faster InitArrayFromResults() from ORM/SQL JSON results
function InternalAdd(const aName: RawUtf8; aIndex: integer = -1): integer;
Low-level method called internally to reserve place for new values
- returns the index of the newly created item in Values[]/Names[] arrays
- you should not have to use it, unless you want to add some items directly within the Values[]/Names[] arrays, using e.g. InitFast(InitialCapacity) to initialize the document
- if aName='', append a dvArray item, otherwise append a dvObject field
- you can specify an optional aIndex value to Insert instead of Add
- warning: FPC optimizer is confused by Values[InternalAdd(name)] so you should call InternalAdd() in an explicit previous step
function IsArray: boolean;
Check if the Document is an array - i.e. Kind = dvArray
function IsCaseSensitive: boolean;
Check if names lookups are case sensitive in this object Document
function IsObject: boolean;
Check if the Document is an object - i.e. Kind = dvObject
function IsVoid: boolean;
Returns true if this is not a true TDocVariant, or Count equals 0
function Reduce(const aPropNames: array of RawUtf8; aCaseSensitive: boolean; aDoNotAddVoidProp: boolean = false): variant; overload;
Create a TDocVariant object, from a selection of properties of the objects of this document array, by property name
- always returns a TDocVariantData, even if no property name did match (in this case, it is dvUndefined)
function ReduceAsArray(const aPropName: RawUtf8; const OnReduce: TOnReducePerItem = nil): variant; overload;
Create a TDocVariant array, from the values of a single property of the objects of this document array, specified by name
- always returns a TDocVariantData, even if no property name did match (in this case, it is dvUndefined)
- you can optionally apply an additional filter to each reduced item
function ReduceAsArray(const aPropName: RawUtf8; const OnReduce: TOnReducePerValue): variant; overload;
Create a TDocVariant array, from the values of a single property of the objects of this document array, specified by name
- always returns a TDocVariantData, even if no property name did match (in this case, it is dvUndefined)
- this overloaded method accepts an additional filter to each reduced item
function ReduceAsVariantArray(const aPropName: RawUtf8; aDuplicates: TSearchDuplicate = sdNone): TVariantDynArray;
Return the variant values of a single property of the objects of this document array, specified by name
- returns nil if the document is not a dvArray
function ReduceFilter(const aExpression: RawUtf8; aLimit: integer = 0; aPathDelim: AnsiChar = #0): variant; overload;
Create a TDocVariant array, matching a filtering expression
- expressions are e.g. 'name=Synopse' or 'price<100'
function ReduceFilter(const aExpression: RawUtf8; const aValue: variant; aLimit: integer = 0; aPathDelim: AnsiChar = #0): variant; overload;
Create a TDocVariant array, matching a filtering expression
- e.g. ReduceFilter('name=','Synopse') or ReduceFilter('price<',MaxPrice)
function Rename(const aFromPropName, aToPropName: TRawUtf8DynArray): integer;
Rename some properties of a TDocVariant object
- returns the number of property names modified
function RetrieveValueOrRaiseException(aName: PUtf8Char; aNameLen: integer; aCaseSensitive: boolean; var Dest: variant; DestByRef: boolean): boolean; overload;
Find an item in this document, and returns its value
- raise an EDocVariant if not found and dvoReturnNullForUnknownProperty is not set in Options (in this case, it will return Null)
- create a copy of the variant by default, unless DestByRef is TRUE
function SearchItemByProp(const aPropName, aPropValue: RawUtf8; aPropValueCaseSensitive: boolean): integer; overload;
Search a property match in this document, handled as array or object
- {aPropName:aPropValue} will be searched within the stored array or object, and the corresponding item index will be returned, on match
- returns -1 if no match is found
- will call VariantEquals() for value comparison
function SearchItemByProp(const aPropNameFmt: RawUtf8; const aPropNameArgs: array of const; const aPropValue: RawUtf8; aPropValueCaseSensitive: boolean): integer; overload;
Search a property match in this document, handled as array or object
- {aPropName:aPropValue} will be searched within the stored array or object, and the corresponding item index will be returned, on match
- returns -1 if no match is found
- will call VariantEquals() for value comparison
function SearchItemByValue(const aValue: Variant; CaseInsensitive: boolean = false; StartIndex: PtrInt = 0): PtrInt;
Search a value in this document, handled as array
- aValue will be searched within the stored array and the corresponding item index will be returned, on match
- returns -1 if no match is found
- you could make several searches, using the StartIndex optional parameter
function SetValueByPath(const aPath: RawUtf8; const aValue: variant; aCreateIfNotExisting: boolean = false; aPathDelim: AnsiChar = '.'; aMergeExisting: boolean = false): PVariant;
Set a value, given its path
- path is defined as a dotted name-space, e.g. 'doc.glossary.title'
- aCreateIfNotExisting=true will force missing nested objects creation
- aMergeExisting=true will merge aValue object with any existing object
- returns nil if there is no item to be set at the supplied aPath
- returns the address of the found or created value in aValue
- you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'
function ToArrayOfConst: TTVarRecDynArray; overload;
Save an array document as an array of TVarRec, i.e. an array of const
- will expect the document to be a dvArray - otherwise, will raise a EDocVariant exception
- values will be passed by referenced as vtVariant to @VValue[ndx]
- would allow to write code as such:
Doc.InitArray(['one',2,3]); s := FormatUtf8('[%,%,%]',Doc.ToArrayOfConst,[],true); // here s='[one,2,3]') since % would be replaced by Args[] parameters s := FormatUtf8('[?,?,?]',[],Doc.ToArrayOfConst,true); // here s='["one",2,3]') since ? would be escaped by Params[] parameters
function ToCsv(const Separator: RawUtf8 = ','): RawUtf8;
Save a document as an CSV of UTF-8 encoded JSON
- will expect the document to be a dvArray - otherwise, will raise a EDocVariant exception
- will use VariantToUtf8() to populate the result array: as a consequence, any nested custom variant types (e.g. TDocVariant) will be stored as JSON
function ToJson(const Prefix, Suffix: RawUtf8; Format: TTextWriterJsonFormat): RawUtf8; overload;
Save a document as UTF-8 encoded JSON
function ToJson: RawUtf8; overload;
Save a document as UTF-8 encoded JSON
- will write either a JSON object or array, depending of the internal layout of this instance (i.e. Kind property value)
- will write 'null' if Kind is dvUndefined
- implemented as just a wrapper around DocVariantType.ToJson()
function ToNonExpandedJson: RawUtf8;
Save an array of objects as UTF-8 encoded non expanded layout JSON
- returned content would be a JSON object in mORMot's TOrmTableJson non expanded format, with reduced JSON size, i.e.
{"fieldCount":2,"values":["f1","f2","1v1",1v2,"2v1",2v2...],"rowCount":20}- will write '' if Kind is dvUndefined or dvObject
- will raise an exception if the array document is not an array of objects with identical field names
- can be unserialized using the InitArrayFromResults() method
function ToRawUtf8DynArray: TRawUtf8DynArray; overload;
Save a document as an array of UTF-8 encoded JSON
- will expect the document to be a dvArray - otherwise, will raise a EDocVariant exception
- will use VariantToUtf8() to populate the result array: as a consequence, any nested custom variant types (e.g. TDocVariant) will be stored as JSON
function ToTextPairs(const NameValueSep: RawUtf8 = '='; const ItemSep: RawUtf8 = #13#10; Escape: TTextWriterKind = twJsonEscape): RawUtf8;
Save a document as UTF-8 encoded Name=Value pairs
- will follow by default the .INI format, but you can specify your own expected layout
function ToUrlEncode(const UriRoot: RawUtf8): RawUtf8;
Save an object document as an URI-encoded list of parameters
- object field names should be plain ASCII-7 RFC compatible identifiers (0..9a..zA..Z_.~), otherwise their values are skipped
procedure AddByPath(const aSource: TDocVariantData; const aPaths: array of RawUtf8; aPathDelim: AnsiChar = '.');
Add one or several properties, specified by path, from another object
- path are defined as open array, e.g. ['doc','glossary','title'], but could also contained nested paths, e.g. ['doc.glossary', title'] or ['doc', 'glossary/title'] of aPathDelim is '/'
- matching values would be added as root values, with the path as name
- instance and supplied aSource should be a dvObject
procedure AddFrom(const aDocVariant: Variant);
Add one or several values from another document
- supplied document should be of the same kind than the current one, otherwise nothing is added
- for an object, dvoCheckForDuplicatedNames flag is used: use AddOrUpdateFrom() to force objects merging
procedure AddItems(const aValue: array of const);
Add one or several values to this document, handled as array
- if instance's Kind is dvObject, it will raise an EDocVariant exception
procedure AddNameValuesToObject(const NameValuePairs: array of const);
Add some properties to a TDocVariantData dvObject
- data is supplied two by two, as Name,Value pairs
- caller should ensure that Kind=dvObject, otherwise it won't do anything
- any existing Name would be duplicated - use Update() if you want to replace any existing value
procedure AddObject(const aNameValuePairs: array of const; const aName: RawUtf8 = '');
Add one object document to this document
- if the document is an array, keep aName=''
- if the document is an object, set the new object property as aName
- new object will keep the same options as this document
- slightly faster than AddItem(_Obj(...)) or AddValue(aName, _Obj(...))
procedure AddOrUpdateFrom(const aDocVariant: Variant; aOnlyAddMissing: boolean = false);
Merge (i.e. add or update) several values from another object
- current document should be an object
procedure AddOrUpdateNameValuesToObject(const NameValuePairs: array of const);
Deprecated method which redirects to Update()
procedure AddOrUpdateObject(const NewValues: variant; OnlyAddMissing: boolean = false; RecursiveUpdate: boolean = false);
Merge some TDocVariantData dvObject properties to a TDocVariantData dvObject
- data is supplied two by two, as Name,Value pairs
- caller should ensure that both variants have Kind=dvObject, otherwise it won't do anything
- any existing Name would be updated with the new Value, unless OnlyAddMissing is set to TRUE, in which case existing values would remain
procedure Clear;
To be called before any Init*() method call, when a previous Init*() has already be performed on the same instance, to avoid memory leaks
- for instance:
var Doc: TDocVariantData; // stack-allocated variable begin Doc.InitArray(['one',2,3.0]); // no need of any Doc.Clear here assert(Doc.Count=3); Doc.Clear; // to release memory before following InitObject() Doc.InitObject(['name','John','year',1972]); end;
- will check the VType, and call ClearFast private method
procedure FillZero;
Fill all Values[] with #0, then delete all values
- could be used to specifically remove sensitive information from memory
procedure Init(const aOptions: TDocVariantOptions; aKind: TDocVariantKind); overload;
Initialize a TDocVariantData to store a content of some known type
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure Init(aModel: TDocVariantModel; aKind: TDocVariantKind = dvUndefined); overload;
Initialize a TDocVariantData to store some document-based content
- use the options corresponding to the supplied TDocVariantModel
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure Init(const aOptions: TDocVariantOptions = []); overload;
Initialize a TDocVariantData to store some document-based content
- can be used with a stack-allocated TDocVariantData variable:
var Doc: TDocVariantData; // stack-allocated variable begin Doc.Init; Doc.AddValue('name','John'); assert(Doc.Value['name']='John'); assert(variant(Doc).name='John'); end;
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitArray(const aItems: array of const; aOptions: TDocVariantOptions = []); overload;
Initialize a variant instance to store some document-based array content
- array will be initialized with data supplied as parameters, e.g.
var Doc: TDocVariantData; // stack-allocated variable begin Doc.InitArray(['one',2,3.0]); assert(Doc.Count=3); end;
which is the same as:
var Doc: TDocVariantData; i: integer; begin Doc.Init; Doc.AddItem('one'); Doc.AddItem(2); Doc.AddItem(3.0); assert(Doc.Count=3); for i := 0 to Doc.Count-1 do writeln(Doc.Value[i]); end;
- this method is called e.g. by _Arr() and _ArrFast() global functions
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitArray(const aItems: array of const; aModel: TDocVariantModel); overload;
Initialize a variant instance to store some document-based array content
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitArrayFrom(const aSource: TDocVariantData; aOptions: TDocVariantOptions; aOffset: integer = 0; aLimit: integer = 0); overload;
Create a TDocVariant array, from a sub-range of this document array
- returned variant instance is a dvArray containing only the specified rows
new.InitArrayFrom(src) returns a copy of src array new.InitArrayFrom(src, 10) returns items 10..Count-1 of src new.InitArrayFrom(src, 0, 10) returns first 0..9 items of src new.InitArrayFrom(src, 10, 20) returns items 10..29 - truncated if Count<30 new.InitArrayFrom(src, -10) returns last Count-10..Count-1 items of src
procedure InitArrayFrom(const aItems: TInt64DynArray; aOptions: TDocVariantOptions; aCount: integer = -1); overload;
Initialize a variant instance to store some 64-bit integer array content
procedure InitArrayFrom(var aItems; ArrayInfo: PRttiInfo; aOptions: TDocVariantOptions; ItemsCount: PInteger = nil); overload;
Initialize a variant instance to store some dynamic array content
procedure InitArrayFrom(const aItems: TDoubleDynArray; aOptions: TDocVariantOptions; aCount: integer = -1); overload;
Initialize a variant instance to store some double array content
procedure InitArrayFrom(const aItems: TDynArray; aOptions: TDocVariantOptions = JSON_FAST_FLOAT); overload;
Initialize a variant instance to store some TDynArray content
procedure InitArrayFrom(const aItems: TRawUtf8DynArray; aOptions: TDocVariantOptions; aCount: integer = -1); overload;
Initialize a variant instance to store some RawUtf8 array content
procedure InitArrayFrom(const aItems: TIntegerDynArray; aOptions: TDocVariantOptions; aCount: integer = -1); overload;
Initialize a variant instance to store some 32-bit integer array content
procedure InitArrayFromCsv(const aCsv: RawUtf8; aOptions: TDocVariantOptions; aSeparator: AnsiChar = #0; aTrimItems: boolean = false; aAddVoidItems: boolean = false; aQuote: AnsiChar = #0);
Initialize a variant instance from some 'a,b,c' CSV one-line content
- is by default separator tolerant, i.e. will detect ',' ';' or #9 in text
procedure InitArrayFromCsvFile(const aCsv: RawUtf8; aOptions: TDocVariantOptions; aSeparator: AnsiChar = #0; aQuote: AnsiChar = #0);
Initialize a variant instance from a CSV file content with header
- stored objects names will be retrieved from the first CSV line
- is by default separator tolerant, i.e. will detect ',' ';' or #9 in text
procedure InitArrayFromObjArray(const ObjArray; aOptions: TDocVariantOptions; aWriterOptions: TTextWriterWriteObjectOptions = [woDontStoreDefault]; aCount: integer = -1);
Initialize a variant instance to store a T*ObjArray content
- will call internally ObjectToVariant() to make the conversion
procedure InitArrayFromObjectNames(const aObject: variant; aOptions: TDocVariantOptions = []; aItemsCopiedByReference: boolean = true);
Initialize a variant array instance from an object Names[]
procedure InitArrayFromObjectValues(const aObject: variant; aOptions: TDocVariantOptions = []; aItemsCopiedByReference: boolean = true);
Initialize a variant array instance from an object Values[]
procedure InitArrayFromVariants(const aItems: TVariantDynArray; aOptions: TDocVariantOptions = []; aItemsCopiedByReference: boolean = true; aCount: integer = -1);
Initialize a variant instance to store some document-based array content
- array will be initialized with data supplied as variant dynamic array
- if Items is [], the variant will be set as null
- will be almost immediate, since TVariantDynArray is reference-counted, unless ItemsCopiedByReference is set to FALSE
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitClone(const CloneFrom: TDocVariantData);
Clone a document-based variant with the very same options but no data
- the same options will be used, without the dvArray/dvObject flags
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitCopy(const SourceDocVariant: variant; aOptions: TDocVariantOptions);
Ensure a document-based variant instance will have one unique options set
- this will create a copy of the supplied TDocVariant instance, forcing all nested events to have the same set of Options
- you can use this function to ensure that all internal properties of this variant will be copied e.g. per-reference (if you set JSON_[mDefault]) or per-value (if you set JSON_[mDefault]) whatever options the nested objects or arrays were created with
- will raise an EDocVariant if the supplied variant is not a TDocVariant
- you may rather use _Unique() or _UniqueFast() wrappers if you want to ensure that a TDocVariant instance is unique
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitFast(InitialCapacity: integer; aKind: TDocVariantKind); overload;
Initialize a TDocVariantData to store per-reference document-based content
- this overloaded method allows to specify an estimation of how many properties or items this aKind document would contain
procedure InitFast(aKind: TDocVariantKind = dvUndefined); overload;
Initialize a TDocVariantData to store per-reference document-based content
- same as Doc.Init(JSON_FAST);
- can be used with a stack-allocated TDocVariantData variable:
var Doc: TDocVariantData; // stack-allocated variable begin Doc.InitFast; Doc.AddValue('name','John'); assert(Doc.Value['name']='John'); assert(variant(Doc).name='John'); end;
- see also TDocVariant.NewFast() if you want to initialize several TDocVariantData variable instances at once
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitFromPairs(aPairs: PUtf8Char; aOptions: TDocVariantOptions; NameValueSep: AnsiChar = '='; ItemSep: AnsiChar = #10; DoTrim: boolean = true); overload;
Initialize a variant instance to store some document-based object content from a supplied name=value list of UTF-8 encoded text (e.g. .ini file)
- previous name InitCsv() was very misleading, because it was no CSV content
- the supplied content may have been generated by ToTextPairs() method
- if ItemSep=#10, then any kind of line feed (CRLF or LF) will be handled
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitFromPairs(const aPairs: RawUtf8; aOptions: TDocVariantOptions; NameValueSep: AnsiChar = '='; ItemSep: AnsiChar = #10; DoTrim: boolean = true); overload;
Initialize a variant instance to store some document-based object content from a supplied name=value list of UTF-8 encoded text (e.g. .ini file)
- previous name InitCsv() was very misleading, because it was no CSV content
- the supplied content may have been generated by ToTextPairs() method
- if ItemSep = #10, then any kind of line feed (CRLF or LF) will be handled
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitObject(const NameValuePairs: array of const; Model: TDocVariantModel); overload;
Initialize a TDocVariantData to store document-based object content
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitObject(const NameValuePairs: array of const; aOptions: TDocVariantOptions = []); overload;
Initialize a TDocVariantData to store document-based object content
- object will be initialized with data supplied two by two, as Name,Value pairs, e.g.
var Doc: TDocVariantData; // stack-allocated variable begin Doc.InitObject(['name','John','year',1972]);
which is the same as:
var Doc: TDocVariantData; begin Doc.Init; Doc.AddValue('name','John'); Doc.AddValue('year',1972);
- this method is called e.g. by _Obj() and _ObjFast() global functions
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitObjectFromPath(const aPath: RawUtf8; const aValue: variant; aOptions: TDocVariantOptions = []; aPathDelim: AnsiChar = '.');
Initialize a variant instance to store a document-based object with a single property
- the supplied path could be 'Main.Second.Third', to create nested objects, e.g. {"Main":{"Second":{"Third":value}}}
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure InitObjectFromVariants(const aNames: TRawUtf8DynArray; const aValues: TVariantDynArray; aOptions: TDocVariantOptions = []);
Initialize a variant instance to store some document-based object content
- object will be initialized with names and values supplied as dynamic arrays
- if aNames and aValues are [] or do have matching sizes, the variant will be set as null
- will be almost immediate, since Names and Values are reference-counted
- if you call Init*() methods in a row, ensure you call Clear in-between
procedure Reduce(const aPropNames: array of RawUtf8; aCaseSensitive: boolean; var result: TDocVariantData; aDoNotAddVoidProp: boolean = false); overload;
Create a TDocVariant object, from a selection of properties of the objects of this document array, by property name
- if the document is a dvObject, to reduction will be applied to all its properties
- if the document is a dvArray, the reduction will be applied to each stored item, if it is a document
procedure ReduceAsArray(const aPropName: RawUtf8; var result: TDocVariantData; const OnReduce: TOnReducePerItem = nil); overload;
Create a TDocVariant array, from the values of a single property of the objects of this document array, specified by name
- you can optionally apply an additional filter to each reduced item
procedure ReduceAsArray(const aPropName: RawUtf8; var result: TDocVariantData; const OnReduce: TOnReducePerValue); overload;
Create a TDocVariant array, from the values of a single property of the objects of this document array, specified by name
- this overloaded method accepts an additional filter to each reduced item
procedure ReduceFilter(const aKey: RawUtf8; const aValue: variant; aMatch: TCompareOperator; aCompare: TVariantCompare; aLimit: integer; aPathDelim: AnsiChar; var result: TDocVariantData); overload;
Create a TDocVariant array, matching a filtering set of raw parameters
procedure ReduceFilter(const aExpression: RawUtf8; var result: TDocVariantData; aLimit: integer = 0; aCompare: TVariantCompare = nil; aPathDelim: AnsiChar = #0); overload;
Create a TDocVariant array, matching a filtering expression
- expressions are e.g. 'name=Synopse' or 'price<100'
procedure ReduceFilter(const aExpression: RawUtf8; const aValue: variant; var result: TDocVariantData; aCompare: TVariantCompare = nil; aLimit: integer = 0; aPathDelim: AnsiChar = #0); overload;
Create a TDocVariant array, matching a filtering expression
- e.g. ReduceFilter('name=','Synopse') or ReduceFilter('price<',MaxPrice)
procedure Reset;
Delete all internal stored values
- like Clear + Init() with the same options
- will reset Kind to dvUndefined
procedure RetrieveNameOrRaiseException(Index: integer; var Dest: RawUtf8);
Retrieve an item in this document from its index, and returns its Name
- raise an EDocVariant if the supplied Index is not in the 0..Count-1 range and dvoReturnNullForUnknownProperty is set in Options
procedure RetrieveValueOrRaiseException(Index: integer; var Dest: variant; DestByRef: boolean); overload;
Retrieve an item in this document from its index, and returns its value
- raise an EDocVariant if the supplied Index is not in the 0..Count-1 range and dvoReturnNullForUnknownProperty is set in Options
- create a copy of the variant by default, unless DestByRef is TRUE
procedure Reverse;
Inverse the order of Names and Values of this document
- could be applied after a content sort if needed
procedure SaveToJsonFile(const FileName: TFileName);
Save a document as UTF-8 encoded JSON file
- you may then use InitJsonFromFile() to load and parse this file
procedure SetCount(aCount: integer);
Low-level method to force a number of items
- could be used to fast add items to the internal Values[]/Names[] arrays
- just set protected VCount field, do not resize the arrays: caller should ensure that Capacity is big enough and to call Void if aCount=0
procedure SetValueOrRaiseException(Index: integer; const NewValue: variant);
Set an item in this document from its index
- raise an EDocVariant if the supplied Index is not in 0..Count-1 range
procedure SortArrayByField(const aItemPropName: RawUtf8; aValueCompare: TVariantCompare = nil; aValueCompareReverse: boolean = false; aNameSortedCompare: TUtf8Compare = nil);
Sort the document array values by a field of some stored objet values
- do nothing if the document is not a dvArray, or if the items are no dvObject
- aValueCompare will be called with the aItemPropName values, not row
- will sort by UTF-8 text (VariantCompare) if no custom aValueCompare is supplied
- this method is faster than SortByValue/SortByRow
procedure SortArrayByFields(const aItemPropNames: array of RawUtf8; aValueCompare: TVariantCompare = nil; const aValueCompareField: TVariantCompareField = nil; aValueCompareReverse: boolean = false; aNameSortedCompare: TUtf8Compare = nil);
Sort the document array values by field(s) of some stored objet values
- allow up to 4 fields (aItemPropNames[0]..aItemPropNames[3])
- do nothing if the document is not a dvArray, or if the items are no dvObject
- will sort by UTF-8 text (VariantCompare) if no aValueCompareField is supplied
procedure SortByName(SortCompare: TUtf8Compare = nil; SortCompareReversed: boolean = false; SortNested: boolean = false);
Sort the document object values by name
- do nothing if the document is not a dvObject
- will follow case-insensitive order (@StrIComp) by default, but you can specify @StrComp as comparer function for case-sensitive ordering
- once sorted, you can use GetVarData(..,Compare) or GetAs*(..,Compare) methods for much faster O(log(n)) binary search
procedure SortByRow(const SortComparer: TVariantComparer; SortComparerReversed: boolean = false);
Sort the document object values by value using a comparison method
- work for both dvObject and dvArray documents
- you should supply a TVariantComparer callback method
procedure SortByValue(SortCompare: TVariantCompare = nil; SortCompareReversed: boolean = false);
Sort the document object values by value using a comparison function
- work for both dvObject and dvArray documents
- will sort by UTF-8 text (VariantCompare) if no custom aCompare is supplied
procedure ToArrayOfConst(out Result: TTVarRecDynArray); overload;
Save an array document as an array of TVarRec, i.e. an array of const
- will expect the document to be a dvArray - otherwise, will raise a EDocVariant exception
- values will be passed by referenced as vtVariant to @VValue[ndx]
- would allow to write code as such:
Doc.InitArray(['one',2,3]); Doc.ToArrayOfConst(vr); s := FormatUtf8('[%,%,%]',vr,[],true); // here s='[one,2,3]') since % would be replaced by Args[] parameters s := FormatUtf8('[?,?,?]',[],vr,true); // here s='["one",2,3]') since ? would be escaped by Params[] parameters
procedure ToRawUtf8DynArray(out Result: TRawUtf8DynArray); overload;
Save a document as an array of UTF-8 encoded JSON
- will expect the document to be a dvArray - otherwise, will raise a EDocVariant exception
- will use VariantToUtf8() to populate the result array: as a consequence, any nested custom variant types (e.g. TDocVariant) will be stored as JSON
procedure ToTextPairsVar(out result: RawUtf8; const NameValueSep: RawUtf8 = '='; const ItemSep: RawUtf8 = #13#10; Escape: TTextWriterKind = twJsonEscape);
Save a document as UTF-8 encoded Name=Value pairs
- will follow by default the .INI format, but you can specify your own expected layout
procedure Update(const NameValuePairs: array of const);
Merge some properties to a TDocVariantData dvObject
- data is supplied two by two, as Name,Value pairs
- caller should ensure that Kind=dvObject, otherwise it won't do anything
- any existing Name would be updated with the new Value
procedure Void;
Keep the current Options and Kind, but reset all data and VCount to 0
property A[const aName: RawUtf8]: PDocVariantData read GetArrayExistingByName;
Direct access to a dvObject existing dvArray property from its name
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- A['prop'] would return a fake void TDocVariant if the property is not existing or not a dvArray, just like GetAsDocVariantSafe()
- use A_['prop'] to force adding any missing property
property A_[const aName: RawUtf8]: PDocVariantData read GetArrayOrAddByName;
Direct access or add a dvObject's dvArray property from its name
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- A_['prop'] would add a new property if there is none existing, or overwrite an existing property which is not a dvArray
- the new property array would inherit from the Options of this instance
property B[const aName: RawUtf8]: boolean read GetBooleanByName write SetBooleanByName;
Direct access to a dvObject boolean stored property value from its name
- slightly faster than the variant-based Value[] default property
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- use GetAsBoolean if you want to check the availability of the field
- B['prop'] := true would add a new property, or overwrite an existing
property Capacity: integer read GetCapacity write SetCapacity;
The current capacity of this document
- allow direct access to VValue[] length
property Count: integer read VCount;
Number of items stored in this document
- always 0 for Kind=dvUndefined
- the number of name/value pairs for Kind=dvObject (may be 0 if void)
- the number of items for Kind=dvArray (may be 0 if void)
property D[const aName: RawUtf8]: Double read GetDoubleByName write SetDoubleByName;
Direct access to a dvObject floating-point stored property value from its name
- slightly faster than the variant-based Value[] default property
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- use GetAsDouble if you want to check the availability of the field
- D['prop'] := 1.23 would add a new property, or overwrite an existing
property I[const aName: RawUtf8]: Int64 read GetInt64ByName write SetInt64ByName;
Direct access to a dvObject integer stored property value from its name
- slightly faster than the variant-based Value[] default property
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- use GetAsInt/GetAsInt64 if you want to check the availability of the field
- I['prop'] := 123 would add a new property, or overwrite an existing
property Kind: TDocVariantKind read GetKind;
Returns the document internal layout
- just after initialization, it will return dvUndefined
- most of the time, you will add named values with AddValue() or by setting the variant properties: it will return dvObject
- but is you use AddItem(), values will have no associated names: the document will be a dvArray
- is computed from the dvoArray or dvoObject flags presence in Options
property Names: TRawUtf8DynArray read VName;
Direct acces to the low-level internal array of names
- is void (nil) if Kind is not dvObject
- note that length(Names)=Capacity and not Count, so copy(Names, 0, Count) or use FieldNames iterator or GetNames if you want the exact count
- transtyping a variant and direct access to TDocVariantData is the fastest way of accessing all properties of a given dvObject:
with _Safe(aVariantObject)^ do for i := 0 to Count-1 do writeln(Names[i],'=',Values[i]);
property O[const aName: RawUtf8]: PDocVariantData read GetObjectExistingByName;
Direct access to a dvObject existing dvObject property from its name
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- O['prop'] would return a fake void TDocVariant if the property is not existing or not a dvObject, just like GetAsDocVariantSafe()
- use O_['prop'] to force adding any missing property
property Options: TDocVariantOptions read VOptions write SetOptions;
How this document will behave
- those options are set when creating the instance
- dvoArray and dvoObject are not options, but define the document Kind, so those items are ignored when assigned to this property
property O_[const aName: RawUtf8]: PDocVariantData read GetObjectOrAddByName;
Direct access or add a dvObject's dvObject property from its name
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- O_['prop'] would add a new property if there is none existing, or overwrite an existing property which is not a dvObject
- the new property object would inherit from the Options of this instance
property P[const aNameOrPath: RawUtf8]: Variant read GetVariantByPath;
Direct access to a dvObject value stored property value from its path name
- default Value[] will check only names in the current object properties, whereas this property will recognize e.g. 'parent.child' nested objects
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
property S[const aName: RawUtf8]: string read GetStringByName write SetStringByName;
Direct string access to a dvObject UTF-8 stored property value from its name
- just a wrapper around U[] property, to avoid a compilation warning when using plain string variables (internally, RawUtf8 will be used for storage)
- slightly faster than the variant-based Value[] default property
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- use GetAsRawUtf8() if you want to check the availability of the field
- S['prop'] := 'value' would add a new property, or overwrite an existing
property U[const aName: RawUtf8]: RawUtf8 read GetRawUtf8ByName write SetRawUtf8ByName;
Direct access to a dvObject UTF-8 stored property value from its name
- slightly faster than the variant-based Value[] default property
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- use GetAsRawUtf8() if you want to check the availability of the field
- U['prop'] := 'value' would add a new property, or overwrite an existing
property Value[const aNameOrIndex: Variant]: Variant read GetValueOrItem write SetValueOrItem;
Find an item in this document, and returns its value
- raise an EDocVariant if aNameOrIndex is neither an integer nor a string
- raise an EDocVariant if Kind is dvArray and aNameOrIndex is a string or if Kind is dvObject and aNameOrIndex is an integer
- raise an EDocVariant if Kind is dvObject and if aNameOrIndex is a string, which is not found within the object property names and dvoReturnNullForUnknownProperty is set in Options
- raise an EDocVariant if Kind is dvArray and if aNameOrIndex is a integer, which is not within 0..Count-1 and dvoReturnNullForUnknownProperty is set in Options
- so you can use directly:
// for an array document: aVariant := TDocVariant.NewArray(['one',2,3.0]); for i := 0 to TDocVariantData(aVariant).Count-1 do aValue := TDocVariantData(aVariant).Value[i]; // for an object document: aVariant := TDocVariant.NewObject(['name','John','year',1972]); assert(aVariant.Name=TDocVariantData(aVariant)['name']); assert(aVariant.year=TDocVariantData(aVariant)['year']);
- due to the internal implementation of variant execution (somewhat slow _DispInvoke() function), it is a bit faster to execute:
aValue := TDocVariantData(aVariant).Value['name'];
or
aValue := _Safe(aVariant).Value['name'];
instead of
aValue := aVariant.name;
but of course, if want to want to access the content by index (typically for a dvArray), using Values[] - and Names[] - properties is much faster than this variant-indexed pseudo-property:
with TDocVariantData(aVariant) do for i := 0 to Count-1 do Writeln(Values[i]);
is faster than:
with TDocVariantData(aVariant) do for i := 0 to Count-1 do Writeln(Value[i]);
which is faster than:
for i := 0 to aVariant.Count-1 do Writeln(aVariant._(i));
- this property will return the value as varByRef (just like with variant late binding of any TDocVariant instance), so you can write:
var Doc: TDocVariantData; // stack-allocated variable begin Doc.InitJson('{arr:[1,2]}'); assert(Doc.Count=2); Doc.Value['arr'].Add(3); // works since Doc.Value['arr'] is varByRef writeln(Doc.ToJson); // will write '{"arr":[1,2,3]}' end;
- if you want to access a property as a copy, i.e. to assign it to a variant variable which will stay alive after this TDocVariant instance is release, you should not use Value[] but rather GetValueOrRaiseException or GetValueOrNull/GetValueOrEmpty
- see U[] I[] B[] D[] O[] O_[] A[] A_[] _[] properties for direct access of strong typed values, or P[] to retrieve a variant from its path
property Values: TVariantDynArray read VValue;
Direct acces to the low-level internal array of values
- note that length(Values)=Capacity and not Count, so copy(Values, 0, Count) or use FieldValues iterator if you want the exact count
- transtyping a variant and direct access to TDocVariantData is the fastest way of accessing all properties of a given dvObject:
with _Safe(aVariantObject)^ do for i := 0 to Count-1 do writeln(Names[i],'=',Values[i]);
- or to access a dvArray items (e.g. a MongoDB collection):
with TDocVariantData(aVariantArray) do for i := 0 to Count-1 do writeln(Values[i]);
property VarType: word read VType;
Return the custom variant type identifier, i.e. DocVariantType.VarType
property _[aIndex: integer]: PDocVariantData read GetAsDocVariantByIndex;
Direct access to a dvArray's TDocVariant property from its index
- simple values may directly use Values[] dynamic array, but to access a TDocVariantData members, this property is safer
- follows dvoReturnNullForUnknownProperty option to raise an exception
- _[ndx] would return a fake void TDocVariant if aIndex is out of range, if the property is not existing or not a TDocVariantData (just like GetAsDocVariantSafe)
IDocAny = interface(ISerializable)
Abstract parent with common methods to IDocList/IDocDict wrappers
function AsDict: IDocDict;
Returns itself as a IDocDic, or nil if is a IDocList
function AsList: IDocList;
Returns itself as a IDocList, or nil if is a IDocDict
function AsVariant: variant;
Returns the associated TDocVariant instance
function Kind: TDocVariantKind;
Equals dvArray for IDocList, dvObject for IDocDict
function Len: integer;
How many items or name/value pairs are stored in this instance
function Model: TDocVariantModel;
The known model of the internal TDocVariantData storage
function Value: PDocVariantData;
Low-level access to the internal TDocVariantData storage
- warning: is a weak reference pointer to the main IDocList/IDocDict, so you need to copy it to use it outside of this instance
procedure Clear;
Remove all elements from the list/dictionary
EDocList = class(EDocVariant)
Exception raised by IDocList
EDocDict = class(EDocVariant)
Exception raised by IDocDict
IDocList = interface(IDocAny)
A List, used to store multiple values
- implemented via an internal TDocVariantData dvArray
- follows most Python Lists naming and conventions
function Append(const value: RawUtf8): integer; overload;
Adds an UTF-8 text element at the end of the list
function Append(const value: variant): integer; overload;
Adds an element at the end of the list
function AppendDoc(const value: IDocAny): integer;
Adds an IDocList/IDocDict element at the end of the list
function Compare(const another: IDocList; caseinsensitive: boolean = false): integer;
Compare this IDocList value with another instance
- each element of the list will be compared, in their expected order
function Copy(start: integer = 0; stop: integer = 0): IDocList;
Return a of a (sub-range) copy of this IDocList
- consider Range() if you want just to loop over some sub-range, and do not need to allocate a new IDocList instance
- returns a new IDocList instance as Python list[start:stop] range, stop position being *excluded* to the result:
list.Copy returns a copy of the whole list list.Copy(10) returns elements #10..#Count-1, i.e. list[10:] list.Copy(-2) returns last #Count-2..#Count-1 items, i.e. list[-2:] list.Copy(1, 9) returns elements #1..#8, i.e. list[1..9] list.Copy(1, -2) returns elements #1..#Count-3, i.e. list[1:-2]
function Count(const value: RawUtf8): integer; overload;
Counts the number of elements with the specified value
function Count(const value: variant): integer; overload;
Counts the number of elements with the specified value
function Del(position: integer): boolean;
Removes the element at the specified position, not returning it
function Exists(const value: RawUtf8; caseinsensitive: boolean = false): boolean; overload;
Check if a specified text value is present in the list
function Exists(const value: variant): boolean; overload;
Check if a specified value is present in the list
function Filter(const expression: RawUtf8; pathdelim: AnsiChar = '.'): IDocList; overload;
Search matching expression over IDocDict kind of elements in this list
- expressions are e.g. 'name=Synopse' or 'info.price<100'
function Filter(const expression: RawUtf8; const value: variant; limit: integer = 0; pathdelim: AnsiChar = '.'): IDocList; overload;
Search matching expression over IDocDict kind of elements in this list
- use e.g. Filter('name=', 'Synopse') or Filter('info.price<', MaxPrice)
function Filter(const key: RawUtf8; const value: variant; limit: integer; match: TCompareOperator; compare: TVariantCompare; pathdelim: AnsiChar = '.'): IDocList; overload;
Search matching key/value over IDocDict kind of elements in this list
- raw search for compare(object.key,value)=match
- default compare=nil will use VariantCompare
function First(const expression: RawUtf8; const value: variant): variant; overload;
Search the first matching expression over IDocDict kind of elements
function First(const expression: RawUtf8): variant; overload;
Search the first matching expression over IDocDict kind of elements
function GetB(position: integer): boolean;
Methods used as getter/setter for properties
function Index(const value: variant): integer; overload;
Returns the position at the first occurrence of the specified value
function Index(const value: RawUtf8; caseinsensitive: boolean = false): integer; overload;
Returns the position at the first occurrence of the specified text value
function Insert(position: integer; const value: RawUtf8): integer; overload;
Inserts the specified value at the specified position
function Insert(position: integer; const value: variant): integer; overload;
Inserts the specified value at the specified position
function ObjectsDictDynArray: IDocDictDynArray;
Returns all IDocDict kind of elements of this IDocList
- the list should consist e.g. of a JSON array of JSON objects
- will just ignore any element of the IDocList which is not a IDocDict
function Pop(position: integer = -1): variant;
Removes the element at the specified position, and returns it
- raise an EDocList on invalid supplied position
function PopItem(out value: IDocDict; position: integer = -1): boolean; overload;
Removes the last inserted IDocDict, with no out-of-range error raised
- you may change the extraction position (negatives from Len)
- returns false if there is no value at this position, or it is no IDocDict
function PopItem(out value: variant; position: integer = -1): boolean; overload;
Removes the last inserted element into a value-owned IDocDict
- returns false if there is no value at this position (raise no EDocList)
- you may change the extraction position (negatives from Len)
function Reduce(const keys: array of RawUtf8): IDocList;
Extract a list of IDocDict elements which contains only specified keys
- could be used to filter a list of objects into a smaller dataset
function Remove(const value: variant): integer; overload;
Removes the first occurrence of the element with the specified value
function Remove(const value: RawUtf8; caseinsensitive: boolean = false): integer; overload;
Removes the first occurrence of the element with the specified value
function ValueAt(position: integer): PVariant;
Low-level direct access to a stored element in TDocVariantData.Value[]
procedure Extend(const value: IDocList); overload;
Add the elements of a list, to the end of the current list
procedure Extend(const value: array of const); overload;
Add the supplied elements, to the end of the current list
procedure Reverse;
Reverses the sorting order of the elements
procedure Sort(reverse: boolean = false; compare: TVariantCompare = nil);
Sorts the list ascending by default
procedure SortByKeyValue(const keys: array of RawUtf8; reverse: boolean = false; valuecompare: TVariantCompare = nil); overload;
Sorts the IDocDict objects in the list by several key names
procedure SortByKeyValue(const key: RawUtf8; reverse: boolean = false; valuecompare: TVariantCompare = nil); overload;
Sorts the IDocDict objects in the list by a given key name
property A[position: integer]: IDocList read GetL write SetL;
Access one element in the list, as IDocList/IDocArray
- property alias, for compatibility with existing code
- warning: weak reference to the main list, unless you explicitly Copy it
property B[position: integer]: boolean read GetB write SetB;
Access one element in the list, as boolean
property C[position: integer]: currency read GetC write SetC;
Access one element in the list, as fixed precision Currency
property D[position: integer]: IDocDict read GetD write SetD;
Access one element in the list, as IDocDict (Dictionary)
- warning: weak reference to the main list, unless you explicitly Copy it
property F[position: integer]: double read GetF write SetF;
Access one element in the list, as floating-point Double
property I[position: integer]: Int64 read GetI write SetI;
Access one element in the list, as Integer
property Item[position: integer]: variant read GetItem write SetItem;
Access one element in the list, as variant
- this is the default property of this instance so list[n] gives direct access to the element at index 0 <= n < len -1 in the IDocList
- negative positions are retrieved from the end, e.g. list[-1] maps the last element of the list
- raise an EDocList exception on out-of-range position
- U[] S[] I[] F[] C[] B[] L[] D[] are faster and safer if you expect to retrieve a specific value type
property L[position: integer]: IDocList read GetL write SetL;
Access one element in the list, as IDocList (List)
- warning: weak reference to the main list, unless you explicitly Copy it
property O[position: integer]: IDocDict read GetD write SetD;
Access one element in the list, as IDocDict/IDocObject
- property alias, for compatibility with existing code
- warning: weak reference to the main list, unless you explicitly Copy it
property S[position: integer]: string read GetS write SetS;
Access one element in the list, as RTL String text
property U[position: integer]: RawUtf8 read GetU write SetU;
Access one element in the list, as UTF-8 text
IDocDict = interface(IDocAny)
A Dictionary, used to store key:value pairs
- implemented via an internal TDocVariantData dvObject
- follows most Python Dictionaries naming and conventions
- keys are by default searched on the ground object, but you can set PathDelim e.g. to '.' to enable sub-object location (and insertion)
function Compare(const another: IDocDict; const keys: array of RawUtf8; caseinsensitive: boolean = false): integer; overload;
Compare the specified keys of this IDocDict value with another instance
function Compare(const another: IDocDict; caseinsensitive: boolean = false): integer; overload;
Compare this IDocDict value with another instance
- each key/value pair will be compared, in their expected order
function Copy: IDocDict;
Returns a copy of the specified dictionary
function Del(const key: RawUtf8): boolean;
Removes the element at the specified key, not returning it
function Exists(const key: RawUtf8): boolean;
Check if the specified key exists in the dictionary
function Get(const key: RawUtf8; var value: string): boolean; overload;
Access one element in the dictionary, as RTL string text
- if the key does not exist, returns false
function Get(const key: RawUtf8; var value: boolean): boolean; overload;
Access one element in the dictionary, as boolean
- if the key does not exist or is not an integer, returns false
function Get(const key: RawUtf8; var value: integer): boolean; overload;
Access one element in the dictionary, as 32-bit integer
- if the key does not exist or is not an integer, returns false
function Get(const key: RawUtf8): variant; overload;
Access one element in the dictionary, as variant
- if the key does not exist, returns varEmpty and raise no exception
function Get(const key: RawUtf8; var value: variant): boolean; overload;
Access one element in the dictionary, as variant
- if the key does not exist, returns false
function Get(const key: RawUtf8; var value: RawUtf8): boolean; overload;
Access one element in the dictionary, as UTF-8 text
- if the key does not exist, returns false
function Get(const key: RawUtf8; var value: IDocList): boolean; overload;
Access one element in the dictionary, as by-reference IDocList
- if the key does not exist or is not a IDocList, returns false
function Get(const key: RawUtf8; var value: IDocDict): boolean; overload;
Access one element in the dictionary, as a by-reference IDocDict
- if the key does not exist or is not a IDocDict, returns false
function Get(const key: RawUtf8; var value: PDocVariantData): boolean; overload;
Access one element in the dictionary, as by-reference TDocVariantData
- if the key does not exist or is not a IDocList, returns false
function Get(const key: RawUtf8; var value: Int64): boolean; overload;
Access one element in the dictionary, as 64-bit integer
- if the key does not exist or is not an integer, returns false
function Get(const key: RawUtf8; var value: double): boolean; overload;
Access one element in the dictionary, as floating-point double
- if the key does not exist or can not be converted, returns false
function Get(const key: RawUtf8; var value: currency): boolean; overload;
Access one element in the dictionary, fixed precision currency
- if the key does not exist or can not be converted, returns false
function GetB(const key: RawUtf8): boolean;
Methods used as getter/setter for properties
function GetDef(const key: RawUtf8; const default: RawUtf8): variant; overload;
Access one element in the dictionary, as variant
- if the key does not exist, returns the supplied default value
function GetDef(const key: RawUtf8; const default: variant): variant; overload;
Access one element in the dictionary, as variant
- if the key does not exist, returns the supplied default value
function Pop(const key: RawUtf8): variant; overload;
Removes the specified element from the dictionary
- if the key does not exist, raise a EDocDict exception
function Pop(const key: RawUtf8; const default: variant): variant; overload;
Removes the specified element from the dictionary
- if the key does not exist, returns the supplied default value
function PopItem(out key: RawUtf8; out value: variant; position: integer = -1): boolean;
Removes the last inserted key-value pair into the dictionary
- returns false if the dictionary is empty
- you may change the extraction position (negatives from Len)
function Reduce(const keys: array of RawUtf8): IDocDict;
Extract into a new IDocDict which contains only specified keys
- could be used to filter unneeded fields in an object
function SetDefault(const key: RawUtf8; const default: variant): variant; overload;
Returns the value of the specified key, or insert the specified value
function SetDefault(const key: RawUtf8): variant; overload;
Returns the value of the specified key, or insert null for this key
function ValueAt(const key: RawUtf8): PVariant;
Low-level direct access to a stored element in TDocVariantData.Value[]
procedure Sort(reverse: boolean = false; keycompare: TUtf8Compare = nil; nestedDict: boolean = false);
Sorts the dictionary content by their key names
- follow dvoNameCaseSensitive option by default, or supplied keycompare
- can optionnaly sort the nested dictionaries of the dictionary
- once sorted, key lookup will use O(log(n)) - faster than default O(n)
procedure Update(const source: IDocDict; addonlymissing: boolean = false); overload;
Updates (or inserts) the specified key/value pairs of another IDocDict
procedure Update(const key: RawUtf8; const value: variant); overload;
Updates (or inserts) the specified key/value pair
procedure Update(const keyvalues: array of const); overload;
Updates (or inserts) the specified key/value pairs
property A[const key: RawUtf8]: IDocList read GetL write SetL;
Access one element in the dictionary from its key, as IDocList/IDocArray
- property alias, for compatibility with existing code
property B[const key: RawUtf8]: boolean read GetB write SetB;
Access one element in the dictionary from its key, as boolean
property C[const key: RawUtf8]: currency read GetC write SetC;
Access one element in the dictionary from its key, as fixed precision currency
property D[const key: RawUtf8]: IDocDict read GetD write SetD;
Access one element in the dictionary from its key, as IDocDict
property F[const key: RawUtf8]: double read GetF write SetF;
Access one element in the dictionary from its key, as floating-point double
property I[const key: RawUtf8]: Int64 read GetI write SetI;
Access one element in the dictionary from its key, as integer
property Item[const key: RawUtf8]: variant read GetItem write SetItem;
Access one element in the dictionary from its key, as variant
- this is the default property of this instance so dict[name] gives direct access to each value in the IDocDict
- follows dvoNameCaseSensitive and dvoReturnNullForUnknownProperty options
- see Get() overloaded methods to silently check for a key existence
- PathDelim can be set to locate (and create) the key by its full path
- U[] S[] I[] F[] C[] B[] L[] D[] are faster and safer if you expect to retrieve a specific value type
property L[const key: RawUtf8]: IDocList read GetL write SetL;
Access one element in the dictionary from its key, as IDocList
property O[const key: RawUtf8]: IDocDict read GetD write SetD;
Access one element in the dictionary from its key, as IDocDict/IDocObject
- property alias, for compatibility with existing code
property PathDelim: AnsiChar read GetPathDelim write SetPathDelim;
Enable nested objects location in keys for Get() and Item[]
- equals #0 by default, meaning only root object keys are located, e.g. dict.D['child2']
- if PathDelim is e.g. set to '.', then dict.U['child2.name'] matches dict.D['child2'].U['name']
- note that if the sub object does not exist, setting a value will force its creation (and all needed hierarchy)
property S[const key: RawUtf8]: string read GetS write SetS;
Access one element in the dictionary from its key, as RTL string text
property U[const key: RawUtf8]: RawUtf8 read GetU write SetU;
Access one element in the dictionary from its key, as UTF-8 text
IDocArray = IDocList;
Alias to our interface list type, for compatibility with existing code
IDocDictDynArray = array of IDocDict;
A dynamic array of IDocDict instances
IDocObject = IDocDict;
Alias to our interface dictionary type, for compatibility with existing code
PDocVariantData = ^TDocVariantData;
Pointer to a TDocVariant storage
- since variants may be stored by reference (i.e. as varByRef), it may be a good idea to use such a pointer via DocVariantData(aVariant)^ or _Safe(aVariant)^ instead of TDocVariantData(aVariant), if you are not sure how aVariant was allocated (may be not _Obj/_Json)
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData
PDocVariantDataDynArray = array of PDocVariantData;
Pointer to a dynamic array of TDocVariant storage
TDocVariantKind = ( dvUndefined, dvArray, dvObject );
Define the TDocVariant storage layout
- if it has no name property, it is a dvArray
- if it has one or more named properties, it is a dvObject
TDocVariantModel = ( mVoid, mDefault, mFast, mFastFloat, mFastStrict, mFastExtended, mFastExtendedIntern, mNameValue, mNameValueExtended, mNameValueIntern, mNameValueInternExtended );
JSON_[] constant convenient TDocVariant options
- mVoid defines a safe (and slow) full-copy behavior with [] (no option)
- mDefault defines a safe (and slow) full-copy behavior, returning null for unknown fields, as defined e.g. by _Json() and _JsonFmt() functions or JSON_OPTIONS[false]
- mFast will copy-by-reference any TDocVariantData content, as defined e.g. by _JsonFast() and _JsonFastFmt() functions or JSON_OPTIONS[true]
- mFastFloat will copy-by-reference and can parse floating points as double
- mFastStrict will copy-by-reference and only parse strict (quoted) JSON, as defined by JSON_FAST_STRICT global variable
- mFastExtended will copy-by-reference and write extended (unquoted) JSON, as defined by JSON_FAST_EXTENDED global variable
- mFastExtendedIntern will copy-by-reference, write extended JSON and intern names and values, as defined by JSON_FAST_EXTENDEDINTERN variable
- mNameValue will copy-by-reference and check field names case-sensitively, as defined by JSON_NAMEVALUE[false] global variable
- mNameValueExtended will copy-by-reference, check field names case-sensitively and write extended (unquoted) JSON, as defined by JSON_NAMEVALUE[true] global variable
- mNameValueIntern will copy-by-reference, check field names case-sensitively and intern names and values, as defined by JSON_NAMEVALUEINTERN[false] global variable
- mNameValueInternExtended will copy-by-reference, check field names case-sensitively, write extended JSON and intern names and values, as defined by JSON_NAMEVALUEINTERN[true] global variable
TOnReducePerItem = function(Item: PDocVariantData): boolean of object;
Method used by TDocVariantData.ReduceAsArray to filter each object
- should return TRUE if the item match the expectations
TOnReducePerValue = function(const Value: variant): boolean of object;
Method used by TDocVariantData.ReduceAsArray to filter each object
- should return TRUE if the item match the expectations
TSearchDuplicate = ( sdNone, sdCaseSensitive, sdCaseInsensitive );
How duplicated values could be searched
TSynInvokeableVariantTypeClass = class of TSynInvokeableVariantType;
Class-reference type (metaclass) of custom variant type definition
- used by SynRegisterCustomVariantType() function
TSynInvokeableVariantTypeOptions = set of ( sioHasTryJsonToVariant, sioHasToJson, sioCanIterate);
Define how our custom variant types behave, i.e. its methods featureset
TVarDataTypes = set of 0..31;
A set of simple TVarData.VType values, as specified to VarIs()
TVariantCompare = function(const V1, V2: variant): PtrInt;
Function prototype used internally for variant comparison
- as used e.g. by TDocVariantData.SortByValue
TVariantCompareField = function(const FieldName: RawUtf8; const V1, V2: variant): PtrInt of object;
Function prototype used internally for extended variant comparison
- as used by TDocVariantData.SortArrayByFields
TVariantComparer = function(const V1, V2: variant): PtrInt of object;
Function prototype used internally for extended variant comparison
- as used by TDocVariantData.SortByRow
DocVariantDataFake: TDocVariantData = ( VType: varNull; VOptions: [dvoReturnNullForUnknownProperty]);
Constant used e.g. by _Safe() and _DV() overloaded functions
- will be in code section of the exe, so will be read-only by design
- would have Kind=dvUndefined and Count=0, so _Safe() would return a valid, but void document
- its VType is varNull, so would be viewed as a null variant
- dvoReturnNullForUnknownProperty is defined, so that U[]/I[]... methods won't raise any exception about unexpected field name
JSON_FAST = [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference];
MVoid mDefault mFast mFastFloat mFastStrict mFastExtended mFastExtendedIntern mNameValue mNameValueExtended mNameValueIntern mNameValueInternExtended same as JSON_[mFast], but can not be used as PDocVariantOptions
- handle only currency for floating point values: use JSON_FAST_FLOAT if you want to support double values, with potential precision loss
JSON_FAST_FLOAT = [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoAllowDoubleValue];
Same as JSON_FAST, but including dvoAllowDoubleValue for floating point values parsing into double, with potential precision loss
| Functions or procedures | Description | |
|---|---|---|
| CustomVariantToJson | Try to serialize a custom variant value into JSON | |
| DocDict | Create a IDocDict as weak reference to a TDocVariantData dvObject | |
| DocDict | Create a self-owned IDocDict from a set of key,value pairs | |
| DocDict | Create a self-owned IDocDict from a JSON object | |
| DocDict | Create a self-owned void IDocDict | |
| DocDictCopy | Create a self-owned IDocDict as full copy of a TDocVariant dvObject | |
| DocDictCopy | Create a self-owned IDocDict as full copy of a TDocVariantData dvObject | |
| DocDictCopy | Create a self-owned IDocDict as full copy of a TDocVariantData dvObject and a specific options model | |
| DocDictDynArray | Create an array of self-owned IDocDict from a JSON array of JSON objects | |
| DocDictFrom | Create a IDocDict as weak reference to a TDocVariant dvObject | |
| DocDictFromKeys | Create a self-owned IDocDict from a set of keys and a gien value | |
| DocDictFromKeys | Create a self-owned IDocDict from a set of keys - values will be Null | |
| DocList | Create a IDocList as weak reference to a TDocVariantData dvArray | |
| DocList | Create a self-owned IDocList from a set of values | |
| DocList | Create a self-owned void IDocList | |
| DocList | Create a self-owned IDocList from a JSON array | |
| DocListCopy | Create a self-owned IDocList as full copy of a TDocVariant dvArray | |
| DocListCopy | Create a self-owned IDocList as full copy of a TDocVariantData dvArray | |
| DocListCopy | Create a self-owned IDocList as full copy of a TDocVariantData dvArray and a specific options model | |
| DocListFrom | Create a self-owned IDocList from a dynamic array of IDocDict values | |
| DocListFrom | Create a IDocList as weak reference to a TDocVariant dvArray | |
| DocListFromResults | Create a self-owned IDocList from TOrmTableJson ORM/DB dual JSON formats | |
| DocVariantData | Direct access to a TDocVariantData from a given variant instance | |
| DocVariantToObjArray | Fill a T*ObjArray variable from a TDocVariant array document values | |
| DocVariantToObject | Fill a class instance from a TDocVariant object document properties | |
| FastVarDataComp | Internal function as called by inlined VariantCompare/VariantCompareI and the SortDynArrayVariantComp() function overriden by this unit | |
| FillZero | Fill all bytes of the value's memory buffer with zeros, i.e. 'toto' -> #0#0#0#0 | |
| FindSynVariantType | Search of a registered custom variant type from its low-level VarType | |
| FromVarVariant | Retrieve a variant value from variable-length buffer | |
| GetJsonToAnyVariant | Low-level function to parse a JSON content into a variant | |
| GetNextItemToVariant | Convert the next CSV item into a variant number or RawUtf8 varString | |
| GetNumericVariantFromJson | Low-level function to parse a variant from an unescaped JSON number | |
| GetVariantFromJsonField | Low-level function to set a variant from an unescaped JSON number or string | |
| GetVariantFromNotStringJson | Low-level function to set a variant from an unescaped JSON non string | |
| InitializeVariantsJson | Internal initialization function called from mormot.core.json | |
| JsonToAnyVariant | Low-level function to parse a JSON buffer content into a variant | |
| JsonToVariant | Just a wrapper around VariantLoadJson() with some TDocVariantOptions | |
| JsonToVariantDynArray | Convert a JSON array into a dynamic array of variants | |
| JsonToVariantInPlace | Just a wrapper around JsonToAnyVariant() with some TDocVariantOptions | |
| MultiPartToDocVariant | Decode multipart/form-data POST request content into a TDocVariantData | |
| ObjectDefaultToVariant | Will convert a blank TObject into a TDocVariant document instance | |
| ObjectToVariant | Will convert any TObject into a TDocVariant document instance | |
| ObjectToVariant | Will convert any TObject into a TDocVariant document instance | |
| ObjectToVariantDebug | Will serialize any TObject into a TDocVariant debugging document | |
| ParseSortMatch | Parse a "key<value" or "key<" expression for SortMatch() comparison | |
| RawUtf8DynArrayToArrayOfConst | Convert an array of RawUtf8 to open array (const Args: array of const) arguments | |
| RawUtf8ToVariant | Convert an UTF-8 encoded text buffer into a variant RawUtf8 varString | |
| SetNameToVariant | Get the enumeration names corresponding to a set value, as a JSON array | |
| SetNameToVariant | Get the enumeration names corresponding to a set value, as a JSON array | |
| SetVariantByRef | Same as Dest := Source, but copying by reference | |
| SetVariantByValue | Same as Dest := Source, but copying by value | |
| SortCompTo | Low-level conversion of a Compare() result to TCustomVariantType.Compare | |
| SynRegisterCustomVariantType | Register a custom variant type to handle properties | |
| TextBufferToVariant | Convert some UTF-8 buffer into a variant, detecting JSON numbers or constants | |
| TextToVariant | Convert some UTF-8 into a variant, detecting JSON numbers or constants | |
| TextToVariantNumberType | Identify either varInt64, varDouble, varCurrency types following JSON format | |
| TextToVariantNumberTypeNoDouble | Identify either varInt64 or varCurrency types following JSON format | |
| ToText | Retrieve the text representation of a TDocVairnatKind | |
| UniqueVariant | Convert some UTF-8 text buffer into a variant, with string interning | |
| ValuesToVariantDynArray | Convert an open array list into a dynamic array of variants | |
| VariantCompare | TVariantCompare-compatible case-sensitive comparison function | |
| VariantCompareI | TVariantCompare-compatible case-insensitive comparison function | |
| VariantDynArrayToJson | Convert a dynamic array of variants into its JSON serialization | |
| VariantDynArrayToRawUtf8DynArray | Convert a dynamic array of variants into its text values | |
| VariantEquals | Fast comparison of a Variant and UTF-8 encoded String (or number) | |
| VariantLoad | Retrieve a variant value from our optimized binary serialization format | |
| VariantLoad | Retrieve a variant value from our optimized binary serialization format | |
| VariantLoadJson | Retrieve a variant value from a JSON number or string | |
| VariantLoadJson | Retrieve a variant value from a JSON number or string | |
| VariantSave | Save a Variant content into a binary buffer | |
| VariantSave | Save a Variant content into a destination memory buffer | |
| VariantSaveLength | Compute the number of bytes needed to save a Variant content using the VariantSave() function | |
| VariantsToArrayOfConst | Convert a variant array to open array (const Args: array of const) arguments | |
| VariantsToArrayOfConst | Convert a variant array to open array (const Args: array of const) arguments | |
| VariantToString | Convert any Variant into a RTL string type | |
| VariantToString | Convert any Variant into a RTL string type | |
| VariantToVarRec | Convert a variant to an open array (const Args: array of const) argument | |
| VariantTypeName | Return the variant VType as text, e.g. 'Integer', 'String' or 'DocVariant' | |
| VariantTypeName | Return the TVarData.VType as text, e.g. 'Integer', 'String' or 'DocVariant' | |
| VarIs | Allow to check for a specific set of TVarData.VType | |
| VarIsVoid | Fastcheck if a variant hold a value | |
| VarRecToVariant | Convert an open array (const Args: array of const) argument to a variant | |
| VarRecToVariant | Convert an open array (const Args: array of const) argument to a variant | |
| VarStringOrNull | Returns a supplied string as variant, or null if v is void ('') | |
| ZeroFill | Same as FillChar(Value^,SizeOf(TVarData),0) | |
| _Arr | Initialize a variant instance to store some document-based array content | |
| _ArrFast | Initialize a variant instance to store some document-based array content | |
| _ByRef | Copy a TDocVariant to another variable, changing the options on the fly | |
| _ByRef | Copy a TDocVariant to another variable, changing the options on the fly | |
| _Copy | Return a full nested copy of a document-based variant instance | |
| _CopyFast | Return a full nested copy of a document-based variant instance | |
| _Csv | Convert a TDocVariantData array or a string value into a CSV | |
| _DV | Direct copy of a TDocVariantData from a given variant instance | |
| _DV | Direct copy of a TDocVariantData from a given variant instance | |
| _DV | Direct copy of a TDocVariantData from a given variant instance | |
| _Json | Initialize a variant instance to store some document-based content from a supplied (extended) JSON content | |
| _Json | Initialize a variant instance to store some document-based content from a supplied (extended) JSON content | |
| _JsonFast | Initialize a variant instance to store some document-based content from a supplied (extended) JSON content | |
| _JsonFastExt | Initialize a variant instance to store some extended document-based content | |
| _JsonFastFloat | Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with double conversion | |
| _JsonFastFmt | Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating | |
| _JsonFmt | Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating | |
| _JsonFmt | Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating | |
| _Obj | Delphi has troubles inlining goto/label initialize a variant instance to store some document-based object content | |
| _ObjAddProp | Add a property value to a document-based object content | |
| _ObjAddProp | Add a document property value to a document-based object content | |
| _ObjAddProps | Add some property values to a document-based object content | |
| _ObjAddProps | Add the property values of a document to a document-based object content | |
| _ObjAddPropU | Add a RawUtf8 property value to a document-based object content | |
| _ObjFast | Initialize a variant instance to store some document-based object content | |
| _ObjFast | Initialize a variant instance to store any object as a TDocVariant | |
| _Safe | Direct access to a TDocVariantData from a given variant instance | |
| _Safe | Delphi has problems inlining this :( direct access to a TDocVariantData from a given variant instance | |
| _Safe | Direct access to a TDocVariantData from a given variant instance | |
| _SafeArray | Direct access to a TDocVariantData array from a given variant instance | |
| _SafeArray | Direct access to a TDocVariantData array from a given variant instance | |
| _SafeObject | Direct access to a TDocVariantData object from a given variant instance | |
| _Unique | Ensure a document-based variant instance will have only per-value nested objects or array documents | |
| _UniqueFast | Ensure a document-based variant instance will have only per-value nested objects or array documents |
function CustomVariantToJson(W: TJsonWriter; Value: PVarData; Escape: TTextWriterKind): boolean;
Try to serialize a custom variant value into JSON
- as used e.g. by TJsonWriter.AddVariant
function DocDict(const json: RawUtf8; model: TDocVariantModel = mFastFloat): IDocDict; overload;
Create a self-owned IDocDict from a JSON object
function DocDict(model: TDocVariantModel = mFastFloat): IDocDict; overload;
Create a self-owned void IDocDict
function DocDict(const dv: TDocVariantData): IDocDict; overload;
Create a IDocDict as weak reference to a TDocVariantData dvObject
function DocDict(const keyvalues: array of const; model: TDocVariantModel = mFastFloat): IDocDict; overload;
Create a self-owned IDocDict from a set of key,value pairs
function DocDictCopy(const dv: TDocVariantData; model: TDocVariantModel): IDocDict; overload;
Create a self-owned IDocDict as full copy of a TDocVariantData dvObject and a specific options model
function DocDictCopy(const dv: TDocVariantData): IDocDict; overload;
Create a self-owned IDocDict as full copy of a TDocVariantData dvObject
function DocDictCopy(const v: variant): IDocDict; overload;
Create a self-owned IDocDict as full copy of a TDocVariant dvObject
function DocDictDynArray(const json: RawUtf8; model: TDocVariantModel = mFastFloat; jsonfromresults: boolean = false): IDocDictDynArray;
Create an array of self-owned IDocDict from a JSON array of JSON objects
- set jsonfromresults=true if input is TOrmTableJson ORM/DB dual JSON formats
- any element of the JSON array which is not a JSON object will be ignored
function DocDictFrom(const v: variant): IDocDict;
Create a IDocDict as weak reference to a TDocVariant dvObject
function DocDictFromKeys(const keys: array of RawUtf8; model: TDocVariantModel = mFastFloat): IDocDict; overload;
Create a self-owned IDocDict from a set of keys - values will be Null
function DocDictFromKeys(const keys: array of RawUtf8; const value: variant; model: TDocVariantModel = mFastFloat): IDocDict; overload;
Create a self-owned IDocDict from a set of keys and a gien value
function DocList(model: TDocVariantModel = mFastFloat): IDocList; overload;
Create a self-owned void IDocList
function DocList(const json: RawUtf8; model: TDocVariantModel = mFastFloat): IDocList; overload;
Create a self-owned IDocList from a JSON array
function DocList(const dv: TDocVariantData): IDocList; overload;
Create a IDocList as weak reference to a TDocVariantData dvArray
function DocList(const values: array of const; model: TDocVariantModel = mFastFloat): IDocList; overload;
Create a self-owned IDocList from a set of values
function DocListCopy(const dv: TDocVariantData; model: TDocVariantModel): IDocList; overload;
Create a self-owned IDocList as full copy of a TDocVariantData dvArray and a specific options model
function DocListCopy(const dv: TDocVariantData): IDocList; overload;
Create a self-owned IDocList as full copy of a TDocVariantData dvArray
function DocListCopy(const v: variant): IDocList; overload;
Create a self-owned IDocList as full copy of a TDocVariant dvArray
function DocListFrom(const v: variant): IDocList; overload;
Create a IDocList as weak reference to a TDocVariant dvArray
function DocListFrom(const dictarray: IDocDictDynArray): IDocList; overload;
Create a self-owned IDocList from a dynamic array of IDocDict values
function DocListFromResults(const json: RawUtf8; model: TDocVariantModel = mFastFloat): IDocList;
Create a self-owned IDocList from TOrmTableJson ORM/DB dual JSON formats
function DocVariantData(const DocVariant: variant): PDocVariantData;
Direct access to a TDocVariantData from a given variant instance
- return a pointer to the TDocVariantData corresponding to the variant instance, which may be of kind varByRef (e.g. when retrieved by late binding)
- raise an EDocVariant exception if the instance is not a TDocVariant
- the following direct trans-typing may fail, e.g. for varByRef value:
TDocVariantData(aVarDoc.ArrayProp).Add('new item');
- so you can write the following:
DocVariantData(aVarDoc.ArrayProp).AddItem('new item');
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData
procedure DocVariantToObjArray(var arr: TDocVariantData; var objArray; objClass: TClass);
Fill a T*ObjArray variable from a TDocVariant array document values
- will always erase the T*ObjArray instance, and fill it from arr values
function DocVariantToObject(var doc: TDocVariantData; obj: TObject; objRtti: TRttiCustom = nil): boolean;
Fill a class instance from a TDocVariant object document properties
- returns FALSE if the variant is not a dvObject, TRUE otherwise
function FastVarDataComp(A, B: PVarData; caseInsensitive: boolean): integer;
Internal function as called by inlined VariantCompare/VariantCompareI and the SortDynArrayVariantComp() function overriden by this unit
procedure FillZero(var value: variant); overload;
Fill all bytes of the value's memory buffer with zeros, i.e. 'toto' -> #0#0#0#0
- may be used to cleanup stack-allocated content
function FindSynVariantType(aVarType: cardinal): TSynInvokeableVariantType;
Search of a registered custom variant type from its low-level VarType
- returns the matching custom variant type, nil if not found
procedure FromVarVariant(var Source: PByte; var Value: variant; CustomVariantOptions: PDocVariantOptions; SourceMax: PByte);
Retrieve a variant value from variable-length buffer
- matches TFileBufferWriter.Write()
- how custom type variants are created can be defined via CustomVariantOptions
- is just a wrapper around VariantLoad/BinaryLoad
procedure GetJsonToAnyVariant(var Value: variant; var Json: PUtf8Char; EndOfObject: PUtf8Char; Options: PDocVariantOptions; AllowDouble: boolean); overload;
Low-level function to parse a JSON content into a variant
function GetNextItemToVariant(var P: PUtf8Char; out Value: Variant; Sep: AnsiChar = ','; AllowDouble: boolean = true): boolean;
Convert the next CSV item into a variant number or RawUtf8 varString
- just a wrapper around GetNextItem() + TextToVariant()
function GetNumericVariantFromJson(Json: PUtf8Char; var Value: TVarData; AllowVarDouble: boolean): PUtf8Char;
Low-level function to parse a variant from an unescaped JSON number
- returns the position after the number, and set Value to a variant of type varInteger/varInt64/varCurrency (or varDouble if AllowVarDouble is true)
- returns nil if JSON can't be converted to a number - it is likely a string
- handle only up to 4 decimals (i.e. currency) if AllowVarDouble is false
- matches TextToVariantNumberType/TextToVariantNumberTypeNoDouble() logic
- see GetVariantFromNotStringJson() to check the whole Json input, and parse null/false/true values
procedure GetVariantFromJsonField(Json: PUtf8Char; wasString: boolean; var Value: variant; TryCustomVariants: PDocVariantOptions = nil; AllowDouble: boolean = false; JsonLen: integer = 0);
Low-level function to set a variant from an unescaped JSON number or string
- expect the JSON input buffer to be already unescaped and #0 terminated, e.g. by TGetJsonField, and having set properly the wasString flag
- set the varString or call GetVariantFromNotStringJson() if TryCustomVariants=nil
- or call JsonToAnyVariant() to support TryCustomVariants^ complex input
function GetVariantFromNotStringJson(Json: PUtf8Char; var Value: TVarData; AllowDouble: boolean): boolean;
Low-level function to set a variant from an unescaped JSON non string
- expect the JSON input buffer to be already unescaped and #0 terminated, e.g. by TGetJsonField, and having returned wasString=false
- is called e.g. by function GetVariantFromJsonField()
- will recognize null, boolean, integer, Int64, currency, double (if AllowDouble is true) input, then set Value and return TRUE
- returns FALSE if the supplied input has no expected JSON format
procedure InitializeVariantsJson;
Internal initialization function called from mormot.core.json
procedure JsonToAnyVariant(var Value: variant; var Info: TGetJsonField; Options: PDocVariantOptions; AllowDouble: boolean = false);
Low-level function to parse a JSON buffer content into a variant
- warning: will decode in the Json buffer memory itself (no memory allocation or copy), for faster process - so take care that it is not shared
- internal method used by VariantLoadJson(), GetVariantFromJsonField() and TDocVariantData.InitJson()
- will instantiate either an integer, Int64, currency, double or string value (as RawUtf8), guessing the best numeric type according to the textual content, and string in all other cases, except TryCustomVariants points to some options (e.g. @JSON_[mFast] for fast instance) and input is a known object or array, either encoded as strict-JSON (i.e. {..} or [..]), or with some extended (e.g. BSON) syntax
function JsonToVariant(const Json: RawUtf8; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]; AllowDouble: boolean = false): variant;
Just a wrapper around VariantLoadJson() with some TDocVariantOptions
- make a temporary copy of the input Json before parsing
function JsonToVariantDynArray(const Json: RawUtf8): TVariantDynArray;
Convert a JSON array into a dynamic array of variants
- will use a TDocVariantData temporary storage
function JsonToVariantInPlace(var Value: Variant; Json: PUtf8Char; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]; AllowDouble: boolean = false): PUtf8Char;
Just a wrapper around JsonToAnyVariant() with some TDocVariantOptions
procedure MultiPartToDocVariant(const MultiPart: TMultiPartDynArray; var Doc: TDocVariantData; Options: PDocVariantOptions = nil);
Decode multipart/form-data POST request content into a TDocVariantData
- following RFC 1867
- decoded sections are encoded as Doc JSON object with its textual values, or with nested objects, if the data was supplied as binary:
{"name1":{"data":..,"filename":...,"contenttype":...},"name2":...}function ObjectDefaultToVariant(aClass: TClass; aOptions: TDocVariantOptions): variant; overload;
Will convert a blank TObject into a TDocVariant document instance
procedure ObjectToVariant(Value: TObject; var result: variant; Options: TTextWriterWriteObjectOptions = [woDontStoreDefault]); overload;
Will convert any TObject into a TDocVariant document instance
- fast processing function as used by _ObjFast(Value)
- note that the result variable should already be cleared: no VarClear() is done by this function
- would be used e.g. by VarRecToVariant() function
- if you expect lazy-loading of a TObject, see TObjectVariant.New()
function ObjectToVariant(Value: TObject; EnumSetsAsText: boolean): variant; overload;
Will convert any TObject into a TDocVariant document instance
- convenient overloaded function to include woEnumSetsAsText option
function ObjectToVariantDebug(Value: TObject; const ContextFormat: RawUtf8; const ContextArgs: array of const; const ContextName: RawUtf8 = 'context'): variant; overload;
Will serialize any TObject into a TDocVariant debugging document
- just a wrapper around _JsonFast(ObjectToJsonDebug()) with an optional "Context":"..." text message
- if the supplied context format matches '{....}' then it will be added as a corresponding TDocVariant JSON object
function ParseSortMatch(Expression: PUtf8Char; out Key: RawUtf8; out Match: TCompareOperator; Value: PVariant): boolean;
Parse a "key<value" or "key<" expression for SortMatch() comparison
function RawUtf8DynArrayToArrayOfConst(const V: array of RawUtf8): TTVarRecDynArray;
Convert an array of RawUtf8 to open array (const Args: array of const) arguments
- RawUtf8 are accessed by reference as vtAnsiString so should remain available
procedure RawUtf8ToVariant(const Txt: RawUtf8; var Value: TVarData; ExpectedValueType: cardinal); overload;
Convert an UTF-8 encoded text buffer into a variant RawUtf8 varString
- this overloaded version expects a destination variant type (e.g. varString varOleStr / varUString) - if the type is not handled, will raise an EVariantTypeCastError
function SetNameToVariant(Value: cardinal; Info: TRttiCustom; FullSetsAsStar: boolean = false): variant; overload;
Get the enumeration names corresponding to a set value, as a JSON array
function SetNameToVariant(Value: cardinal; Info: PRttiInfo; FullSetsAsStar: boolean = false): variant; overload;
Get the enumeration names corresponding to a set value, as a JSON array
procedure SetVariantByRef(const Source: Variant; var Dest: Variant);
Same as Dest := Source, but copying by reference
- i.e. VType is defined as varVariant or varByRef / varVariantByRef
- for instance, it will be used for late binding of TDocVariant properties, to let following statements work as expected:
V := _Json('{arr:[1,2]}'); V.arr.Add(3); // will work, since V.arr will be returned by reference writeln(V); // will write '{"arr":[1,2,3]}'
procedure SetVariantByValue(const Source: Variant; var Dest: Variant);
Same as Dest := Source, but copying by value
- will unreference any varByRef content
- will convert any string value into RawUtf8 (varString) for consistency
function SortCompTo(cmp: integer): TVarCompareResult;
Low-level conversion of a Compare() result to TCustomVariantType.Compare
function SynRegisterCustomVariantType( aClass: TSynInvokeableVariantTypeClass): TSynInvokeableVariantType;
Register a custom variant type to handle properties
- the registration process is thread-safe
- this will implement an internal mechanism used to bypass the default _DispInvoke() implementation in Variant.pas, to use a faster version
- is called in case of TDocVariant, TBsonVariant or TSqlDBRowVariant
procedure TextBufferToVariant(aValue: PUtf8Char; AllowVarDouble: boolean; out aDest: variant);
Convert some UTF-8 buffer into a variant, detecting JSON numbers or constants
- first try GetVariantFromNotStringJson() then fallback to RawUtf8ToVariant()
procedure TextToVariant(const aValue: RawUtf8; AllowVarDouble: boolean; out aDest: variant);
Convert some UTF-8 into a variant, detecting JSON numbers or constants
- first try GetVariantFromNotStringJson() then fallback to RawUtf8ToVariant()
function TextToVariantNumberType(Json: PUtf8Char): cardinal;
Identify either varInt64, varDouble, varCurrency types following JSON format
- any non valid number is returned as varString
- warning: supplied JSON is expected to be not nil
function TextToVariantNumberTypeNoDouble(Json: PUtf8Char): cardinal;
Identify either varInt64 or varCurrency types following JSON format
- this version won't return varDouble, i.e. won't handle more than 4 exact decimals (as varCurrency), nor scientific notation with exponent (1.314e10)
- this will ensure that any incoming JSON will converted back with its exact textual representation, without digit truncation due to limited precision
- any non valid number is returned as varString
- warning: supplied JSON is expected to be not nil
function ToText(kind: TDocVariantKind): PShortString; overload;
Retrieve the text representation of a TDocVairnatKind
procedure UniqueVariant(Interning: TRawUtf8Interning; var aResult: variant; aText: PUtf8Char; aTextLen: PtrInt; aAllowVarDouble: boolean = false); overload;
Convert some UTF-8 text buffer into a variant, with string interning
- similar to TextToVariant(), but with string interning (if Interning<>nil)
- first try GetVariantFromNotStringJson() then fallback to RawUtf8ToVariant()
function ValuesToVariantDynArray(const items: array of const): TVariantDynArray;
Convert an open array list into a dynamic array of variants
- will use a TDocVariantData temporary storage
function VariantCompare(const V1, V2: variant): PtrInt;
TVariantCompare-compatible case-sensitive comparison function
- just a wrapper around FastVarDataComp(caseInsensitive=false)
function VariantCompareI(const V1, V2: variant): PtrInt;
TVariantCompare-compatible case-insensitive comparison function
- just a wrapper around FastVarDataComp(caseInsensitive=true)
function VariantDynArrayToJson(const V: TVariantDynArray): RawUtf8;
Convert a dynamic array of variants into its JSON serialization
- will use a TDocVariantData temporary storage
function VariantDynArrayToRawUtf8DynArray(const V: TVariantDynArray): TRawUtf8DynArray;
Convert a dynamic array of variants into its text values
function VariantEquals(const V: Variant; const Str: RawUtf8; CaseSensitive: boolean = true): boolean; overload;
Fast comparison of a Variant and UTF-8 encoded String (or number)
- slightly faster than plain V=Str, which computes a temporary variant
- here Str='' equals unassigned (varEmpty), null or false
- if CaseSensitive is false, will use PropNameEquals() for comparison
function VariantLoad(var Value: variant; Source: PAnsiChar; CustomVariantOptions: PDocVariantOptions; SourceMax: PAnsiChar = nil ): PAnsiChar; overload;
Retrieve a variant value from our optimized binary serialization format
- follow the data layout as used by RecordLoad() or VariantSave() function
- return nil if the Source buffer is incorrect
- in case of success, return the memory buffer pointer just after the read content
- how custom type variants are created can be defined via CustomVariantOptions
- is a wrapper around BinaryLoad(rkVariant)
function VariantLoad(const Bin: RawByteString; CustomVariantOptions: PDocVariantOptions): variant; overload;
Retrieve a variant value from our optimized binary serialization format
- follow the data layout as used by RecordLoad() or VariantSave() function
- return varEmpty if the Source buffer is incorrect
- just a wrapper around VariantLoad()
- how custom type variants are created can be defined via CustomVariantOptions
- is a wrapper around BinaryLoad(rkVariant)
function VariantLoadJson(var Value: Variant; const Json: RawUtf8; TryCustomVariants: PDocVariantOptions = nil; AllowDouble: boolean = false): boolean; overload;
Retrieve a variant value from a JSON number or string
- follows TJsonWriter.AddVariant() format (calls JsonToAnyVariant)
- make a temporary copy before parsing - use JsonToAnyVariant() on a buffer
- return true and set Value on success, or false and empty Value on error
function VariantLoadJson(const Json: RawUtf8; TryCustomVariants: PDocVariantOptions = nil; AllowDouble: boolean = false): variant; overload;
Retrieve a variant value from a JSON number or string
- just wrap VariantLoadJson(Value,Json...) procedure as a function
function VariantSave(const Value: variant; Dest: PAnsiChar): PAnsiChar; overload; deprecated;
Save a Variant content into a destination memory buffer
- Dest must be at least VariantSaveLength() bytes long
- will handle standard Variant types and custom types (serialized as JSON)
- will return nil in case of an invalid (not handled) Variant type
- will use a proprietary binary format, with some variable-length encoding of the string length
- warning: will encode RTL string fields as within the variant type itself: using this function between UNICODE and NOT UNICODE versions of Delphi, will propably fail - you have been warned!
- deprecated function - use overloaded BinarySave() functions instead
function VariantSave(const Value: variant): RawByteString; overload;
Save a Variant content into a binary buffer
- will handle standard Variant types and custom types (serialized as JSON)
- will return '' in case of an invalid (not handled) Variant type
- just a wrapper around VariantSaveLength()+VariantSave()
- warning: will encode RTL string fields as within the variant type itself: using this function between UNICODE and NOT UNICODE versions of Delphi, will propably fail - you have been warned!
- is a wrapper around BinarySave(rkVariant)
function VariantSaveLength(const Value: variant): integer; deprecated;
Compute the number of bytes needed to save a Variant content using the VariantSave() function
- will return 0 in case of an invalid (not handled) Variant type
- deprecated function - use overloaded BinarySave() functions instead
function VariantsToArrayOfConst(const V: array of variant): TTVarRecDynArray; overload;
Convert a variant array to open array (const Args: array of const) arguments
- variants are accessed by reference as vtVariant so should remain available
procedure VariantsToArrayOfConst(const V: array of variant; VCount: PtrInt; out result: TTVarRecDynArray); overload;
Convert a variant array to open array (const Args: array of const) arguments
- variants are accessed by reference as vtVariant so should remain available
procedure VariantToString(const V: Variant; var result: string); overload;
Convert any Variant into a RTL string type
function VariantToString(const V: Variant): string; overload;
Convert any Variant into a RTL string type
- expects any varString value to be stored as a RawUtf8
- prior to Delphi 2009, use VariantToString(aVariant) instead of string(aVariant) to safely retrieve a string=AnsiString value from a variant generated by our framework units - otherwise, you may loose encoded characters
- for Unicode versions of Delphi, there won't be any potential data loss, but this version may be slightly faster than a string(aVariant)
procedure VariantToVarRec(const V: variant; var result: TVarRec);
Convert a variant to an open array (const Args: array of const) argument
- variant is accessed by reference as vtVariant so should remain available
function VariantTypeName(V: PVarData): PShortString; overload;
Return the TVarData.VType as text, e.g. 'Integer', 'String' or 'DocVariant'
function VariantTypeName(const V: variant): PShortString; overload;
Return the variant VType as text, e.g. 'Integer', 'String' or 'DocVariant'
function VarIs(const V: Variant; const VTypes: TVarDataTypes): boolean;
Allow to check for a specific set of TVarData.VType
function VarIsVoid(const V: Variant): boolean;
Fastcheck if a variant hold a value
- varEmpty, varNull or a '' string would be considered as void
- varBoolean=false or varDate=0 would be considered as void
- a TDocVariantData with Count=0 would be considered as void
- any other value (e.g. floats or integer) would be considered as not void
procedure VarRecToVariant(const V: TVarRec; var result: variant); overload;
Convert an open array (const Args: array of const) argument to a variant
- note that, due to a Delphi compiler limitation, cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be converted)
- vt*String or vtVariant arguments are returned as varByRef
function VarRecToVariant(const V: TVarRec): variant; overload;
Convert an open array (const Args: array of const) argument to a variant
- note that, due to a Delphi compiler limitation, cardinal values should be type-casted to Int64() (otherwise the integer mapped value will be converted)
- vt*String or vtVariant arguments are returned as varByRef
function VarStringOrNull(const v: RawUtf8): variant;
Returns a supplied string as variant, or null if v is void ('')
procedure ZeroFill(Value: PVarData);
Same as FillChar(Value^,SizeOf(TVarData),0)
- so can be used for TVarData or Variant
- it will set V.VType := varEmpty, so Value will be Unassigned
- it won't call VarClear(variant(Value)): it should have been cleaned before
function _Arr(const Items: array of const; Options: TDocVariantOptions = []): variant;
Initialize a variant instance to store some document-based array content
- array will be initialized with data supplied as parameters, e.g.
aVariant := _Arr(['one',2,3.0]);
- this global function is an alias to TDocVariant.NewArray()
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set Options = [dvoValueCopiedByReference] or using _ArrFast() will increase the process speed a lot
function _ArrFast(const Items: array of const): variant; overload;
Initialize a variant instance to store some document-based array content
- this global function is an handy alias to:
_Array(Items, JSON_FAST);
- so all created objects and arrays will be handled by reference, for best speed - but you should better write on the resulting variant tree with caution
function _ByRef(const DocVariant: variant; Options: TDocVariantOptions): variant; overload;
Copy a TDocVariant to another variable, changing the options on the fly
- note that the content (items or properties) is copied by reference, so consider using _Copy() instead if you expect to safely modify its content
- will return null if the supplied variant is not a TDocVariant
procedure _ByRef(const DocVariant: variant; out Dest: variant; Options: TDocVariantOptions); overload;
Copy a TDocVariant to another variable, changing the options on the fly
- note that the content (items or properties) is copied by reference, so consider using _Copy() instead if you expect to safely modify its content
- will return null if the supplied variant is not a TDocVariant
function _Copy(const DocVariant: variant): variant;
Return a full nested copy of a document-based variant instance
- is just a wrapper around:
TDocVariant.NewUnique(DocVariant,JSON_[mDefault])
- you can use this function to ensure that all internal properties of this variant will be copied per-value whatever options the nested objects or arrays were created with: to be used on a value returned as varByRef (e.g. by _() pseudo-method)
- for huge document with a big depth of nested objects or arrays, a full per-value copy may be time and resource consuming, but will be also safe - consider using _ByRef() instead if a fast copy-by-reference is enough
- will raise an EDocVariant if the supplied variant is not a TDocVariant or a varByRef pointing to a TDocVariant
function _CopyFast(const DocVariant: variant): variant;
Return a full nested copy of a document-based variant instance
- is just a wrapper around:
TDocVariant.NewUnique(DocVariant, JSON_FAST)
- you can use this function to ensure that all internal properties of this variant will be copied per-value whatever options the nested objects or arrays were created with: to be used on a value returned as varByRef (e.g. by _() pseudo-method)
- for huge document with a big depth of nested objects or arrays, a full per-value copy may be time and resource consuming, but will be also safe - consider using _ByRef() instead if a fast copy-by-reference is enough
- will raise an EDocVariant if the supplied variant is not a TDocVariant or a varByRef pointing to a TDocVariant
function _Csv(const DocVariantOrString: variant): RawUtf8;
Convert a TDocVariantData array or a string value into a CSV
- will call either TDocVariantData.ToCsv, or return the string
- returns '' if the supplied value is neither a TDocVariant or a string
- could be used e.g. to store either a JSON CSV string or a JSON array of strings in a settings property
function _DV(const DocVariant: variant): TDocVariantData; overload;
Direct copy of a TDocVariantData from a given variant instance
- slower, but maybe used instead of _Safe() e.g. on Delphi 11
function _DV(const DocVariant: variant; var DV: TDocVariantData): boolean; overload;
Direct copy of a TDocVariantData from a given variant instance
- slower, but maybe used instead of _Safe() e.g. on Delphi 11
function _DV(const DocVariant: variant; ExpectedKind: TDocVariantKind): TDocVariantData; overload;
Direct copy of a TDocVariantData from a given variant instance
- slower, but maybe used instead of _Safe() e.g. on Delphi 11
function _Json(const Json: RawUtf8; var Value: variant; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]): boolean; overload;
Initialize a variant instance to store some document-based content from a supplied (extended) JSON content
- this global function is an alias to TDocVariant.NewJson(), and will return TRUE if JSON content was correctly converted into a variant
- in addition to the JSON RFC specification strict mode, this method will handle some BSON-like extensions, e.g. unquoted field names or ObjectID()
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, add dvoValueCopiedByReference in Options will increase the process speed a lot, or use _JsonFast()
function _Json(const Json: RawUtf8; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]): variant; overload;
Initialize a variant instance to store some document-based content from a supplied (extended) JSON content
- this global function is an alias to TDocVariant.NewJson(), and return an Unassigned (varEmpty) variant if JSON content was not correctly converted
- object or array will be initialized from the supplied JSON content, e.g.
aVariant := _Json('{"id":10,"doc":{"name":"John","birthyear":1972}}'); // now you can access to the properties via late binding assert(aVariant.id=10); assert(aVariant.doc.name='John'); assert(aVariant.doc.birthYear=1972); // and also some pseudo-properties: assert(aVariant._count=2); assert(aVariant.doc._kind=ord(dvObject)); // or with a JSON array: aVariant := _Json('["one",2,3]'); assert(aVariant._kind=ord(dvArray)); for i := 0 to aVariant._count-1 do writeln(aVariant._(i));
- in addition to the JSON RFC specification strict mode, this method will handle some BSON-like extensions, e.g. unquoted field names:
aVariant := _Json('{id:10,doc:{name:"John",birthyear:1972}}');
- if the mormot.db.nosql.bson unit is used in the application, the MongoDB Shell syntax will also be recognized to create TBsonVariant, like
new Date() ObjectId() MinKey MaxKey /<jRegex>/<jOptions>
see @http://docs.mongodb.org/manual/reference/mongodb-extended-json
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, add dvoValueCopiedByReference in Options will increase the process speed a lot, or use _JsonFast()
- handle only currency for floating point values: call _JsonFastFloat or set dvoAllowDoubleValue option to support double, with potential precision loss
function _JsonFast(const Json: RawUtf8): variant;
Initialize a variant instance to store some document-based content from a supplied (extended) JSON content
- this global function is an handy alias to:
_Json(JSON, JSON_FAST);
so returns an Unassigned (varEmpty) variant if JSON content was not correct
- so all created objects and arrays will be handled by reference, for best speed - but you should better write on the resulting variant tree with caution
- in addition to the JSON RFC specification strict mode, this method will handle some BSON-like extensions, e.g. unquoted field names or ObjectID()
- will handle only currency for floating point values to avoid precision loss: use _JsonFastFloat() instead if you want to support double values
function _JsonFastExt(const Json: RawUtf8): variant;
Initialize a variant instance to store some extended document-based content
- this global function is an handy alias to:
_Json(JSON, JSON_FAST_EXTENDED);
function _JsonFastFloat(const Json: RawUtf8): variant;
Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with double conversion
- _JsonFast() will support only currency floats: use this method instead if your JSON input is likely to require double values - with potential precision loss
function _JsonFastFmt(const Format: RawUtf8; const Args, Params: array of const): variant;
Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating
- this global function is an handy alias e.g. to:
aVariant := _JsonFmt('{%:{$in:[?,?]}}',['type'],['food','snack'], JSON_FAST);
- so all created objects and arrays will be handled by reference, for best speed - but you should better write on the resulting variant tree with caution
- in addition to the JSON RFC specification strict mode, this method will handle some BSON-like extensions, e.g. unquoted field names or ObjectID():
function _JsonFmt(const Format: RawUtf8; const Args, Params: array of const; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty]): variant; overload;
Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating
- wrapper around the _Json(FormatUtf8(...,JsonFormat=true)) function, i.e. every Args[] will be inserted for each % and Params[] for each ?, with proper JSON escaping of string values, and writing nested _Obj() / _Arr() instances as expected JSON objects / arrays
- typical use (in the context of mormot.db.nosql.bson unit) could be:
aVariant := _JsonFmt('{%:{$in:[?,?]}}',['type'],['food','snack']); aVariant := _JsonFmt('{type:{$in:?}}',[],[_Arr(['food','snack'])]); // which are the same as: aVariant := _JsonFmt('{type:{$in:["food","snack"]}}'); // in this context: u := VariantSaveJson(aVariant); assert(u='{"type":{"$in":["food","snack"]}}'); u := VariantSaveMongoJson(aVariant,modMongoShell); assert(u='{type:{$in:["food","snack"]}}');
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, add dvoValueCopiedByReference in Options will increase the process speed a lot, or use _JsonFast()
procedure _JsonFmt(const Format: RawUtf8; const Args, Params: array of const; Options: TDocVariantOptions; out Result: variant); overload;
Initialize a variant instance to store some document-based content from a supplied (extended) JSON content, with parameters formating
- this overload function will set directly a local variant variable, and would be used by inlined _JsonFmt/_JsonFastFmt functions
function _Obj(const NameValuePairs: array of const; Options: TDocVariantOptions = []): variant;
Delphi has troubles inlining goto/label initialize a variant instance to store some document-based object content
- object will be initialized with data supplied two by two, as Name,Value pairs, e.g.
aVariant := _Obj(['name','John','year',1972]);
or even with nested objects:
aVariant := _Obj(['name','John','doc',_Obj(['one',1,'two',2.0])]);
- this global function is an alias to TDocVariant.NewObject()
- by default, every internal value will be copied, so access of nested properties can be slow - if you expect the data to be read-only or not propagated into another place, set Options=[dvoValueCopiedByReference] or using _ObjFast() will increase the process speed a lot
procedure _ObjAddProp(const Name: RawUtf8; const Value: TDocVariantData; var Obj: variant); overload;
Add a document property value to a document-based object content
procedure _ObjAddProp(const Name: RawUtf8; const Value: variant; var Obj: variant); overload;
Add a property value to a document-based object content
- if Obj is a TDocVariant object, will add the Name/Value pair
- if Obj is not a TDocVariant, will create a new fast document, initialized with supplied the Name/Value pairs
- this function will also ensure that ensure Obj is not stored by reference, but as a true TDocVariantData
procedure _ObjAddProps(const Document: variant; var Obj: variant); overload;
Add the property values of a document to a document-based object content
- if Document is not a TDocVariant object, will do nothing
- if Obj is a TDocVariant object, will add Document fields to its content
- if Obj is not a TDocVariant object, Document will be copied to Obj
procedure _ObjAddProps(const NameValuePairs: array of const; var Obj: variant); overload;
Add some property values to a document-based object content
- if Obj is a TDocVariant object, will add the Name/Value pairs
- if Obj is not a TDocVariant, will create a new fast document, initialized with supplied the Name/Value pairs
- this function will also ensure that ensure Obj is not stored by reference, but as a true TDocVariantData
procedure _ObjAddPropU(const Name: RawUtf8; const Value: RawUtf8; var Obj: variant);
Add a RawUtf8 property value to a document-based object content
function _ObjFast(aObject: TObject; aOptions: TTextWriterWriteObjectOptions = [woDontStoreDefault]): variant; overload;
Initialize a variant instance to store any object as a TDocVariant
- is a wrapper around ObjectToVariant(aObject, result, aOptions)
function _ObjFast(const NameValuePairs: array of const): variant; overload;
Initialize a variant instance to store some document-based object content
- this global function is an handy alias to:
Obj(NameValuePairs, JSON_FAST);
- so all created objects and arrays will be handled by reference, for best speed - but you should better write on the resulting variant tree with caution
function _Safe(const DocVariant: variant; out DV: PDocVariantData): boolean; overload;
Direct access to a TDocVariantData from a given variant instance
- return true and set DocVariant with a pointer to the TDocVariantData corresponding to the variant instance, which may be of kind varByRef (e.g. when retrieved by late binding)
- return false if the supplied Value is not a TDocVariant, but e.g. a string, a number or another type of custom variant
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData
function _Safe(const DocVariant: variant; ExpectedKind: TDocVariantKind): PDocVariantData; overload;
Delphi has problems inlining this :( direct access to a TDocVariantData from a given variant instance
- return a pointer to the TDocVariantData corresponding to the variant instance, which may be of kind varByRef (e.g. when retrieved by late binding)
- will check the supplied document kind, i.e. either dvObject or dvArray and raise a EDocVariant exception if it does not match
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData
function _Safe(const DocVariant: variant): PDocVariantData; overload;
Direct access to a TDocVariantData from a given variant instance
- return a pointer to the TDocVariantData corresponding to the variant instance, which may be of kind varByRef (e.g. when retrieved by late binding)
- will return a read-only fake TDocVariantData with Kind=dvUndefined if the supplied variant is not a TDocVariant instance, so could be safely used in a with block (use "with" moderation, of course):
with _Safe(aDocVariant)^ do for ndx := 0 to Count-1 do // here Count=0 for the "fake" result writeln(Names[ndx]);
or excluding the "with" statement, as more readable code:
var dv: PDocVariantData; ndx: PtrInt; begin dv := _Safe(aDocVariant); for ndx := 0 to dv.Count-1 do // here Count=0 for the "fake" result writeln(dv.Names[ndx]);
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData
function _SafeArray(const Value: variant; ExpectedCount: integer; out DV: PDocVariantData): boolean; overload;
Direct access to a TDocVariantData array from a given variant instance
- overload to check for a given number of itemsin the array
function _SafeArray(const Value: variant; out DV: PDocVariantData): boolean; overload;
Direct access to a TDocVariantData array from a given variant instance
- return true and set DV with a pointer to the TDocVariantData corresponding to the variant instance, if it is a dvArray
- return false if the supplied Value is not an array TDocVariant
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData
function _SafeObject(const Value: variant; out DV: PDocVariantData): boolean;
Direct access to a TDocVariantData object from a given variant instance
- return true and set DV with a pointer to the TDocVariantData corresponding to the variant instance, if it is a dvObject
- return false if the supplied Value is not an object TDocVariant
- note: due to a local variable lifetime change in Delphi 11, don't use this function with a temporary variant (e.g. from TList<variant>.GetItem) - call _DV() and a local TDocVariantData instead of a PDocVariantData
procedure _Unique(var DocVariant: variant);
Ensure a document-based variant instance will have only per-value nested objects or array documents
- is just a wrapper around:
TDocVariantData(DocVariant).InitCopy(DocVariant, JSON_[mDefault])
- you can use this function to ensure that all internal properties of this variant will be copied per-value whatever options the nested objects or arrays were created with
- for huge document with a big depth of nested objects or arrays, a full per-value copy may be time and resource consuming, but will be also safe
- will raise an EDocVariant if the supplied variant is not a TDocVariant or a varByRef pointing to a TDocVariant
procedure _UniqueFast(var DocVariant: variant);
Ensure a document-based variant instance will have only per-value nested objects or array documents
- is just a wrapper around:
TDocVariantData(DocVariant).InitCopy(DocVariant, JSON_FAST)
- you can use this function to ensure that all internal properties of this variant will be copied per-reference whatever options the nested objects or arrays were created with
- for huge document with a big depth of nested objects or arrays, it will first create a whole copy of the document nodes, but further assignments of the resulting value will be per-reference, so will be almost instant
- will raise an EDocVariant if the supplied variant is not a TDocVariant or a varByRef pointing to a TDocVariant
DocAnyDefaultModel: TDocVariantModel = mFastFloat;
Default TDocVariant model for IDocList/IDocDict
DocVariantType: TDocVariant;
The internal custom variant type used to register TDocVariant
DocVariantVType: cardinal;
Copy of DocVariantType.VarType
- as used by inlined functions of TDocVariantData
DV_FAST: array[TDocVariantKind] of TVarData;
Defined here for inlining - properly filled in initialization section below
JSON_: array[TDocVariantModel] of TDocVariantOptions = ( [], [dvoReturnNullForUnknownProperty], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoAllowDoubleValue], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoJsonParseDoNotTryCustomVariants], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoSerializeAsExtendedJson], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoSerializeAsExtendedJson, dvoJsonParseDoNotTryCustomVariants, dvoInternNames, dvoInternValues], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoNameCaseSensitive], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoNameCaseSensitive, dvoSerializeAsExtendedJson], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoNameCaseSensitive, dvoInternNames, dvoInternValues], [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoNameCaseSensitive, dvoInternNames, dvoInternValues, dvoSerializeAsExtendedJson] );
Some convenient TDocVariant options, e.g. as JSON_[fDefault]
JSON_FAST_EXTENDED: TDocVariantOptions;
TDocVariant options to be used so that JSON serialization would use the unquoted JSON syntax for field names
- you could use it e.g. on a TOrm variant published field to reduce the JSON escape process during storage in the database, by customizing your TOrmModel instance:
(aModel.Props[TOrmMyRecord]['VariantProp'] as TOrmPropInfoRttiVariant). DocVariantOptions := JSON_FAST_EXTENDED;
or - in a cleaner way - by overriding TOrm.InternalDefineModel():
class procedure TOrmMyRecord.InternalDefineModel(Props: TOrmProperties); begin (Props.Fields.ByName('VariantProp') as TOrmPropInfoRttiVariant). DocVariantOptions := JSON_FAST_EXTENDED; end;
or to set all variant fields at once:
class procedure TOrmMyRecord.InternalDefineModel(Props: TOrmProperties); begin Props.SetVariantFieldsDocVariantOptions(JSON_FAST_EXTENDED); end;
- consider using JSON_NAMEVALUE[true] for case-sensitive TSynNameValue-like storage, or JSON_FAST_EXTENDEDINTERN if you expect RawUtf8 names and values interning
JSON_FAST_EXTENDEDINTERN: TDocVariantOptions;
TDocVariant options for JSON serialization with efficient storage
- i.e. unquoted JSON syntax for field names and RawUtf8 interning
- may be used e.g. for efficient persistence of similar data
- consider using JSON_FAST_EXTENDED if you don't expect RawUtf8 names and values interning, or need BSON variants parsing
JSON_FAST_STRICT: TDocVariantOptions;
TDocVariant options which may be used for plain JSON parsing
- this won't recognize any extended syntax
JSON_NAMEVALUE: TDocVariantOptionsBool;
TDocVariant options to be used for case-sensitive TSynNameValue-like storage, with optional extended JSON syntax serialization
- consider using JSON_FAST_EXTENDED for case-insensitive objects
JSON_NAMEVALUEINTERN: TDocVariantOptionsBool;
TDocVariant options to be used for case-sensitive TSynNameValue-like storage, RawUtf8 interning and optional extended JSON syntax serialization
- consider using JSON_FAST_EXTENDED for case-insensitive objects, or JSON_NAMEVALUE[] if you don't expect names and values interning
JSON_OPTIONS: TDocVariantOptionsBool;
- JSON_OPTIONS[false] is e.g. _Json() and _JsonFmt() functions default
- JSON_OPTIONS[true] are used e.g. by _JsonFast() and _JsonFastFmt() functions
- handle only currency for floating point values: use JSON_FAST_FLOAT/JSON_[mFastFloat] if you want to support double values, with potential precision loss
JSON_OPTIONS_FAST_STRICT: TDocVariantOptions absolute JSON_FAST_STRICT;
Some slightly more verbose backward compatible options
SynVariantTypes: array of TSynInvokeableVariantType;
Internal list of our TSynInvokeableVariantType instances
- SynVariantTypes[0] is always DocVariantVType
- SynVariantTypes[1] is e.g. BsonVariantType from mormot.db.nosql.bson
- instances are owned by Variants.pas as TInvokeableVariantType instances
- is defined here for proper FindSynVariantType inlining