From 6864fe02eef9886d6dc0d89b68cb1a51369d5a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 12 Nov 2023 13:47:44 +0100 Subject: [PATCH 01/24] chore: add edition settings --- prqlc/bindings/dotnet/.editorconfig | 175 ++++++++++++++ prqlc/bindings/dotnet/.gitignore | 356 +++++++++++++++++++++++++++- prqlc/bindings/dotnet/README.md | 34 ++- prqlc/bindings/dotnet/prql-logo.png | Bin 0 -> 80276 bytes 4 files changed, 551 insertions(+), 14 deletions(-) create mode 100644 prqlc/bindings/dotnet/.editorconfig create mode 100644 prqlc/bindings/dotnet/prql-logo.png diff --git a/prqlc/bindings/dotnet/.editorconfig b/prqlc/bindings/dotnet/.editorconfig new file mode 100644 index 000000000000..fb783beb72a5 --- /dev/null +++ b/prqlc/bindings/dotnet/.editorconfig @@ -0,0 +1,175 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +root = true + +# Default settings: +# A newline ending every file +# Use 4 spaces as indentation +[*] +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +end_of_line = crlf + +# C# files +[*.cs] +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_switch_labels = true +csharp_indent_labels = one_less_than_current + +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion + +# avoid this. unless absolutely necessary +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion + +# Types: use keywords instead of BCL types, and permit var only when the type is clear +csharp_style_var_for_built_in_types = true:none +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# name all constant fields using PascalCase +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.required_modifiers = const +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +# static fields should have s_ prefix +dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion +dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields +dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style +dotnet_naming_symbols.static_fields.applicable_kinds = none +dotnet_naming_symbols.static_fields.required_modifiers = static +dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected +dotnet_naming_style.static_prefix_style.required_prefix = s_ +dotnet_naming_style.static_prefix_style.capitalization = camel_case + +# internal and private fields should be _camelCase +dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion +dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields +dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_style +dotnet_naming_symbols.private_internal_fields.applicable_kinds = field +dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal +dotnet_naming_style.camel_case_style.capitalization = camel_case + +# Code style defaults +csharp_using_directive_placement = outside_namespace:suggestion +dotnet_sort_system_directives_first = true +csharp_prefer_braces = true:silent +csharp_preserve_single_line_blocks = true:none +csharp_preserve_single_line_statements = false:none +csharp_prefer_static_local_function = true:suggestion +csharp_prefer_simple_using_statement = false:none +csharp_style_prefer_switch_expression = true:suggestion + +# Code quality +dotnet_style_readonly_field = true:suggestion +dotnet_code_quality_unused_parameters = non_public:suggestion + +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:refactoring +dotnet_style_prefer_conditional_expression_over_return = true:refactoring +csharp_prefer_simple_default_expression = true:suggestion + +# Expression-bodied members +csharp_style_expression_bodied_methods = true:silent +csharp_style_expression_bodied_constructors = true:silent +csharp_style_expression_bodied_operators = true:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:refactoring +csharp_style_expression_bodied_local_functions = true:refactoring + +# Pattern matching +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion + +# Null checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Other features +csharp_style_prefer_index_operator = false:none +csharp_style_prefer_range_operator = false:none +csharp_style_pattern_local_over_anonymous_function = false:none + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = do_not_ignore +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = false:suggestion + +# Xml project files +[*.{csproj,props,targets}] +indent_size = 2 +charset = utf-8 \ No newline at end of file diff --git a/prqlc/bindings/dotnet/.gitignore b/prqlc/bindings/dotnet/.gitignore index 1746e3269ed0..2f23fafc5d96 100644 --- a/prqlc/bindings/dotnet/.gitignore +++ b/prqlc/bindings/dotnet/.gitignore @@ -1,2 +1,354 @@ -bin -obj +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Codecod +codecov.exe +.coverage/ \ No newline at end of file diff --git a/prqlc/bindings/dotnet/README.md b/prqlc/bindings/dotnet/README.md index 1f2ca1e28d88..3e621a3f5646 100644 --- a/prqlc/bindings/dotnet/README.md +++ b/prqlc/bindings/dotnet/README.md @@ -1,21 +1,31 @@ # prql-dotnet -`prql-net` offers PRQL bindings for .NET bindings as a `netstandard2.0` library. +`PrqlCompiler` offers PRQL bindings for .NET bindings as `net6.0` and `net7.0` libraries. -It provides the `PrqlCompiler` class which contains the `ToJson` and `ToSql` +It provides the `PrqlCompiler` class which contains the `Compile`, `PrqlToPl`, `PlToRq` and `RqToSql` static methods. -It's still at an early stage, and isn't published to NuGet. Contributions are -welcome. +It's still at an early stage, and isn't published to NuGet. Contributions are welcome. ## Installation -Make sure that `libprqlc.so` (Linux), `libprqlc.dylib` (macOS) or `libprqlc.dll` -(Windows) is in your project's `bin` directory together with `PrqlCompiler.dll` -and the rest of your project's compiled files. I.e. -`{your_project}/bin/Debug/net7.0/`. +Current project and package only handles Windows native library `prqlc.dll`. +Handling of `prqlc.so` (Linux), `prqlc.dylib` (macOS) is work in progress. -The `libprqlc` library gets dynamically imported at runtime. +For consumer of this package, ensure that `prqlc.dll` is in your project's `bin` (i.e. `{your_project}/bin/Debug/net7.0/`) directory +together with `PrqlCompiler.dll` and the rest of your project's compiled files. + +If it's not the case, ensure that you specified a runtime parameter when publishing your project. +I.e. `dotnet publish YourProject.csproj --runtime win-x64 --framework net6.0 -o Publish\net6.0-win-x64` . + +If you're using the package `PrqlCompiler` in a test project, identically, don't forget to specify the runtime. +I.e. `dotnet test YourProject.Tests.csproj --runtime win-x64 --framework net6.0` . + +The list of currently supported runtimes is: + +* win-x64 + +The `prqlc` library gets dynamically imported at runtime ans id not needed at compiled time ## Usage @@ -26,6 +36,7 @@ var options = new PrqlCompilerOptions { Format = false, SignatureComment = false, + Target = "sql.mysql" }; var sql = PrqlCompiler.Compile("from employees", options); Console.WriteLine(sql); @@ -33,6 +44,5 @@ Console.WriteLine(sql); # TODO -This is currently at 0.1.0 because we're waiting to update prqlc-clib for the -latest API. When we've done that, we can match the version here with the broader -PRQL version. +We're waiting to include the build and tests of this package into the GitHub-actions. +When we've done that, we can match the version here with the broader PRQL version. diff --git a/prqlc/bindings/dotnet/prql-logo.png b/prqlc/bindings/dotnet/prql-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..226d9d16c7111f57f86606009ce5f52ad8ca7b80 GIT binary patch literal 80276 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 literal 0 HcmV?d00001 From de796286f9e9160eb57b8b416b13e029af794a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 12 Nov 2023 13:48:56 +0100 Subject: [PATCH 02/24] build: move build settings to props and targets --- prqlc/bindings/dotnet/Directory.Build.props | 71 +++++++++++++++++++ prqlc/bindings/dotnet/Directory.Build.targets | 22 ++++++ .../PrqlCompiler.Tests.csproj | 8 --- .../dotnet/PrqlCompiler/PrqlCompiler.csproj | 36 ++-------- prqlc/bindings/dotnet/prql-net.sln | 19 +++-- 5 files changed, 114 insertions(+), 42 deletions(-) create mode 100644 prqlc/bindings/dotnet/Directory.Build.props create mode 100644 prqlc/bindings/dotnet/Directory.Build.targets diff --git a/prqlc/bindings/dotnet/Directory.Build.props b/prqlc/bindings/dotnet/Directory.Build.props new file mode 100644 index 000000000000..7a92fb71e649 --- /dev/null +++ b/prqlc/bindings/dotnet/Directory.Build.props @@ -0,0 +1,71 @@ + + + + true + false + portable + + + + net6.0;net7.0 + AnyCPU + enable + enable + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + Prql.Compiler + prql-logo.png + PRQL Compiler + PRQL + Copyright ยฉ The PRQL Project 2023 + .NET bindings for the PRQL compiler. PRQL is a modern language for transforming data + Apache-2.0 + https://prql-lang.org/ + README.md + prql;sql + https://github.com/PRQL/prql + git + false + snupkg + + + + + True + \ + + + True + \ + + + + + + $(NoWarn);CS1591 + + + + false + true + + + + 5 + preview + + + + 5 + preview + + + diff --git a/prqlc/bindings/dotnet/Directory.Build.targets b/prqlc/bindings/dotnet/Directory.Build.targets new file mode 100644 index 000000000000..de6b1baaf9bf --- /dev/null +++ b/prqlc/bindings/dotnet/Directory.Build.targets @@ -0,0 +1,22 @@ + + + + + + + + + + + <_Parameter1>%(InternalsVisibleTo.Identity) + + + + + + + <_Parameter1>$(AssemblyName)%(InternalsVisibleToSuffix.Identity) + + + + \ No newline at end of file diff --git a/prqlc/bindings/dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj b/prqlc/bindings/dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj index eeddc9523e9a..63bfc64a6ae4 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj +++ b/prqlc/bindings/dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj @@ -1,13 +1,5 @@ - - net7.0 - enable - enable - - false - - diff --git a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.csproj b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.csproj index 1204677b5cda..3258cc81ee59 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.csproj +++ b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.csproj @@ -1,39 +1,17 @@ - - netstandard2.0 - - - - Prql.Compiler - 0.1.0 - PRQL Compiler - PRQL - Copyright ยฉ The PRQL Project 2023 - .NET bindings for the PRQL compiler. PRQL is a modern language for transforming data - Apache-2.0 - https://prql-lang.org/ - README.md - prql;sql - https://github.com/PRQL/prql - - - - True - \ - + + - - PreserveNewest - - - PreserveNewest - - + + false PreserveNewest + true + \runtimes\win-x64\native + %(FileName)%(Extension) diff --git a/prqlc/bindings/dotnet/prql-net.sln b/prqlc/bindings/dotnet/prql-net.sln index 76842e4e1189..4f4a2d9110d1 100644 --- a/prqlc/bindings/dotnet/prql-net.sln +++ b/prqlc/bindings/dotnet/prql-net.sln @@ -3,18 +3,24 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrqlCompiler", "PrqlCompiler\PrqlCompiler.csproj", "{339EA2A6-23D2-4938-884F-052431AC0674}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PrqlCompiler", "PrqlCompiler\PrqlCompiler.csproj", "{339EA2A6-23D2-4938-884F-052431AC0674}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrqlCompiler.Tests", "PrqlCompiler.Tests\PrqlCompiler.Tests.csproj", "{78C1AD08-6FF5-444E-9298-385887ABAA80}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PrqlCompiler.Tests", "PrqlCompiler.Tests\PrqlCompiler.Tests.csproj", "{78C1AD08-6FF5-444E-9298-385887ABAA80}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution items", "{A5DC0D85-61A8-4E32-B5FC-4196CB406F3C}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitignore = .gitignore + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets + README.md = README.md + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {339EA2A6-23D2-4938-884F-052431AC0674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {339EA2A6-23D2-4938-884F-052431AC0674}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -25,4 +31,7 @@ Global {78C1AD08-6FF5-444E-9298-385887ABAA80}.Release|Any CPU.ActiveCfg = Release|Any CPU {78C1AD08-6FF5-444E-9298-385887ABAA80}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection EndGlobal From b9d82c3751904bcbcbe913ad1e614419ff0a850d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 12 Nov 2023 13:52:00 +0100 Subject: [PATCH 03/24] refactor: improve function descriptions and exception messages --- .../dotnet/PrqlCompiler/PrqlCompiler.cs | 33 ++++--------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs index 66dcdd0775ac..73aa7e44b6ac 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs @@ -18,9 +18,7 @@ public static class PrqlCompiler public static Result Compile(string prqlQuery) { if (string.IsNullOrEmpty(prqlQuery)) - { - throw new ArgumentException(nameof(prqlQuery)); - } + throw new ArgumentException("PRQL query cannot be null or empty.", nameof(prqlQuery)); var options = new PrqlCompilerOptions(); @@ -34,19 +32,11 @@ public static Result Compile(string prqlQuery) /// PRQL compiler options. /// SQL query. /// is null or empty. - /// is null. /// cannot be compiled. public static Result Compile(string prqlQuery, PrqlCompilerOptions options) { if (string.IsNullOrEmpty(prqlQuery)) - { - throw new ArgumentException(nameof(prqlQuery)); - } - - if (options is null) - { - throw new ArgumentException(nameof(options)); - } + throw new ArgumentException("PRQL query cannot be null or empty.", nameof(prqlQuery)); var nativeOptions = new NativePrqlCompilerOptions(options); var nativeResult = CompileExtern(prqlQuery, ref nativeOptions); @@ -66,9 +56,7 @@ public static Result Compile(string prqlQuery, PrqlCompilerOptions options) public static Result PrqlToPl(string prqlQuery) { if (string.IsNullOrEmpty(prqlQuery)) - { - throw new ArgumentException(nameof(prqlQuery)); - } + throw new ArgumentException("PRQL query cannot be null or empty.", nameof(prqlQuery)); var nativeResult = PrqlToPlExtern(prqlQuery); var result = new Result(nativeResult); @@ -79,7 +67,7 @@ public static Result PrqlToPl(string prqlQuery) /// /// Finds variable references, validates functions calls, determines frames and converts PL to RQ. /// - /// A PRQL query. + /// A PL string in JSON format. /// JSON. /// is null or empty. /// cannot be compiled. @@ -87,9 +75,7 @@ public static Result PrqlToPl(string prqlQuery) public static Result PlToRq(string plJson) { if (string.IsNullOrEmpty(plJson)) - { - throw new ArgumentException(nameof(plJson)); - } + throw new ArgumentException("PL json cannot be null or empty.", nameof(plJson)); var nativeResult = PlToRqExtern(plJson); var result = new Result(nativeResult); @@ -110,14 +96,7 @@ public static Result PlToRq(string plJson) public static Result RqToSql(string rqJson, PrqlCompilerOptions options) { if (string.IsNullOrEmpty(rqJson)) - { - throw new ArgumentException(nameof(rqJson)); - } - - if (options is null) - { - throw new ArgumentException(nameof(options)); - } + throw new ArgumentException("PL json cannot be null or empty.", nameof(rqJson)); var nativeOptions = new NativePrqlCompilerOptions(options); var nativeResult = RqToSqlExtern(rqJson, ref nativeOptions); From bc12ed93523f702a7f06d17792b7f1a95a1db207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 12 Nov 2023 13:52:30 +0100 Subject: [PATCH 04/24] fix: update name of the native dll to import --- prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs index 73aa7e44b6ac..8eb2fb03909d 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs @@ -105,16 +105,16 @@ public static Result RqToSql(string rqJson, PrqlCompilerOptions options) return result; } - [DllImport("libprqlc", EntryPoint = "compile")] + [DllImport("prqlc", EntryPoint = "compile", CharSet = CharSet.Ansi)] private static extern NativeResult CompileExtern(string prqlQuery, ref NativePrqlCompilerOptions options); - [DllImport("libprqlc", EntryPoint = "prql_to_pl")] + [DllImport("prqlc", EntryPoint = "prql_to_pl", CharSet = CharSet.Ansi)] private static extern NativeResult PrqlToPlExtern(string prqlQuery); - [DllImport("libprqlc", EntryPoint = "pl_to_rq")] + [DllImport("prqlc", EntryPoint = "pl_to_rq", CharSet = CharSet.Ansi)] private static extern NativeResult PlToRqExtern(string plJson); - [DllImport("libprqlc", EntryPoint = "rq_to_sql")] + [DllImport("prqlc", EntryPoint = "rq_to_sql", CharSet = CharSet.Ansi)] private static extern NativeResult RqToSqlExtern(string rqJson, ref NativePrqlCompilerOptions options); } } From 2f85dc07b40984fc19b57f407ed6033fd24d492b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 12 Nov 2023 13:56:39 +0100 Subject: [PATCH 05/24] refactor: make PrqlCompilerOptions immutable --- .../dotnet/PrqlCompiler/PrqlCompilerOptions.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompilerOptions.cs b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompilerOptions.cs index 4b827e91073f..3420a0f901b0 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompilerOptions.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompilerOptions.cs @@ -6,24 +6,25 @@ namespace Prql.Compiler /// Compilation options for SQL backend of the compiler. /// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public class PrqlCompilerOptions - { + public record struct PrqlCompilerOptions + ( /// /// Pass generated SQL string trough a formatter that splits it into /// multiple lines and prettifies indentation and spacing. /// /// Defaults to true. - public bool Format { get; set; } = true; + bool Format = true, /// /// Target and dialect to compile to. /// - public string Target { get; set; } + string Target = "", /// /// Emits the compiler signature as a comment after generated SQL. /// /// Defaults to true. - public bool SignatureComment { get; set; } = true; - } + bool SignatureComment = true + ) + { } } From eca84f5155c9a89f77724cecd0b1bd3eaed4e647 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 12 Nov 2023 13:16:15 +0000 Subject: [PATCH 06/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- prqlc/bindings/dotnet/.editorconfig | 2 +- prqlc/bindings/dotnet/.gitignore | 2 +- prqlc/bindings/dotnet/Directory.Build.props | 2 +- prqlc/bindings/dotnet/Directory.Build.targets | 2 +- prqlc/bindings/dotnet/README.md | 38 +++++++++++-------- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/prqlc/bindings/dotnet/.editorconfig b/prqlc/bindings/dotnet/.editorconfig index fb783beb72a5..6b3a9426d28e 100644 --- a/prqlc/bindings/dotnet/.editorconfig +++ b/prqlc/bindings/dotnet/.editorconfig @@ -172,4 +172,4 @@ csharp_style_prefer_primary_constructors = false:suggestion # Xml project files [*.{csproj,props,targets}] indent_size = 2 -charset = utf-8 \ No newline at end of file +charset = utf-8 diff --git a/prqlc/bindings/dotnet/.gitignore b/prqlc/bindings/dotnet/.gitignore index 2f23fafc5d96..f1e7fbc4887c 100644 --- a/prqlc/bindings/dotnet/.gitignore +++ b/prqlc/bindings/dotnet/.gitignore @@ -351,4 +351,4 @@ MigrationBackup/ # Codecod codecov.exe -.coverage/ \ No newline at end of file +.coverage/ diff --git a/prqlc/bindings/dotnet/Directory.Build.props b/prqlc/bindings/dotnet/Directory.Build.props index 7a92fb71e649..9abd58d9224d 100644 --- a/prqlc/bindings/dotnet/Directory.Build.props +++ b/prqlc/bindings/dotnet/Directory.Build.props @@ -47,7 +47,7 @@ \ - + $(NoWarn);CS1591 diff --git a/prqlc/bindings/dotnet/Directory.Build.targets b/prqlc/bindings/dotnet/Directory.Build.targets index de6b1baaf9bf..bedf09ca8c08 100644 --- a/prqlc/bindings/dotnet/Directory.Build.targets +++ b/prqlc/bindings/dotnet/Directory.Build.targets @@ -19,4 +19,4 @@ - \ No newline at end of file + diff --git a/prqlc/bindings/dotnet/README.md b/prqlc/bindings/dotnet/README.md index 3e621a3f5646..40b69007fad7 100644 --- a/prqlc/bindings/dotnet/README.md +++ b/prqlc/bindings/dotnet/README.md @@ -1,31 +1,38 @@ # prql-dotnet -`PrqlCompiler` offers PRQL bindings for .NET bindings as `net6.0` and `net7.0` libraries. +`PrqlCompiler` offers PRQL bindings for .NET bindings as `net6.0` and `net7.0` +libraries. -It provides the `PrqlCompiler` class which contains the `Compile`, `PrqlToPl`, `PlToRq` and `RqToSql` -static methods. +It provides the `PrqlCompiler` class which contains the `Compile`, `PrqlToPl`, +`PlToRq` and `RqToSql` static methods. -It's still at an early stage, and isn't published to NuGet. Contributions are welcome. +It's still at an early stage, and isn't published to NuGet. Contributions are +welcome. ## Installation Current project and package only handles Windows native library `prqlc.dll`. -Handling of `prqlc.so` (Linux), `prqlc.dylib` (macOS) is work in progress. +Handling of `prqlc.so` (Linux), `prqlc.dylib` (macOS) is work in progress. -For consumer of this package, ensure that `prqlc.dll` is in your project's `bin` (i.e. `{your_project}/bin/Debug/net7.0/`) directory -together with `PrqlCompiler.dll` and the rest of your project's compiled files. +For consumer of this package, ensure that `prqlc.dll` is in your project's `bin` +(i.e. `{your_project}/bin/Debug/net7.0/`) directory together with +`PrqlCompiler.dll` and the rest of your project's compiled files. -If it's not the case, ensure that you specified a runtime parameter when publishing your project. -I.e. `dotnet publish YourProject.csproj --runtime win-x64 --framework net6.0 -o Publish\net6.0-win-x64` . +If it's not the case, ensure that you specified a runtime parameter when +publishing your project. I.e. +`dotnet publish YourProject.csproj --runtime win-x64 --framework net6.0 -o Publish\net6.0-win-x64` +. -If you're using the package `PrqlCompiler` in a test project, identically, don't forget to specify the runtime. -I.e. `dotnet test YourProject.Tests.csproj --runtime win-x64 --framework net6.0` . +If you're using the package `PrqlCompiler` in a test project, identically, don't +forget to specify the runtime. I.e. +`dotnet test YourProject.Tests.csproj --runtime win-x64 --framework net6.0` . The list of currently supported runtimes is: -* win-x64 +- win-x64 -The `prqlc` library gets dynamically imported at runtime ans id not needed at compiled time +The `prqlc` library gets dynamically imported at runtime ans id not needed at +compiled time ## Usage @@ -44,5 +51,6 @@ Console.WriteLine(sql); # TODO -We're waiting to include the build and tests of this package into the GitHub-actions. -When we've done that, we can match the version here with the broader PRQL version. +We're waiting to include the build and tests of this package into the +GitHub-actions. When we've done that, we can match the version here with the +broader PRQL version. From 800f541555a3df4180b809282634b1e2296f646d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 22:33:46 +0000 Subject: [PATCH 07/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- prqlc/bindings/dotnet/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/prqlc/bindings/dotnet/README.md b/prqlc/bindings/dotnet/README.md index 3a69cf5d4657..e032087c0761 100644 --- a/prqlc/bindings/dotnet/README.md +++ b/prqlc/bindings/dotnet/README.md @@ -11,8 +11,9 @@ welcome. ## Installation -Current project and package only handles Windows native library `libprqlc_lib.dll`. -Handling of `libprqlc_lib.so` (Linux), `libprqlc_lib.dylib` (macOS) is work in progress. +Current project and package only handles Windows native library +`libprqlc_lib.dll`. Handling of `libprqlc_lib.so` (Linux), `libprqlc_lib.dylib` +(macOS) is work in progress. For consumer of this package, ensure that `prqlc.dll` is in your project's `bin` (i.e. `{your_project}/bin/Debug/net7.0/`) directory together with From ae0aa9f3454cf28cd636e25364edcb4dce9db2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 11:17:27 +0100 Subject: [PATCH 08/24] ci: github-action for building, testing and packaging in .NET --- .github/workflows/test-dotnet.yaml | 29 ++++++++++++++----- .../dotnet/PrqlCompiler/PrqlCompiler.cs | 8 ++--- .../dotnet/PrqlCompiler/PrqlCompiler.csproj | 2 +- prqlc/bindings/dotnet/README.md | 27 +++++++++-------- prqlc/bindings/dotnet/prql-net.sln | 1 + 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index 233cb2bdcf80..32c68eebed4c 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -6,7 +6,7 @@ on: jobs: test: - runs-on: ubuntu-latest + runs-on: windows-2022 steps: - name: ๐Ÿ“‚ Checkout code uses: actions/checkout@v4 @@ -15,11 +15,24 @@ jobs: - name: ๐Ÿ”ง Setup dotnet uses: actions/setup-dotnet@v3 with: - dotnet-version: 7 - - name: ๐Ÿงช Build and test - working-directory: prqlc/bindings + dotnet-version: | + 6 + 7 + - name: ๐Ÿ› ๏ธ Build + working-directory: prqlc/bindings/dotnet run: | - dotnet build dotnet - cp ../../target/debug/libprqlc_lib.* dotnet/PrqlCompiler/bin/Debug/net*/ - cp ../../target/debug/libprqlc_lib.* dotnet/PrqlCompiler.Tests/bin/Debug/net*/ - dotnet test dotnet + dotnet build prql-net.sln -p:version="%version%" -c Release /p:ContinuousIntegrationBuild=true --nologo + - name: ๐Ÿงช Test + working-directory: prqlc/bindings/dotnet + run: | + dotnet test PrqlCompiler.tests\PrqlCompiler.Tests.csproj -c release --runtime win-x64 --logger GitHubActions /p:CI=true --nologo + - name: ๐Ÿ“ฆ Package + working-directory: prqlc/bindings/dotnet + run: | + dotnet pack PrqlCompiler -p:version="%version%" -c Release --include-symbols /p:CI=true --no-build --nologo + # - name: ๐Ÿšš Publish + # working-directory: prqlc/bindings/dotnet + # run: | + # dotnet nuget push PrqlCompiler/bin/Release/*.nupkg -k $NUGET_AUTH_TOKEN -s https://api.nuget.org/v3/index.json + # env: + # NUGET_AUTH_TOKEN: ${{ secrets.NUGET_TOKEN }} \ No newline at end of file diff --git a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs index e6084ded6402..0dab275d9e68 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs @@ -105,16 +105,16 @@ public static Result RqToSql(string rqJson, PrqlCompilerOptions options) return result; } - [DllImport("libprqlc_lib", EntryPoint = "compile", CharSet = CharSet.Ansi)] + [DllImport("prqlc_lib", EntryPoint = "compile", CharSet = CharSet.Ansi)] private static extern NativeResult CompileExtern(string prqlQuery, ref NativePrqlCompilerOptions options); - [DllImport("libprqlc_lib", EntryPoint = "prql_to_pl", CharSet = CharSet.Ansi)] + [DllImport("prqlc_lib", EntryPoint = "prql_to_pl", CharSet = CharSet.Ansi)] private static extern NativeResult PrqlToPlExtern(string prqlQuery); - [DllImport("libprqlc_lib", EntryPoint = "pl_to_rq", CharSet = CharSet.Ansi)] + [DllImport("prqlc_lib", EntryPoint = "pl_to_rq", CharSet = CharSet.Ansi)] private static extern NativeResult PlToRqExtern(string plJson); - [DllImport("libprqlc_lib", EntryPoint = "rq_to_sql", CharSet = CharSet.Ansi)] + [DllImport("prqlc_lib", EntryPoint = "rq_to_sql", CharSet = CharSet.Ansi)] private static extern NativeResult RqToSqlExtern(string rqJson, ref NativePrqlCompilerOptions options); } } diff --git a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.csproj b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.csproj index e652b0dc9ae9..cd140020247a 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.csproj +++ b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.csproj @@ -6,7 +6,7 @@ - + false PreserveNewest true diff --git a/prqlc/bindings/dotnet/README.md b/prqlc/bindings/dotnet/README.md index e032087c0761..9dc570204268 100644 --- a/prqlc/bindings/dotnet/README.md +++ b/prqlc/bindings/dotnet/README.md @@ -12,28 +12,31 @@ welcome. ## Installation Current project and package only handles Windows native library -`libprqlc_lib.dll`. Handling of `libprqlc_lib.so` (Linux), `libprqlc_lib.dylib` +`prqlc_lib.dll`. Handling of `libprqlc_lib.so` (Linux), `libprqlc_lib.dylib` (macOS) is work in progress. -For consumer of this package, ensure that `prqlc.dll` is in your project's `bin` -(i.e. `{your_project}/bin/Debug/net7.0/`) directory together with -`PrqlCompiler.dll` and the rest of your project's compiled files. +A package published on NuGet [Work in progress], includes the .NET bindings +and the native libraries. -If it's not the case, ensure that you specified a runtime parameter when -publishing your project. I.e. +For developers consuming this package, when publishing your application, +ensure that the native library described above is in your project's `bin` +directory together with `PrqlCompiler.dll` (.NET bindings to the native library) +and the rest of your project's compiled files. If it's not the case, ensure +that you specified a runtime parameter when publishing your project. I.e. `dotnet publish YourProject.csproj --runtime win-x64 --framework net6.0 -o Publish\net6.0-win-x64` . If you're using the package `PrqlCompiler` in a test project, identically, don't -forget to specify the runtime. I.e. +forget to specify the runtime when running your tests or native libraries +won't be copied. I.e. `dotnet test YourProject.Tests.csproj --runtime win-x64 --framework net6.0` . The list of currently supported runtimes is: - win-x64 -The `prqlc` library gets dynamically imported at runtime ans id not needed at -compiled time +The `prqlc_lib` library gets dynamically imported at runtime and is not needed at +compiled time. ## Usage @@ -52,6 +55,6 @@ Console.WriteLine(sql); ## TODO -We're waiting to include the build and tests of this package into the -GitHub-actions. When we've done that, we can match the version here with the -broader PRQL version. +We're currently including the build, test, package and publication of this +package into the GitHub-actions. When we've done that, we can match the +version here with the broader PRQL version. diff --git a/prqlc/bindings/dotnet/prql-net.sln b/prqlc/bindings/dotnet/prql-net.sln index 4f4a2d9110d1..317451eae514 100644 --- a/prqlc/bindings/dotnet/prql-net.sln +++ b/prqlc/bindings/dotnet/prql-net.sln @@ -14,6 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution Directory.Build.props = Directory.Build.props Directory.Build.targets = Directory.Build.targets README.md = README.md + ..\..\..\.github\workflows\test-dotnet.yaml = ..\..\..\.github\workflows\test-dotnet.yaml EndProjectSection EndProject Global From 235951ead75428a499f73acc7283d753c0c9707d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 11:33:39 +0100 Subject: [PATCH 09/24] fix: explicitely run the script setting the version --- .github/workflows/test-dotnet.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index 32c68eebed4c..6b9ea428db1f 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -11,7 +11,14 @@ jobs: - name: ๐Ÿ“‚ Checkout code uses: actions/checkout@v4 - name: ๐Ÿ— Build prqlc-clib - run: cargo build --package prqlc-clib + run: cargo build --package --release prqlc-clib + - name: ๐Ÿ”ข Set version + - run: ./.github/workflows/scripts/set_version.sh + - name: ๐Ÿœ Debug CI/CD + shell: pwsh + run: | + Write-Host "Version: $env:version" + Get-ChildItem ./target/release/ - name: ๐Ÿ”ง Setup dotnet uses: actions/setup-dotnet@v3 with: From bada233ec17a827bc3dd49e0ad8d3f49e1f5ddad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 11:44:09 +0100 Subject: [PATCH 10/24] fix: syntax issue --- .github/workflows/test-dotnet.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index 6b9ea428db1f..9b6480e34ad9 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -13,7 +13,7 @@ jobs: - name: ๐Ÿ— Build prqlc-clib run: cargo build --package --release prqlc-clib - name: ๐Ÿ”ข Set version - - run: ./.github/workflows/scripts/set_version.sh + run: ./.github/workflows/scripts/set_version.sh - name: ๐Ÿœ Debug CI/CD shell: pwsh run: | From fe70d3a3d348e1c5ee9f36ebedeedc78bb96cb6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 12:01:34 +0100 Subject: [PATCH 11/24] fix: cargo invocation --- .github/workflows/test-dotnet.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index 9b6480e34ad9..900649de8614 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -11,7 +11,7 @@ jobs: - name: ๐Ÿ“‚ Checkout code uses: actions/checkout@v4 - name: ๐Ÿ— Build prqlc-clib - run: cargo build --package --release prqlc-clib + run: cargo build --package prqlc-clib --release - name: ๐Ÿ”ข Set version run: ./.github/workflows/scripts/set_version.sh - name: ๐Ÿœ Debug CI/CD From e67b2c795b96199bdc84d44db9cb1ebd4d60844e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 12:47:08 +0100 Subject: [PATCH 12/24] fix: new attempt --- .github/workflows/test-dotnet.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index 900649de8614..50b4c0ce6606 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -14,7 +14,9 @@ jobs: run: cargo build --package prqlc-clib --release - name: ๐Ÿ”ข Set version run: ./.github/workflows/scripts/set_version.sh - - name: ๐Ÿœ Debug CI/CD + - name: ๐Ÿœ Debug CI/CD (version) + run: echo $version + - name: ๐Ÿœ Debug CI/CD (version + target/release) shell: pwsh run: | Write-Host "Version: $env:version" From ab7045466624d4613d3cb368c65541b5f6e9656b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 13:02:39 +0100 Subject: [PATCH 13/24] fix: finally understood that default shell is powershell :-/ --- .github/workflows/test-dotnet.yaml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index 50b4c0ce6606..ce00e217ab31 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -13,9 +13,9 @@ jobs: - name: ๐Ÿ— Build prqlc-clib run: cargo build --package prqlc-clib --release - name: ๐Ÿ”ข Set version - run: ./.github/workflows/scripts/set_version.sh - - name: ๐Ÿœ Debug CI/CD (version) - run: echo $version + run: | + $version = cargo metadata --format-version=1 --no-deps | jq --raw-output '.packages[] | select(.name == "prql-compiler") | .version' + echo "version=$version" >> $env:GITHUB_ENV - name: ๐Ÿœ Debug CI/CD (version + target/release) shell: pwsh run: | @@ -29,16 +29,19 @@ jobs: 7 - name: ๐Ÿ› ๏ธ Build working-directory: prqlc/bindings/dotnet + shell: cmd run: | dotnet build prql-net.sln -p:version="%version%" -c Release /p:ContinuousIntegrationBuild=true --nologo - name: ๐Ÿงช Test working-directory: prqlc/bindings/dotnet + shell: cmd run: | dotnet test PrqlCompiler.tests\PrqlCompiler.Tests.csproj -c release --runtime win-x64 --logger GitHubActions /p:CI=true --nologo - name: ๐Ÿ“ฆ Package working-directory: prqlc/bindings/dotnet + shell: cmd run: | - dotnet pack PrqlCompiler -p:version="%version%" -c Release --include-symbols /p:CI=true --no-build --nologo + dotnet pack PrqlCompiler -p:version="$version" -c Release --include-symbols /p:CI=true --no-build --nologo # - name: ๐Ÿšš Publish # working-directory: prqlc/bindings/dotnet # run: | From 4357236461f8ef4f045f02e96441ae23bcd04e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 13:20:32 +0100 Subject: [PATCH 14/24] style: switch to file-scoped namespace --- .../dotnet/PrqlCompiler.Tests/CompilerTest.cs | 2 +- prqlc/bindings/dotnet/PrqlCompiler/Message.cs | 79 ++++--- .../dotnet/PrqlCompiler/MessageKind.cs | 35 ++- .../PrqlCompiler/NativePrqlCompilerOptions.cs | 23 +- .../dotnet/PrqlCompiler/NativeResult.cs | 13 +- .../dotnet/PrqlCompiler/PrqlCompiler.cs | 221 +++++++++--------- .../PrqlCompiler/PrqlCompilerOptions.cs | 47 ++-- prqlc/bindings/dotnet/PrqlCompiler/Result.cs | 51 ++-- .../dotnet/PrqlCompiler/SourceLocation.cs | 43 ++-- prqlc/bindings/dotnet/PrqlCompiler/Span.cs | 29 ++- 10 files changed, 267 insertions(+), 276 deletions(-) diff --git a/prqlc/bindings/dotnet/PrqlCompiler.Tests/CompilerTest.cs b/prqlc/bindings/dotnet/PrqlCompiler.Tests/CompilerTest.cs index 5d7fdf1e1e91..1a97b6cadc26 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler.Tests/CompilerTest.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler.Tests/CompilerTest.cs @@ -2,7 +2,7 @@ namespace Prql.Compiler.Tests; -sealed public class CompilerTest +public sealed class CompilerTest { [Fact] public void ToCompile_Works() diff --git a/prqlc/bindings/dotnet/PrqlCompiler/Message.cs b/prqlc/bindings/dotnet/PrqlCompiler/Message.cs index d580dd823000..20b07e7c0e96 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/Message.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/Message.cs @@ -1,46 +1,45 @@ using System.Runtime.InteropServices; -namespace Prql.Compiler +namespace Prql.Compiler; + +/// +/// Compile result message. +/// +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] +public struct Message { /// - /// Compile result message. + /// Message kind. Currently only Error is implemented. + /// + public MessageKind Kind { get; set; } + + /// + /// Machine-readable identifier of the error. + /// + public string Code { get; set; } + + /// + /// Plain text of the error. + /// + public string Reason { get; set; } + + /// + /// A list of suggestions of how to fix the error. + /// + public string Hint { get; set; } + + /// + /// Character offset of error origin within a source file. + /// + public Span Span { get; set; } + + /// + /// Annotated code, containing cause and hints. + /// + public string Display { get; set; } + + /// + /// Line and column number of error origin within a source file. /// - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public struct Message - { - /// - /// Message kind. Currently only Error is implemented. - /// - public MessageKind Kind { get; set; } - - /// - /// Machine-readable identifier of the error. - /// - public string Code { get; set; } - - /// - /// Plain text of the error. - /// - public string Reason { get; set; } - - /// - /// A list of suggestions of how to fix the error. - /// - public string Hint { get; set; } - - /// - /// Character offset of error origin within a source file. - /// - public Span Span { get; set; } - - /// - /// Annotated code, containing cause and hints. - /// - public string Display { get; set; } - - /// - /// Line and column number of error origin within a source file. - /// - public SourceLocation Location { get; set; } - } + public SourceLocation Location { get; set; } } diff --git a/prqlc/bindings/dotnet/PrqlCompiler/MessageKind.cs b/prqlc/bindings/dotnet/PrqlCompiler/MessageKind.cs index efb0a4cb015f..2958666d88b2 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/MessageKind.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/MessageKind.cs @@ -1,24 +1,23 @@ using System; -namespace Prql.Compiler +namespace Prql.Compiler; + +/// +/// Compile message kind. Currently only Error is implemented. +/// +[Serializable] +public enum MessageKind { /// - /// Compile message kind. Currently only Error is implemented. + /// Error message. + /// + Error, + /// + /// Warning message. + /// + Warning, + /// + /// Lint message. /// - [Serializable] - public enum MessageKind - { - /// - /// Error message. - /// - Error, - /// - /// Warning message. - /// - Warning, - /// - /// Lint message. - /// - Lint - } + Lint } diff --git a/prqlc/bindings/dotnet/PrqlCompiler/NativePrqlCompilerOptions.cs b/prqlc/bindings/dotnet/PrqlCompiler/NativePrqlCompilerOptions.cs index c267e4eeed1e..69dcb25a8a30 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/NativePrqlCompilerOptions.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/NativePrqlCompilerOptions.cs @@ -1,16 +1,15 @@ -namespace Prql.Compiler +namespace Prql.Compiler; + +internal struct NativePrqlCompilerOptions { - internal struct NativePrqlCompilerOptions - { - public bool Format; - public string Target; - public bool SignatureComment; + public bool Format; + public string Target; + public bool SignatureComment; - public NativePrqlCompilerOptions(PrqlCompilerOptions options) - { - Format = options.Format; - Target = options.Target; - SignatureComment = options.SignatureComment; - } + public NativePrqlCompilerOptions(PrqlCompilerOptions options) + { + Format = options.Format; + Target = options.Target; + SignatureComment = options.SignatureComment; } } diff --git a/prqlc/bindings/dotnet/PrqlCompiler/NativeResult.cs b/prqlc/bindings/dotnet/PrqlCompiler/NativeResult.cs index 8902e1ed44e5..b15940ed14c6 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/NativeResult.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/NativeResult.cs @@ -1,13 +1,12 @@ using System; -namespace Prql.Compiler +namespace Prql.Compiler; + +internal struct NativeResult { - internal struct NativeResult - { #pragma warning disable CS0649 // Field is never assigned to - public string Output; - public IntPtr Messages; - public int MessagesLen; + public string Output; + public IntPtr Messages; + public int MessagesLen; #pragma warning restore CS0649 // Field is never assigned to - } } diff --git a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs index 0dab275d9e68..163dab3d46f0 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompiler.cs @@ -1,120 +1,119 @@ using System; using System.Runtime.InteropServices; -namespace Prql.Compiler +namespace Prql.Compiler; + +/// +/// The PRQL compiler transpiles RPQL queries. +/// +public static class PrqlCompiler { /// - /// The PRQL compiler transpiles RPQL queries. + /// Compile a PRQL string into a SQL string. + /// + /// A PRQL query. + /// SQL query. + /// is null or empty. + /// cannot be compiled. + public static Result Compile(string prqlQuery) + { + if (string.IsNullOrEmpty(prqlQuery)) + throw new ArgumentException("PRQL query cannot be null or empty.", nameof(prqlQuery)); + + var options = new PrqlCompilerOptions(); + + return Compile(prqlQuery, options); + } + + /// + /// Compile a PRQL string into a SQL string. + /// + /// A PRQL query. + /// PRQL compiler options. + /// SQL query. + /// is null or empty. + /// cannot be compiled. + public static Result Compile(string prqlQuery, PrqlCompilerOptions options) + { + if (string.IsNullOrEmpty(prqlQuery)) + throw new ArgumentException("PRQL query cannot be null or empty.", nameof(prqlQuery)); + + var nativeOptions = new NativePrqlCompilerOptions(options); + var nativeResult = CompileExtern(prqlQuery, ref nativeOptions); + var result = new Result(nativeResult); + + return result; + } + + /// + /// Build PL AST from a PRQL string. /// - public static class PrqlCompiler + /// A PRQL query. + /// JSON. + /// is null or empty. + /// cannot be compiled. + /// https://docs.rs/prql-compiler/latest/prql_compiler/ir/pl + public static Result PrqlToPl(string prqlQuery) { - /// - /// Compile a PRQL string into a SQL string. - /// - /// A PRQL query. - /// SQL query. - /// is null or empty. - /// cannot be compiled. - public static Result Compile(string prqlQuery) - { - if (string.IsNullOrEmpty(prqlQuery)) - throw new ArgumentException("PRQL query cannot be null or empty.", nameof(prqlQuery)); - - var options = new PrqlCompilerOptions(); - - return Compile(prqlQuery, options); - } - - /// - /// Compile a PRQL string into a SQL string. - /// - /// A PRQL query. - /// PRQL compiler options. - /// SQL query. - /// is null or empty. - /// cannot be compiled. - public static Result Compile(string prqlQuery, PrqlCompilerOptions options) - { - if (string.IsNullOrEmpty(prqlQuery)) - throw new ArgumentException("PRQL query cannot be null or empty.", nameof(prqlQuery)); - - var nativeOptions = new NativePrqlCompilerOptions(options); - var nativeResult = CompileExtern(prqlQuery, ref nativeOptions); - var result = new Result(nativeResult); - - return result; - } - - /// - /// Build PL AST from a PRQL string. - /// - /// A PRQL query. - /// JSON. - /// is null or empty. - /// cannot be compiled. - /// https://docs.rs/prql-compiler/latest/prql_compiler/ir/pl - public static Result PrqlToPl(string prqlQuery) - { - if (string.IsNullOrEmpty(prqlQuery)) - throw new ArgumentException("PRQL query cannot be null or empty.", nameof(prqlQuery)); - - var nativeResult = PrqlToPlExtern(prqlQuery); - var result = new Result(nativeResult); - - return result; - } - - /// - /// Finds variable references, validates functions calls, determines frames and converts PL to RQ. - /// - /// A PL string in JSON format. - /// JSON. - /// is null or empty. - /// cannot be compiled. - /// https://docs.rs/prql-compiler/latest/prql_compiler/ast - public static Result PlToRq(string plJson) - { - if (string.IsNullOrEmpty(plJson)) - throw new ArgumentException("PL json cannot be null or empty.", nameof(plJson)); - - var nativeResult = PlToRqExtern(plJson); - var result = new Result(nativeResult); - - return result; - } - - /// - /// Convert RQ AST into an SQL string. - /// - /// RQ string in JSON format. - /// PRQL compiler options. - /// JSON. - /// is null or empty. - /// is null. - /// cannot be compiled. - /// https://docs.rs/prql-compiler/latest/prql_compiler/ir/rq - public static Result RqToSql(string rqJson, PrqlCompilerOptions options) - { - if (string.IsNullOrEmpty(rqJson)) - throw new ArgumentException("PL json cannot be null or empty.", nameof(rqJson)); - - var nativeOptions = new NativePrqlCompilerOptions(options); - var nativeResult = RqToSqlExtern(rqJson, ref nativeOptions); - var result = new Result(nativeResult); - - return result; - } - - [DllImport("prqlc_lib", EntryPoint = "compile", CharSet = CharSet.Ansi)] - private static extern NativeResult CompileExtern(string prqlQuery, ref NativePrqlCompilerOptions options); - - [DllImport("prqlc_lib", EntryPoint = "prql_to_pl", CharSet = CharSet.Ansi)] - private static extern NativeResult PrqlToPlExtern(string prqlQuery); - - [DllImport("prqlc_lib", EntryPoint = "pl_to_rq", CharSet = CharSet.Ansi)] - private static extern NativeResult PlToRqExtern(string plJson); - - [DllImport("prqlc_lib", EntryPoint = "rq_to_sql", CharSet = CharSet.Ansi)] - private static extern NativeResult RqToSqlExtern(string rqJson, ref NativePrqlCompilerOptions options); + if (string.IsNullOrEmpty(prqlQuery)) + throw new ArgumentException("PRQL query cannot be null or empty.", nameof(prqlQuery)); + + var nativeResult = PrqlToPlExtern(prqlQuery); + var result = new Result(nativeResult); + + return result; } + + /// + /// Finds variable references, validates functions calls, determines frames and converts PL to RQ. + /// + /// A PL string in JSON format. + /// JSON. + /// is null or empty. + /// cannot be compiled. + /// https://docs.rs/prql-compiler/latest/prql_compiler/ast + public static Result PlToRq(string plJson) + { + if (string.IsNullOrEmpty(plJson)) + throw new ArgumentException("PL json cannot be null or empty.", nameof(plJson)); + + var nativeResult = PlToRqExtern(plJson); + var result = new Result(nativeResult); + + return result; + } + + /// + /// Convert RQ AST into an SQL string. + /// + /// RQ string in JSON format. + /// PRQL compiler options. + /// JSON. + /// is null or empty. + /// is null. + /// cannot be compiled. + /// https://docs.rs/prql-compiler/latest/prql_compiler/ir/rq + public static Result RqToSql(string rqJson, PrqlCompilerOptions options) + { + if (string.IsNullOrEmpty(rqJson)) + throw new ArgumentException("PL json cannot be null or empty.", nameof(rqJson)); + + var nativeOptions = new NativePrqlCompilerOptions(options); + var nativeResult = RqToSqlExtern(rqJson, ref nativeOptions); + var result = new Result(nativeResult); + + return result; + } + + [DllImport("prqlc_lib", EntryPoint = "compile", CharSet = CharSet.Ansi)] + private static extern NativeResult CompileExtern(string prqlQuery, ref NativePrqlCompilerOptions options); + + [DllImport("prqlc_lib", EntryPoint = "prql_to_pl", CharSet = CharSet.Ansi)] + private static extern NativeResult PrqlToPlExtern(string prqlQuery); + + [DllImport("prqlc_lib", EntryPoint = "pl_to_rq", CharSet = CharSet.Ansi)] + private static extern NativeResult PlToRqExtern(string plJson); + + [DllImport("prqlc_lib", EntryPoint = "rq_to_sql", CharSet = CharSet.Ansi)] + private static extern NativeResult RqToSqlExtern(string rqJson, ref NativePrqlCompilerOptions options); } diff --git a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompilerOptions.cs b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompilerOptions.cs index 3420a0f901b0..7c9e35f38dcf 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompilerOptions.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/PrqlCompilerOptions.cs @@ -1,30 +1,29 @@ using System.Runtime.InteropServices; -namespace Prql.Compiler -{ +namespace Prql.Compiler; + +/// +/// Compilation options for SQL backend of the compiler. +/// +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] +public record struct PrqlCompilerOptions +( /// - /// Compilation options for SQL backend of the compiler. + /// Pass generated SQL string trough a formatter that splits it into + /// multiple lines and prettifies indentation and spacing. /// - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public record struct PrqlCompilerOptions - ( - /// - /// Pass generated SQL string trough a formatter that splits it into - /// multiple lines and prettifies indentation and spacing. - /// - /// Defaults to true. - bool Format = true, + /// Defaults to true. + bool Format = true, - /// - /// Target and dialect to compile to. - /// - string Target = "", + /// + /// Target and dialect to compile to. + /// + string Target = "", - /// - /// Emits the compiler signature as a comment after generated SQL. - /// - /// Defaults to true. - bool SignatureComment = true - ) - { } -} + /// + /// Emits the compiler signature as a comment after generated SQL. + /// + /// Defaults to true. + bool SignatureComment = true +) +{ } diff --git a/prqlc/bindings/dotnet/PrqlCompiler/Result.cs b/prqlc/bindings/dotnet/PrqlCompiler/Result.cs index 60568751d282..51fd19ed2ec0 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/Result.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/Result.cs @@ -2,37 +2,36 @@ using System.Linq; using System.Runtime.InteropServices; -namespace Prql.Compiler -{ - /// - /// Result of compilation. - /// - public class Result - { - private readonly IReadOnlyCollection _messages; +namespace Prql.Compiler; - internal Result(NativeResult result) - { - Output = result.Output; +/// +/// Result of compilation. +/// +public class Result +{ + private readonly IReadOnlyCollection _messages; - var messages = new List(); + internal Result(NativeResult result) + { + Output = result.Output; - for (var i = 0; i < result.MessagesLen; i++) - { - messages.Add(Marshal.PtrToStructure(result.Messages)); - } + var messages = new List(); - _messages = messages.ToList().AsReadOnly(); + for (var i = 0; i < result.MessagesLen; i++) + { + messages.Add(Marshal.PtrToStructure(result.Messages)); } - /// - /// The compiler output. - /// - public string Output { get; } - - /// - /// Error, warning and lint messages. - /// - public IReadOnlyCollection Messages => _messages; + _messages = messages.ToList().AsReadOnly(); } + + /// + /// The compiler output. + /// + public string Output { get; } + + /// + /// Error, warning and lint messages. + /// + public IReadOnlyCollection Messages => _messages; } diff --git a/prqlc/bindings/dotnet/PrqlCompiler/SourceLocation.cs b/prqlc/bindings/dotnet/PrqlCompiler/SourceLocation.cs index 426c65835def..d3b6d1dd001e 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/SourceLocation.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/SourceLocation.cs @@ -1,31 +1,30 @@ using System.Runtime.InteropServices; -namespace Prql.Compiler +namespace Prql.Compiler; + +/// +/// Location within a source file. +/// +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] +public struct SourceLocation { /// - /// Location within a source file. + /// Start line. /// - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public struct SourceLocation - { - /// - /// Start line. - /// - public int StartLine { get; set; } + public int StartLine { get; set; } - /// - /// Start column. - /// - public int StartCol { get; set; } + /// + /// Start column. + /// + public int StartCol { get; set; } - /// - /// End line. - /// - public int EndLine { get; set; } + /// + /// End line. + /// + public int EndLine { get; set; } - /// - /// End column. - /// - public int EndCol { get; set; } - } + /// + /// End column. + /// + public int EndCol { get; set; } } diff --git a/prqlc/bindings/dotnet/PrqlCompiler/Span.cs b/prqlc/bindings/dotnet/PrqlCompiler/Span.cs index 441347a96390..0bd92cc0b1b7 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler/Span.cs +++ b/prqlc/bindings/dotnet/PrqlCompiler/Span.cs @@ -1,22 +1,21 @@ using System.Runtime.InteropServices; -namespace Prql.Compiler +namespace Prql.Compiler; + +/// +/// Identifier of a location in source. +/// Contains offsets in terms of chars. +/// +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] +public struct Span { /// - /// Identifier of a location in source. - /// Contains offsets in terms of chars. + /// Start offset. /// - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public struct Span - { - /// - /// Start offset. - /// - public int Start { get; set; } + public int Start { get; set; } - /// - /// End offset. - /// - public int End { get; set; } - } + /// + /// End offset. + /// + public int End { get; set; } } From 37658463188d22db8b24db4dd717f317cc63af2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 13:20:46 +0100 Subject: [PATCH 15/24] fix: no clue --- .github/workflows/test-dotnet.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index ce00e217ab31..68097aa59a8b 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -14,7 +14,9 @@ jobs: run: cargo build --package prqlc-clib --release - name: ๐Ÿ”ข Set version run: | - $version = cargo metadata --format-version=1 --no-deps | jq --raw-output '.packages[] | select(.name == "prql-compiler") | .version' + $raw = cargo metadata --format-version=1 --no-deps + Write-Host "version: $raw" + $version = $raw | jq --raw-output '.packages[] | select(.name == "prql-compiler") | .version' echo "version=$version" >> $env:GITHUB_ENV - name: ๐Ÿœ Debug CI/CD (version + target/release) shell: pwsh From 0343340ae7fa9eaf65a285442e18b6962af8948b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 13:34:51 +0100 Subject: [PATCH 16/24] fix: change jq --- .github/workflows/test-dotnet.yaml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index 68097aa59a8b..e9b2f900b16d 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -16,7 +16,7 @@ jobs: run: | $raw = cargo metadata --format-version=1 --no-deps Write-Host "version: $raw" - $version = $raw | jq --raw-output '.packages[] | select(.name == "prql-compiler") | .version' + $version = $raw | jq --raw-output '.packages[0] | .version' echo "version=$version" >> $env:GITHUB_ENV - name: ๐Ÿœ Debug CI/CD (version + target/release) shell: pwsh @@ -32,18 +32,15 @@ jobs: - name: ๐Ÿ› ๏ธ Build working-directory: prqlc/bindings/dotnet shell: cmd - run: | - dotnet build prql-net.sln -p:version="%version%" -c Release /p:ContinuousIntegrationBuild=true --nologo + run: dotnet build prql-net.sln -p:version="%version%" -c Release /p:ContinuousIntegrationBuild=true --nologo - name: ๐Ÿงช Test working-directory: prqlc/bindings/dotnet shell: cmd - run: | - dotnet test PrqlCompiler.tests\PrqlCompiler.Tests.csproj -c release --runtime win-x64 --logger GitHubActions /p:CI=true --nologo + run: dotnet test PrqlCompiler.tests\PrqlCompiler.Tests.csproj -c release --runtime win-x64 --logger GitHubActions /p:CI=true --nologo - name: ๐Ÿ“ฆ Package working-directory: prqlc/bindings/dotnet shell: cmd - run: | - dotnet pack PrqlCompiler -p:version="$version" -c Release --include-symbols /p:CI=true --no-build --nologo + run: dotnet pack PrqlCompiler -p:version="$version" -c Release --include-symbols /p:CI=true --no-build --nologo # - name: ๐Ÿšš Publish # working-directory: prqlc/bindings/dotnet # run: | From c7c6d4facb3152eb7151b3a00671af0a9adaf11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 13:46:19 +0100 Subject: [PATCH 17/24] fix: add reference to GitHubActionsTestLogger --- .github/workflows/test-dotnet.yaml | 1 - .../dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index e9b2f900b16d..d3d2afcb1675 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -15,7 +15,6 @@ jobs: - name: ๐Ÿ”ข Set version run: | $raw = cargo metadata --format-version=1 --no-deps - Write-Host "version: $raw" $version = $raw | jq --raw-output '.packages[0] | .version' echo "version=$version" >> $env:GITHUB_ENV - name: ๐Ÿœ Debug CI/CD (version + target/release) diff --git a/prqlc/bindings/dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj b/prqlc/bindings/dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj index 63bfc64a6ae4..de0fc968f4e3 100644 --- a/prqlc/bindings/dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj +++ b/prqlc/bindings/dotnet/PrqlCompiler.Tests/PrqlCompiler.Tests.csproj @@ -1,6 +1,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + From d60c6354ccd937bc66e86ff6daedbec5ada2811d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 14:22:38 +0100 Subject: [PATCH 18/24] fix: package command for CMD shell --- .github/workflows/test-dotnet.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index d3d2afcb1675..19978eb73e60 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -39,7 +39,7 @@ jobs: - name: ๐Ÿ“ฆ Package working-directory: prqlc/bindings/dotnet shell: cmd - run: dotnet pack PrqlCompiler -p:version="$version" -c Release --include-symbols /p:CI=true --no-build --nologo + run: dotnet pack PrqlCompiler -p:version="%version%" -c Release --include-symbols /p:CI=true --no-build --nologo # - name: ๐Ÿšš Publish # working-directory: prqlc/bindings/dotnet # run: | From edb5735481fa07a8124af60018922ef316f51fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 14:31:03 +0100 Subject: [PATCH 19/24] style: fix trailing spaces reported by linter --- .github/workflows/test-dotnet.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index 19978eb73e60..2df45ac1b1d2 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -11,10 +11,10 @@ jobs: - name: ๐Ÿ“‚ Checkout code uses: actions/checkout@v4 - name: ๐Ÿ— Build prqlc-clib - run: cargo build --package prqlc-clib --release + run: cargo build --package prqlc-clib --release - name: ๐Ÿ”ข Set version run: | - $raw = cargo metadata --format-version=1 --no-deps + $raw = cargo metadata --format-version=1 --no-deps $version = $raw | jq --raw-output '.packages[0] | .version' echo "version=$version" >> $env:GITHUB_ENV - name: ๐Ÿœ Debug CI/CD (version + target/release) From 003c1cd82db010ed7abef996930f43b46b6eb7e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 14:42:10 +0100 Subject: [PATCH 20/24] fix: attemp to make package downloadable to check it --- .github/workflows/test-dotnet.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index 2df45ac1b1d2..b7fb63ea4d34 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -6,7 +6,7 @@ on: jobs: test: - runs-on: windows-2022 + runs-on: windows-latest steps: - name: ๐Ÿ“‚ Checkout code uses: actions/checkout@v4 @@ -40,6 +40,13 @@ jobs: working-directory: prqlc/bindings/dotnet shell: cmd run: dotnet pack PrqlCompiler -p:version="%version%" -c Release --include-symbols /p:CI=true --no-build --nologo + - name: ๐Ÿฑ Archive artifacts + uses: actions/upload-artifact@v3 + with: + name: nuget-packages + path: | + prqlc/bindings/dotnet/PrqlCompiler/bin/Release/*.nupkg + prqlc/bindings/dotnet/PrqlCompiler/bin/Release/*.snupkg # - name: ๐Ÿšš Publish # working-directory: prqlc/bindings/dotnet # run: | From 7bca705739c1ef79b3db49d4e93d72ee6a56d881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 14:57:43 +0100 Subject: [PATCH 21/24] style: prettier test-dotnet.yaml --- .github/workflows/test-dotnet.yaml | 32 ++++++++++++++++++------------ 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index b7fb63ea4d34..277b1b4d2581 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -14,42 +14,48 @@ jobs: run: cargo build --package prqlc-clib --release - name: ๐Ÿ”ข Set version run: | - $raw = cargo metadata --format-version=1 --no-deps - $version = $raw | jq --raw-output '.packages[0] | .version' - echo "version=$version" >> $env:GITHUB_ENV + $raw = cargo metadata --format-version=1 --no-deps + $version = $raw | jq --raw-output '.packages[0] | .version' + echo "version=$version" >> $env:GITHUB_ENV - name: ๐Ÿœ Debug CI/CD (version + target/release) shell: pwsh run: | - Write-Host "Version: $env:version" - Get-ChildItem ./target/release/ + Write-Host "Version: $env:version" + Get-ChildItem ./target/release/ - name: ๐Ÿ”ง Setup dotnet uses: actions/setup-dotnet@v3 with: dotnet-version: | - 6 - 7 + 6 + 7 - name: ๐Ÿ› ๏ธ Build working-directory: prqlc/bindings/dotnet shell: cmd - run: dotnet build prql-net.sln -p:version="%version%" -c Release /p:ContinuousIntegrationBuild=true --nologo + run: + dotnet build prql-net.sln -p:version="%version%" -c Release + /p:ContinuousIntegrationBuild=true --nologo - name: ๐Ÿงช Test working-directory: prqlc/bindings/dotnet shell: cmd - run: dotnet test PrqlCompiler.tests\PrqlCompiler.Tests.csproj -c release --runtime win-x64 --logger GitHubActions /p:CI=true --nologo + run: + dotnet test PrqlCompiler.tests\PrqlCompiler.Tests.csproj -c release + --runtime win-x64 --logger GitHubActions /p:CI=true --nologo - name: ๐Ÿ“ฆ Package working-directory: prqlc/bindings/dotnet shell: cmd - run: dotnet pack PrqlCompiler -p:version="%version%" -c Release --include-symbols /p:CI=true --no-build --nologo + run: + dotnet pack PrqlCompiler -p:version="%version%" -c Release + --include-symbols /p:CI=true --no-build --nologo - name: ๐Ÿฑ Archive artifacts uses: actions/upload-artifact@v3 with: name: nuget-packages path: | - prqlc/bindings/dotnet/PrqlCompiler/bin/Release/*.nupkg - prqlc/bindings/dotnet/PrqlCompiler/bin/Release/*.snupkg + prqlc/bindings/dotnet/PrqlCompiler/bin/Release/*.nupkg + prqlc/bindings/dotnet/PrqlCompiler/bin/Release/*.snupkg # - name: ๐Ÿšš Publish # working-directory: prqlc/bindings/dotnet # run: | # dotnet nuget push PrqlCompiler/bin/Release/*.nupkg -k $NUGET_AUTH_TOKEN -s https://api.nuget.org/v3/index.json # env: - # NUGET_AUTH_TOKEN: ${{ secrets.NUGET_TOKEN }} \ No newline at end of file + # NUGET_AUTH_TOKEN: ${{ secrets.NUGET_TOKEN }} From 109282908e010900a1cfde61343e9d7c8cae58a9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 19 Nov 2023 13:57:57 +0000 Subject: [PATCH 22/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- prqlc/bindings/dotnet/README.md | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/prqlc/bindings/dotnet/README.md b/prqlc/bindings/dotnet/README.md index 9dc570204268..3cba4aa3bc63 100644 --- a/prqlc/bindings/dotnet/README.md +++ b/prqlc/bindings/dotnet/README.md @@ -11,32 +11,32 @@ welcome. ## Installation -Current project and package only handles Windows native library -`prqlc_lib.dll`. Handling of `libprqlc_lib.so` (Linux), `libprqlc_lib.dylib` -(macOS) is work in progress. - -A package published on NuGet [Work in progress], includes the .NET bindings -and the native libraries. - -For developers consuming this package, when publishing your application, -ensure that the native library described above is in your project's `bin` -directory together with `PrqlCompiler.dll` (.NET bindings to the native library) -and the rest of your project's compiled files. If it's not the case, ensure -that you specified a runtime parameter when publishing your project. I.e. +Current project and package only handles Windows native library `prqlc_lib.dll`. +Handling of `libprqlc_lib.so` (Linux), `libprqlc_lib.dylib` (macOS) is work in +progress. + +A package published on NuGet [Work in progress], includes the .NET bindings and +the native libraries. + +For developers consuming this package, when publishing your application, ensure +that the native library described above is in your project's `bin` directory +together with `PrqlCompiler.dll` (.NET bindings to the native library) and the +rest of your project's compiled files. If it's not the case, ensure that you +specified a runtime parameter when publishing your project. I.e. `dotnet publish YourProject.csproj --runtime win-x64 --framework net6.0 -o Publish\net6.0-win-x64` . If you're using the package `PrqlCompiler` in a test project, identically, don't -forget to specify the runtime when running your tests or native libraries -won't be copied. I.e. +forget to specify the runtime when running your tests or native libraries won't +be copied. I.e. `dotnet test YourProject.Tests.csproj --runtime win-x64 --framework net6.0` . The list of currently supported runtimes is: - win-x64 -The `prqlc_lib` library gets dynamically imported at runtime and is not needed at -compiled time. +The `prqlc_lib` library gets dynamically imported at runtime and is not needed +at compiled time. ## Usage @@ -56,5 +56,5 @@ Console.WriteLine(sql); ## TODO We're currently including the build, test, package and publication of this -package into the GitHub-actions. When we've done that, we can match the -version here with the broader PRQL version. +package into the GitHub-actions. When we've done that, we can match the version +here with the broader PRQL version. From d7676844b9b7a48b8da19213bb491bcdcb44b2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 16:12:12 +0100 Subject: [PATCH 23/24] refactor: try to use the bash script --- .github/workflows/test-dotnet.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-dotnet.yaml b/.github/workflows/test-dotnet.yaml index 277b1b4d2581..c7a7a0119b40 100644 --- a/.github/workflows/test-dotnet.yaml +++ b/.github/workflows/test-dotnet.yaml @@ -13,10 +13,8 @@ jobs: - name: ๐Ÿ— Build prqlc-clib run: cargo build --package prqlc-clib --release - name: ๐Ÿ”ข Set version - run: | - $raw = cargo metadata --format-version=1 --no-deps - $version = $raw | jq --raw-output '.packages[0] | .version' - echo "version=$version" >> $env:GITHUB_ENV + shell: bash + run: ./.github/workflows/scripts/set_version.sh - name: ๐Ÿœ Debug CI/CD (version + target/release) shell: pwsh run: | From 1bb0ca47467ddc848197048178661a4269eef90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 19 Nov 2023 16:29:17 +0100 Subject: [PATCH 24/24] style: switch end of line to lf to match with .gitignore --- prqlc/bindings/dotnet/.editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prqlc/bindings/dotnet/.editorconfig b/prqlc/bindings/dotnet/.editorconfig index 6b3a9426d28e..ccb0b8371b8e 100644 --- a/prqlc/bindings/dotnet/.editorconfig +++ b/prqlc/bindings/dotnet/.editorconfig @@ -26,7 +26,7 @@ indent_size = 4 trim_trailing_whitespace = true dotnet_style_operator_placement_when_wrapping = beginning_of_line tab_width = 4 -end_of_line = crlf +end_of_line = lf # C# files [*.cs]