From eb7154d8979f5ba533b9512de4f5d1a6672d9b25 Mon Sep 17 00:00:00 2001 From: Trevi Awater Date: Sat, 2 Mar 2024 08:34:22 +0100 Subject: [PATCH] Fix --- .../CustomRenderers/QueryEditorRenderer.cs | 26 ++++++++ .../Xamarin.Neo4j/Controls/QueryEditor.cs | 7 ++ .../Controls/QueryResultView.xaml.cs | 2 +- .../Xamarin.Neo4j/Models/QueryResult.cs | 2 + .../Xamarin.Neo4j/Pages/SessionPage.xaml | 6 +- .../Xamarin.Neo4j/Pages/SessionPage.xaml.cs | 12 ++-- .../Xamarin.Neo4j/Services/Neo4jService.cs | 2 + .../Xamarin.Neo4j/Utilities/QueryHelper.cs | 66 +++++++++++++++++++ 8 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Utilities/QueryHelper.cs diff --git a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j.iOS/CustomRenderers/QueryEditorRenderer.cs b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j.iOS/CustomRenderers/QueryEditorRenderer.cs index 5041dc2..cb566ca 100644 --- a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j.iOS/CustomRenderers/QueryEditorRenderer.cs +++ b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j.iOS/CustomRenderers/QueryEditorRenderer.cs @@ -7,6 +7,7 @@ // © Xamarin.Neo4j.iOS // +using CoreGraphics; using UIKit; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; @@ -18,6 +19,31 @@ namespace Xamarin.Neo4j.iOS.CustomRenderers { public class QueryEditorRenderer : EditorRenderer { + protected override void OnElementChanged(ElementChangedEventArgs e) + { + base.OnElementChanged(e); + if (Control != null && Element != null) + { + var executeButton = new UIBarButtonItem("Execute", UIBarButtonItemStyle.Done, (sender, args) => + { + if (Element is QueryEditor queryEditor) + { + queryEditor.RaiseExecuteClicked(); + + Control.ResignFirstResponder(); + } + }); + + var toolbar = new UIToolbar(new CGRect(0.0f, 0.0f, Control.Frame.Size.Width, 44.0f)); + toolbar.Items = new[] + { + new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace), + executeButton + }; + + Control.InputAccessoryView = toolbar; + } + } } } diff --git a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Controls/QueryEditor.cs b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Controls/QueryEditor.cs index b6867c4..ba645ef 100644 --- a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Controls/QueryEditor.cs +++ b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Controls/QueryEditor.cs @@ -16,6 +16,8 @@ namespace Xamarin.Neo4j.Controls { public double MaxHeight { get; set; } + public event EventHandler ExecuteClicked; + protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint) { var sizeRequest = base.OnMeasure(widthConstraint, heightConstraint); @@ -27,5 +29,10 @@ namespace Xamarin.Neo4j.Controls return new SizeRequest(new Size(sizeRequest.Request.Width, newHeight)); } + + public void RaiseExecuteClicked() + { + ExecuteClicked?.Invoke(this, EventArgs.Empty); + } } } diff --git a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Controls/QueryResultView.xaml.cs b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Controls/QueryResultView.xaml.cs index 8c312aa..d879192 100644 --- a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Controls/QueryResultView.xaml.cs +++ b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Controls/QueryResultView.xaml.cs @@ -62,7 +62,7 @@ namespace Xamarin.Neo4j.Controls result = result.Replace("{{password}}", QueryResult.ConnectionString.Password); result = result.Replace("{{encryption}}", isEncrypted ? "ENCRYPTION_ON" : "ENCRYPTION_OFF"); result = result.Replace("{{trust}}", ignoreTrust ? "TRUST_ALL_CERTIFICATES" : "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES"); - result = result.Replace("{{query}}", QueryResult.Query); + result = result.Replace("{{query}}", QueryResult.DisplayQuery); result = result.Replace("{{backgroundColor}}", App.Current.RequestedTheme == OSAppTheme.Dark ? "#292C31" : "#FFFFFF"); _neovisHtml = result; diff --git a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Models/QueryResult.cs b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Models/QueryResult.cs index ea2955d..29638d9 100644 --- a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Models/QueryResult.cs +++ b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Models/QueryResult.cs @@ -25,6 +25,8 @@ namespace Xamarin.Neo4j.Models public string ErrorMessage { get; set; } public string Query { get; set; } + + public string DisplayQuery { get; set; } public Neo4jConnectionString ConnectionString { get; set; } diff --git a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Pages/SessionPage.xaml b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Pages/SessionPage.xaml index 5a6b43d..85d91d2 100644 --- a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Pages/SessionPage.xaml +++ b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Pages/SessionPage.xaml @@ -36,18 +36,18 @@ - + - + - + diff --git a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Pages/SessionPage.xaml.cs b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Pages/SessionPage.xaml.cs index 6cb7668..16ba20e 100644 --- a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Pages/SessionPage.xaml.cs +++ b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Pages/SessionPage.xaml.cs @@ -1,9 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - using Xamarin.Forms; using Xamarin.Forms.Xaml; using Xamarin.Neo4j.Models; @@ -15,6 +10,8 @@ namespace Xamarin.Neo4j.Pages [XamlCompilation(XamlCompilationOptions.Compile)] public partial class SessionPage : ContentPage { + private bool _canCompleteEntry = true; + private SessionViewModel ViewModel => (SessionViewModel) BindingContext; public SessionPage(Neo4jConnectionString connectionString, string initialQuery = null) @@ -38,5 +35,10 @@ namespace Xamarin.Neo4j.Pages { ViewModel.DeleteQueryResult(e.Data); } + + private void ExecuteQuery(object sender, EventArgs e) + { + ViewModel.Commands["ExecuteQuery"].Execute(null); + } } } diff --git a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Services/Neo4jService.cs b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Services/Neo4jService.cs index 1c5bd2d..e1f499b 100644 --- a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Services/Neo4jService.cs +++ b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Services/Neo4jService.cs @@ -16,6 +16,7 @@ using Neo4jClient.Cypher; using Xamarin.Forms; using Xamarin.Neo4j.Models; using Xamarin.Neo4j.Services; +using Xamarin.Neo4j.Utilities; [assembly: Dependency(typeof(Neo4jService))] @@ -151,6 +152,7 @@ namespace Xamarin.Neo4j.Services Success = true, CanDisplayGraph = canDisplayGraph, Query = query, + DisplayQuery = QueryHelper.TransformQuery(query), ConnectionString = connectionString, Results = results }; diff --git a/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Utilities/QueryHelper.cs b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Utilities/QueryHelper.cs new file mode 100644 index 0000000..5ac132e --- /dev/null +++ b/Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Utilities/QueryHelper.cs @@ -0,0 +1,66 @@ +// +// QueryHelper.cs +// +// Trevi Awater +// 02-03-2024 +// +// © Xamarin.Neo4j +// + +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace Xamarin.Neo4j.Utilities +{ + public static class QueryHelper + { + public static string TransformQuery(string query) + { + // Check if there is a return statement, if not return the original query + if (query.IndexOf("RETURN ", StringComparison.OrdinalIgnoreCase) <= 0) + return query; + + // This pattern is designed to match relationships with and without labels. + // It captures the relationship direction and type, but not the existing label (if any). + const string pattern = @"-\[:?(\w+)?\]->"; + var matches = Regex.Matches(query, pattern); + + // Keep track of unique relationships to ensure they are returned + var relationships = new List(); + var relationshipCounter = 1; + + var transformedQuery = query; + + foreach (Match match in matches) + { + var newLabel = $"display_variable_{relationshipCounter++}"; // Generate a unique label for the relationship + + // Replace the first occurrence of this match in the query with the new labeled version + var oldPattern = match.Value; + var newPattern = oldPattern.Replace("[:", $"[{newLabel}:").Replace("]->", "]->"); + var idx = transformedQuery.IndexOf(oldPattern); + + if (idx != -1) + { + transformedQuery = transformedQuery.Substring(0, idx) + newPattern + transformedQuery.Substring(idx + oldPattern.Length); + } + + relationships.Add(newLabel); + } + + // Construct the new RETURN clause with the added relationships. + if (relationships.Count > 0) + { + // Assuming there's always a RETURN statement to append to. + var returnIndex = transformedQuery.LastIndexOf("RETURN ", StringComparison.OrdinalIgnoreCase); + var returnClause = transformedQuery.Substring(returnIndex + "RETURN ".Length); + var newReturnClause = string.Join(", ", relationships) + ", " + returnClause; + + transformedQuery = transformedQuery.Substring(0, returnIndex) + "RETURN " + newReturnClause; + } + + return transformedQuery; + } + } +}