Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 12/14/18 in Posts

  1. That's not harmful, it's just unnecessary code. What really rustles my jimmies is something like this: try doSomething(); except ShowMessage('There was an error'); end;
  2. If it is the distance you are looking for, I don't think presorting are really faster as calculate the distance direct. from my experience presorting is in the most cases slower. But it depends. If the Data is more or less static then maybe presorting will win. in other cases Use Hypot to calculate the distance. for point in Pointlist do begin dist := Hypot(checkx-point.x, checky-point.y); if dist < checkdist then ..... end; Hypot is very fast You can also use a parallel Loop in this case
  3. Georgge Bakh

    I-Pascal 2.0

    I-Pascal v2.0 has been released. What is I-Pascal? It's a Pascal language support plugin for IntelliJ IDEA. Integration with Delphi and Free Pascal Compiler. The main goal of the project is to provide modern code editing and inspection tool for Pascal language. Dependency cycles ready. In the new release: Completion options from not used yet units (with automatic modification of uses clause) Completion itself is improved and not is comparable to one for Java Delphi 10.3 inline declarations syntax support. Highlighting, find usage, renaming etc. No inherited destructor call inspection Project site: http://siberika.com/ Installation instructions: http://siberika.com/install.htm Source code: https://github.com/casteng/i-pascal
  4. try WriteLicenseData; except on exception do begin raise; Exit; end; end;
  5. It creates a line to place a breakpoint, if you disable stop on exceptions in the debugger.
  6. If anyone has not noticed, the previous structure is, in code, equivalent to: WriteLicenseData;
  7. Very bad idea to use the distance since that involves sqrt. Do the searching with sqr distance and only call sqrt when you have the closest point.
  8. This is obviously a range searching task (https://en.wikipedia.org/wiki/Range_searching) . I'd probably start with something like range tree (https://stackoverflow.com/questions/31121628/finding-all-points-in-certain-radius-of-another-point). Probably a google search like this https://www.google.com/search?q=find+points+in+radius&amp;ie=utf-8&amp;oe=utf-8 will give more hints.
  9. @Lars Fosdal Sorry I cannot help you with it. I tried the attribute [JsonReflectAttribute(ctObject???,rtObject???,TArrayElementInterceptor)] but there is no a converter/reverter type that accepts values of any type: strings, numbers, and objects. Perhaps you may need to create a descendant of TJSONUnMarshal to handle all the options. It would be great if Embarcadero improves JSON support and allow to convert other types to a custom record if this record can take values of other types: type TSwitch = class private FSwitch: Boolean; public property Switch: Boolean read FSwitch write FSwitch; end; TArrayElement = record private FValue: Variant; public class operator Implicit(const Value: Integer): TArrayElement; class operator Implicit(const Value: string): TArrayElement; class operator Implicit(const Value: TSwitch): TArrayElement; end;
  10. I've made some tests a while ago, and put them into an empty, commented region (for later unbury, if I need them). Maybe it helps somehow. class function TJson_Marshal_Base<T>.Internal_FromObject(AValue: TJSONObject ) : TJson_Marshal_Base<T>; var LMar: TJSONUnMarshal; begin Result := nil; if not Assigned( AValue ) then Exit; LMar := TJSONUnMarshal.Create(); // This sets DateTimeIsUTC internally by default try LMar.DateTimeIsUTC := True; // !! Important to ensure same Coding/Decoding {$REGION 'OptionalReverter'} // LMar.RegisterReverter(TToolPanel_Parcel, //TODO remove, since it never gets here // function (Data: TListOfStrings) : TObject // var // LObj : TToolPanel_Parcel; // begin // // if Length(Data) >= 9 then // begin // LObj := TToolPanel_Parcel.Create; // // LObj.FValueType := StrToIntDef(Data[0], -1); // LObj.FValueNum := Data[1]; // LObj.FValueUnit := Data[2]; // LObj.FTimestamp := StrToDateDef( Data[3], 0); // LObj.FTimestampColor := StrToIntDef( Data[4], Integer( TAlphaColorRec.Red )); // LObj.FLine1 := Data[5]; // LObj.FLine2 := Data[6]; // // LObj.FCoord.FromString_Location( Data[7] ); // // LObj.FGeoCode := Data[8]; // // if Length(Data) >= 10 then // LObj.FMultiLine := Data[9] // else // LObj.FMultiLine := ''; // // Result := LObj; // end // else // begin // Result := nil; // end; // // end // // ); {$ENDREGION} //UnMarshal will attempt to create a TTestObject from the TJSONObject data //using RTTI lookup - for that to function, the type MUST be defined in a unit Result := TJson_Marshal_Base<T>.Create; //( AData ); Result := LMar.CreateObject(TJson_Marshal_Base<T>, AValue, Result ) as TJson_Marshal_Base<T>; finally LMar.Free; end; end;
  11. May be TMessageArray = array of array of Variant; ? program TestJson; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, REST.Json; const JsonData = '{' + ' "message": [' + ' [ 0, "a text" ],' + ' [ 1 ],' + ' [ 1, { "switch": true } ],' + ' [ 2, "text one", "text line two" ]' + ' ]' + '}'; type TMessageArray = array of array of Variant; TJsonMessage = class private Fmessage: TMessageArray; public property message: TMessageArray read FMessage write FMessage; end; var Message: TJsonMessage; begin try if TypeInfo(TJsonMessage) = nil then Writeln('No RTTI for ', TJsonMessage.ClassName); Message := TJson.JsonToObject<TJsonMessage>(JsonData); Writeln('Length = ', Length(Message.message)); Message.Free; except on E: Exception do begin Writeln(E.ClassName, ': ', E.Message); Readln; end; end; end. I tried this option, but my test application gives the exception: "Exception class EConversionError with message 'Internal: Cannot instantiate type TestJson.TJsonMessage'.". I still do not understand why.
  12. Hi @Stuart Clennett, it's a bug! 🙂 Thanks for spotting it. The TMARSFireDAC.InjectMacroValues and TMARSFireDAC.InjectParamValues implementations assume every TFDAdaptedDataSet actually has a Command (not nil). TFDMemTable do not have Command assigned. Workaround: if you do not need your memory table to be included as the result of Retrieve method, you can decorate it with the RESTExclude attribute: [RESTExclude] FDMemTable1: TFDMemTable; However, I just fixed this in the "develop" branch of MARS repository: https://github.com/andrea-magni/MARS/commit/b6299926671b00e75981c47a74375d9c51c529ca Another workaround would be to change your copy of TMARSFDDataModuleResource.Retrieve and change this line: if LDataSet is TFDAdaptedDataSet then to this: if (LDataSet is TFDAdaptedDataSet) and Assigned(TFDAdaptedDataSet(LDataset).Command) then The MARS.Data.FireDAC.DataModule has nothing special, it is provided as an example of use, you can copy it, change it... it is obviously the counter-part of a TMARSFDResource but there no direct deal with the specific class, just matter of the shape of its methods (types returned, GET/POST selection, ...). Thanks, Andrea
  13. Andrea Magni

    Custom media type

    Hi @Bjørn Larsen, You have a number of possibilities and I would choose one way or another depending on the actual use case. If you need a single (or just a few) methods to produce application/scim+json content type, I would probably follow the way to let MARS produce standard JSON and then fix the ContentType/ContentEncoding. There's a handy way to do this through the Context attribute (MARS will inject a reference to the Response object you will be able to use it across all the methods you need): [Path('helloworld')] THelloWorldResource = class protected [Context] Response: TWebResponse; // add unit Web.HTTPApp to uses clause public [GET, Produces(TMediaType.APPLICATION_JSON)] function User1: TJSONObject; end; (...) function THelloWorldResource.User1: TJSONObject; begin Result := TJSONObject.Create; Result.WriteStringValue('id', TGUID.NewGuid.ToString); Response.ContentType := 'application/scim+json'; Response.ContentEncoding := 'UTF-8'; end; If you have several methods (in a single resource) that need to produce application/scim+json and you want to generalize this "response patching" one for all, you may take advantage of another MARS functionality: AfterInvoke code execution. It comes in a couple of variations, the first one will let you add a method (PatchResponse) and decorate it in order to have MARS execute it after each request to that resource: [Path('helloworld')] THelloWorldResource = class protected [Context] Response: TWebResponse; public [GET, Produces(TMediaType.APPLICATION_JSON)] function User1: TJSONObject; [AfterInvoke] procedure PatchResponse; end; (...) procedure THelloWorldResource.PatchResponse; begin Response.ContentType := 'application/scim+json'; Response.ContentEncoding := 'UTF-8'; end; function THelloWorldResource.User1: TJSONObject; begin Result := TJSONObject.Create; Result.WriteStringValue('id', TGUID.NewGuid.ToString); end; This way, your User1 (and other) method will not be polluted by the "response patching" and at the same time you have a single copy of the "response patching" code (DRY principle). Another AfterInvoke possibility is to define it at a more general level by calling TMARSActivation.RegisterAfterInvoke: TMARSActivation.RegisterAfterInvoke( procedure (const AActivation: IMARSActivation) begin if AActivation.ResourceInstance is THelloWorldResource then // or whatever other strategy begin AActivation.Response.ContentType := 'application/scim+json'; AActivation.Response.ContentEncoding := 'UTF-8'; end; end ); This has the advantage to be very wide (possibly spanning over each MARS engine/application) and does not require the injection of the Response object at resource level. You can setup your own strategy to determine when it's the case to patch the response or not (i.e. use some custom attribute yourself to decorate resources/methods or check the current ContentType or whatever... the AActivation parameter will provide you a very detailed context over the current MARS activation including Request, Response, selected class, selected method, method return value and so on). These are all "patching" options. There is another option available though: define a new media type. From the example you posted, I can't see if you are returning standard or custom types (i.e. TJSONObject instances or TYourClass instances/records). In both cases you can define a new MBW (MessageBodyWriter) for a new media type (application/scim+json) and have full control over Response generation. It's easy, I am attaching here a unit (MBW.ScimPlusJSON.pas) with a new MBW implementation for application/scim+json that will match any request with a Produces('application/scim+json') attribute and will act the same of the standard JSON MBW with the addition of setting the ContentEncoding of the Response. (ContenType will automatically be set by MARS). Just be sure to include the unit in the uses list of your resources unit or in the Server.Ignition unit. You resource then will look like this: [Path('helloworld')] THelloWorldResource = class protected [Context] Response: TWebResponse; public [GET, Produces(MEDIATYPE_APPLICATION_SCIM_PLUS_JSON)] function User1: TJSONObject; end; (...) function THelloWorldResource.User1: TJSONObject; begin Result := TJSONObject.Create; Result.WriteStringValue('id', TGUID.NewGuid.ToString); end; Hope this helps you to solve your problem and please let me know if something is unclear or you need anything else. Sincerely, Andrea MBW.ScimPlusJSON.pas
  14. Clément

    Detailed logging (for debugging)

    Hi, Why can't you write your log in levels. For example: MyLog.Info('Entering method X'); Mylog.Debug(1, 'Connecting to database'); MyLog.Debug(2, 'Connected to database = '+FDatabase.ConnectionString ); And the constructor Mylog := TMyLog.Create( 0 ); // No Debug information Mylog := TMyLog.Create( 1 ); // Only Debug 1 Mylog := TMyLog.Create( 2 ); // Debug up to level 2. This way you can activate debug using a INI file. [Settings] Debuglevel = 0; // Or 1 or 2 HTH, Clément
×