This commit is contained in:
Trevi Awater
2024-03-02 08:34:22 +01:00
parent aa6fa75136
commit eb7154d897
8 changed files with 114 additions and 9 deletions

View File

@@ -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<Editor> 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;
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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; }

View File

@@ -36,18 +36,18 @@
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout>
<StackLayout VerticalOptions="FillAndExpand">
<pancakeView:PancakeView BackgroundColor="White" CornerRadius="2" Padding="4" Margin="16">
<pancakeView:PancakeView CornerRadius="2">
<pancakeView:PancakeView.Border>
<pancakeView:Border Thickness="2" Color="#d8e5f1" />
</pancakeView:PancakeView.Border>
<controls:QueryEditor Text="{Binding Query}" MaxHeight="200" HorizontalOptions="FillAndExpand" AutoSize="TextChanges" />
<controls:QueryEditor Text="{Binding Query}" ExecuteClicked="ExecuteQuery" MaxHeight="200" HorizontalOptions="FillAndExpand" AutoSize="TextChanges" />
</pancakeView:PancakeView>
</pancakeView:PancakeView>
<CollectionView x:Name="resultsCollection" ItemsSource="{Binding QueryResults}">
<CollectionView x:Name="resultsCollection" ItemsSource="{Binding QueryResults}" VerticalOptions="FillAndExpand">
<CollectionView.ItemTemplate>
<DataTemplate>
<controls:QueryResultView CloseRequested="CloseResultView" />

View File

@@ -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);
}
}
}

View File

@@ -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
};

View File

@@ -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<string>();
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;
}
}
}