couchdb-net icon indicating copy to clipboard operation
couchdb-net copied to clipboard

Views creation via HasViews syntax

Open LoloActemium opened this issue 3 years ago • 5 comments

Hi,

I'm currently using your lib to log OPC/UA events in CouchDB database (and I like it :)). I use your lib because I'm a CouchDB noob and I'm an EF Cpore user on some other projects (using SQL Server as DB). Is there a way to create views within the OnDatabaseCreating(....) function ? An HasView(...) syntax would be nice, but I could find it. Or should I have to implement it myself ?

Kind regards, Laurent.

LoloActemium avatar Aug 17 '21 10:08 LoloActemium

Hi,

thanks for the kind words :)

No there's not even a method to create views normally. This is because views are Javascript functions and since I didn't want to invest in C# to JS I implemented only the reading

matteobortolazzo avatar Aug 17 '21 19:08 matteobortolazzo

Hi, And what about "just" implementing a view creation with Js as simple string ? In a curl fashion, passing the Js in a POST request. Kind Regards, Laurent.

LoloActemium avatar Aug 18 '21 05:08 LoloActemium

We are going to use tooling like this. Maybe you also can consider that approach.

AlexandrSHad avatar Aug 18 '21 15:08 AlexandrSHad

Hello, I implemented it this way (see code below) in my DatabaseContext file. It's based on the lib source code for Login/Logout and GetName.

//Add eventTypes view
var viewDefinition = new View()
{
    Name = "eventTypes",
    Map = "function (doc) {\n  emit(doc.eventTypeName, null);\n}",
    Reduce = "function (keys, values, rereduce) {\n return true;\n}"
};

HasView<ServerEvent>("Events", viewDefinition);

It's enough for me, as it sends an 400 error when the Js code is not well formatted (does not check document properties names, but not a problem for me). I had to copy/adapt some functions because allmost all interesting functions/properties are marked as internal :) I can provide the complete code, if someone is intereted. If I found time, I will try to implement it in the lib itself, and PR it.

HasView function code :

private void HasView<TSource>(string documentName, View viewDefinition)
{
    using (var flurlClient = GetConfiguredClient())
    {
        //Get database name
        var database = typeof(TSource).GetName();

        //Log in to database server
        string cookieToken = LoginAsync(flurlClient).GetAwaiter().GetResult();

        //Trying to get the design document containing the views
        var flurlResponse = flurlClient.Request(_databaseEndpoint).AppendPathSegment($"/{database}/_design/{documentName}")
            .WithCookie("AuthSession", cookieToken)
            .AllowHttpStatus("404")
            .GetAsync().GetAwaiter().GetResult();

        if (flurlResponse.StatusCode == 404)
        {
            //Create new view
            var designDoc = new DesignDocument()
            {
                Language = "javascript",
                Views = new Dictionary<string, View>()
            };
            designDoc.Views.Add(viewDefinition.Name, viewDefinition);

            var test = flurlClient.Request(_databaseEndpoint).AppendPathSegment($"/{database}/_design/{documentName}")
                .WithCookie("AuthSession", cookieToken)
                .AllowHttpStatus("400")
                .PutJsonAsync(designDoc).GetAwaiter().GetResult();

            if (test.StatusCode == 400)
            {
                throw new Exception($"Invalid map or reduce source code in view {documentName}:{viewDefinition.Name}");
            }
        }
        else
        {
            var views = flurlResponse.GetJsonAsync<DesignDocument>().GetAwaiter().GetResult();

            if (!views.Views.ContainsKey(viewDefinition.Name))
            {
                views.Views.Add(viewDefinition.Name, viewDefinition);

                //create view
                var test = flurlClient.Request(_databaseEndpoint).AppendPathSegment($"/{database}/_design/{documentName}")
                    .WithCookie("AuthSession", cookieToken)
                    .AllowHttpStatus("400")
                    .PutJsonAsync(views).GetAwaiter().GetResult();

                if (test.StatusCode == 400)
                {
                    throw new Exception($"Invalid map or reduce source code in view {documentName}:{viewDefinition.Name}");
                }
            }
        }

        LogoutAsync(flurlClient).GetAwaiter().GetResult();
    }
}

Kind regards, Laurent.

LoloActemium avatar Aug 19 '21 13:08 LoloActemium

Hi @LoloActemium ,

yes, I can consider implementing it, it's not a bad idea.

In the meanwhile, you can refactor your code using NewRequest() method in ICouchDatabase as it gives use authentication and the document URL for free.

A you should using async-await if possible

matteobortolazzo avatar Sep 07 '21 19:09 matteobortolazzo