Search code examples
httpprologswi-prolog

How to query prolog database from prolog webpage?


I'm using swipl. I'm trying to query the parts.pl database file below from a web page, but I'm not sure how to post the query and have it "query" the database and return those results.

I.e., what I'm expecting to be able to do is enter a query as I would on the swipl command line such as 'part(jeep, 100, A, B).' and have the same results returned to me on the page.

Can anyone give a bit of guidance on how to do this. Here's what I've got so far.

:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/http_error)).
:- use_module(library(http/html_write)).
:- use_module(library(http/http_client)).

:- use_module(parts).

:- http_handler('/', my_query_form, []).

server(Port) :-
    http_server(http_dispatch, [port(Port)]).

my_query_form(Request) :-
    reply_html_page(
        my_style,
        [title('My Test')],
        [\page_content(Request)]).

page_content(_Request) -->
    html(
        [
        form([action='/landing', method='POST'], [
            p([], [
                label([for=model], 'Model '),
                input([name=model, type=textarea])
                    ]),
            p([], [
                label([for=major], 'Major '),
                input([name=major, type=textarea])
                    ]),
            p([], [
                label([for=minor], 'Minor '),
                input([name=part, type=textarea])
                    ]),
            p([], input([name=submit, type=submit, value='Search'], []))
        ])]).

:- http_handler('/landing', landing_pad, []).

landing_pad(Request) :-
    member(method(post), Request), !,
    http_read_data(Request, Data, []),
    format('Content-type: text/html~n~n', []),
    format('<p>', []),
    portray_clause(Data),
    format('</p<p>=======~n', []),
    portray_clause(Request),
    format('</p>').

:- multifile
    user:body//2.

user:body(my_style, Body) -->
    html(body([
        div(id(top), h3('Parts Query')),
        div(id(beta), p(i('(beta)'))),
        div(id(content), Body)
        ])).

This is my parts.pl file.

:- module(parts,[part/4]).
% part(model, major, minor, description).
part(jeep, 100, 1000, 'description of 100-1000').
part(jeep, 100, 1001, 'description of 100-1001').
part(jeep, 100, 1002, 'description of 100-1002').
part(jeep, 101, 1000, 'description of 101-1000').
part(jeep, 101, 1001, 'description of 101-1001').
part(jeep, 101, 1002, 'description of 101-1002').
part(ford, 101, 1000, 'description of 101-1000').

Update: (my latest which actually does query, but returns the entire database)

landing_pad(Request) :-
    member(method(post), Request), !,
    http_read_data(Request, Data, []),
    format('Content-type: text/html~n~n', []),    
    format('<p>', []),
    memberchk(model=Model, Data),
    findall(p(Model, Major, Minor, Description),
        part(Model, Major, Minor, Description), Descriptions),
    maplist(description, Descriptions),
    format('</p>').   

description(p(M,A,I,D)) :- format("~q ~q:~q - ~q</br>", [M,A,I,D]).

Solution

  • You are extremely close.

    All that remains is to actually query your database with the components that were specified. I give you part of this querying, and leave filling out the rest as an exercise:

    landing_pad(Request) :-
        member(method(post), Request), !,
        http_read_data(Request, Data, []),
        format('Content-type: text/html~n~n', []),
        format('<p>', []),
        memberchk(model=Model, Data),
        findall(p(Major,Description), part(Model, Major, _, Description), Descriptions),
        maplist(description, Descriptions),
        format('</p>').
    

    I have highlighted the new parts in bold.

    The findall/3 collects all matching parts. In this case, only the Model component is used from the form data. You can fill out the rest.

    To show the descriptions, you can use for example:

    description(p(M,D)) :- format("<p>~q: ~q</p>\n", [M,D]). 
    

    as the definition of description/1.

    Hint: Note the use of the ~q format specifier. It makes debugging a lot easier. You will see what I mean if you add the additional features as part of the query, because you need to distinguish between integers and atoms.