]> lifelog.hopto.org Git - LifeLog.git/commitdiff
Updated to PerlCBF v.3.2. Various plugin and index changes. 2.7.dev
authorWill Budic <redacted>
Mon, 20 May 2024 06:30:30 +0000 (16:30 +1000)
committerWill Budic <redacted>
Mon, 20 May 2024 06:30:30 +0000 (16:30 +1000)
htdocs/cgi-bin/docs/PerlCNF/Specifications_For_CNF_Data_Tables.md [new file with mode: 0644]
htdocs/cgi-bin/docs/PerlCNF/Specifications_For_CNF_ReadMe.md
htdocs/cgi-bin/images/VS-on-METABOX-42.png
htdocs/cgi-bin/index.cgi
htdocs/cgi-bin/index.cnf
htdocs/cgi-bin/system/modules/CNFMeta.pm
htdocs/cgi-bin/system/modules/CNFParser.pm
htdocs/cgi-bin/system/modules/CNFSQL.pm
htdocs/cgi-bin/system/modules/HTMLIndexProcessorPlugin.pm
htdocs/cgi-bin/system/modules/HTMLProcessorPlugin.pm
htdocs/cgi-bin/system/modules/MarkdownPlugin.pm

diff --git a/htdocs/cgi-bin/docs/PerlCNF/Specifications_For_CNF_Data_Tables.md b/htdocs/cgi-bin/docs/PerlCNF/Specifications_For_CNF_Data_Tables.md
new file mode 100644 (file)
index 0000000..c8198b2
--- /dev/null
@@ -0,0 +1,163 @@
+# Configuration Network File Format Specifications - CNF Data and SQL Document Section
+
+
+<span id="content" class="span-content">This section is part of the main ⇾ [CNF specifications](docs/PerlCNF/Specifications_For_CNF_ReadMe.md)</span>
+
+
+## CNF Data and SQL Document Section
+
+CNF scripted delimited data property, having uniform table data rows.
+The data is converted by default into arrays as rows. If it contains a header (recommended) these becomes the header of the data. A table header will be produced that contains the row's column's information, like name and type specs.
+The table header contains the actual data reference.
+
+This table is and specs are used to access, map and translate the data.
+There is a basic header being created by the parser and placed into its data hash.
+
+Example on how to access the data table of a property.
+
+```Perl
+my $table  = CNFParser->new(...)->data(){'MyDataProperty'};
+my $header = $$table->{header};
+my $lbls   = CNFMeta::_deRefArray(@$$header[0]);
+my $spec   = CNFMeta::_deRefArray(@$$header[3]);
+my $data   = $$table->{data};
+```
+
+## SQL Based CNF Instruction
+>
+> The following reserved words or instructions a data and SQL related.
+<style>
+    .CNF_md_table{
+        background-color: beige;
+        td{
+            border-right: solid black 1px;
+            border-bottom: solid #ab0433 1px;
+        }
+    }
+</style>
+<table class="CNF_md_table">
+ <thead>
+  <tr>
+   <th>Instruction</th>
+   <th>Decription</th>
+  </tr>
+ </thead>
+ <tbody>
+  <tr>
+   <td>DATA</td>
+   <td>CNF scripted delimited data property, expected to have uniform table data rows, where very first is the table header if provided.</td>
+  </tr>
+  <tr>
+   <td>FILE</td>
+   <td>CNF scripted delimited data property is in a separate data file location, from the current script.</td>
+  </tr>
+    <tr>
+   <td>TABLE</td>
+   <td> SQL create Table body statement part. These can unfortunately differ from one database system to another.</td>
+  </tr>
+    <tr>
+   <td>INDEX</td>
+   <td>SQL create Index body. Indexes provide faster and more efficient data searches and updates.</td>
+  </tr>
+    <tr>
+   <td>VIEW</td>
+   <td>SQL create View body. Views provide a faster and narrower snapshot of what can be a lot of data.</td>
+  </tr>
+      <tr>
+   <td>SQL</td>
+   <td>Direct SQL statement without any variable unknowns.</td>
+  </tr>
+    <tr>
+   <td>MIGRATE</td>
+   <td>Same as SQL instruction, but migrations related towards tables and the application version.</td>
+  </tr>
+ </tbody>
+</table>
+
+## CNFMeta SQL Related
+>
+>Meta tags in use are DATA instruction related.
+
+1. Meta for what actions on data and table is required.
+   1. <code>_SQL_PostgreSQL_</code>
+      - Data is to be linked or related to a Postgres SQL Database, default is SQLite.
+      - In cases where the SQL underlining driver is something different from SQLite or Postgres this should be set to true and hope for the best.
+   2. <code>_SQL_TABLE_</code>
+      - Create or link to an SQL Table equivalent.
+   3. <code>AUTO_NUMBERED</code>
+      - ID column is auto numbered from 1-* if an '#' is found as the value.
+   4. <code>_HAS_HEADER_</code>
+      - Specifically instruct first record is the header labels and specs for the columns.
+   5. Column CNF type is optionally placed next to header label, default column type is TEXT.
+      - i.e. <code> `ID _INT_`Name _TEXT_`Entered _DATE_`Active _BOOL_~ </code>
+
+### Table Column CNF Data Types
+
+1. Column Data type are geared towards the CNF data type provision.
+   1. See %CNFMeta::CNF_DATA_TYPES global.
+      - BOOL INT NUMBER DATE TEXT
+   2. The date type is specific in CNF set to an universal date and time stamp of <code>YYY-MM-DD hh:mm:ss</code>.
+   3. Global $CNFMeta::SQL_CNF_VAR_LENGTH = 2024; can be changed to provide for the __TEXT__ limit translation of specified columns for a database. You can expect database errors if inserting texts that is larger than this variable limit
+
+### CNSQL Package
+
+- Accessed as a global instance of CNFParser, it is the SQL based utility for external database interactions.
+- Its actual use is expected to be via a PLUGIN instructed CNF property, to provide driver to be used, credentials and other details.
+- Example method to use it: `my $sql = CNFParser->new()->SQL();`
+- Required method when using tables with a database based storage:`$sql->initDatabase($db, $do_not_auto_synch, $map)`
+- The __DataProcessingPlugin__ provides the concept of processing the scripted data to to CNF table column type conversion.
+  - The parser provided header gets updated by this plugin.
+  - The parsers natural processing mechanism will require all SQL properties in raw form before a plugin is called to process further.
+
+>The following is extract from the original ⇾ <span id="content"> [specifications](docs/PerlCNF/Specifications_For_CNF_ReadMe.md)</span>.
+
+### CNF DATA Instruction
+
+CNF Instructions are parallel with the reserved words. Which means, you can't use these reserved words to replace with your own instruction. This section explains in more detail, what these are, and how are implemented.
+
+1. DATA
+    1. Data is specifically parsed, not requiring quoted strings and isn't delimited by new lines alone.
+    2. Data rows are ended with the __"~"__ delimiter. In the tag body.
+    3. Data columns are delimited with the invert quote __"`"__ (back tick) making the row.
+    4. First column can be taken as the unique and record identity column (UID).
+        1. If no UID is set, or specified with # or, 0, ID is considered to be auto-numbered based on data position plus 1, so not to have zero IDs.
+        2. When UID is specified, an existing previous assigned UID cannot be overridden, therefore can cause duplicates.
+        3. Data processing plugins can be installed to cater and change behavior on this whole concept.
+    5. Data is to be updated in storage if any column other than the UID, has its contents changed in the file.
+       1. This behavior can be controlled by disabling something like an auto file storage update. i.e. during application upgrades. To prevent user set settings to reset to factory defaults.
+       2. The result would then be that database already stored data remains, and only new ones are added. This exercise is out of scope of this specification.
+    6. First row labels the columns and is prefixed to PerlCNF datatype.
+       1. Generic data rows, do not require, but processors and plugins would definitely need it.
+       2. Current known types are, __@__{label} as CNFDateTime, __#__ for number or if in row autonumbering to be applied. Text is default without signifier.
+
+    ```CNF
+        <<MyAliasTable<DATA
+        01`admin`admin@inc.com`Super User~
+        02`chef`chef@inc.com`Bruno Allinoise~
+        03`juicy`sfox@inc.com`Samantha Fox~
+        >>
+    ```
+
+2. FILE
+   1. Expects a file name assigned value, file containing actual further CNF DATA rows instructions, separately.
+   2. The file is expected to be located next to the config file.
+   3. File is to be sequentially buffer read and processed instead as a whole in one go.
+   4. The same principles apply in the file as to the DATA instruction CNF tag format, that is expected to be contained in it.
+
+    ```CNF
+        <<MyItemsTbl<FILE data_my_app.cnf>
+    ```
+
+## CNF Meta Instructions
+
+> Various Meta instructions are available to aid processing and decision making
+
+***
+
+   Document is from project ⇾ <https://lifelog.hopto.org/gitweb/?p=PerlCNF.git>
+
+   An open source application.
+
+   Please refer to this specifications header and item or section points, on any desired clarifications or research/troubleshooting inquires.
+
+<center>Sun Stage - v.1.0 2024</center>
index 5360754317e148f915b4f62052ad945928bdd118..f86a14941af783ba7fe6a83343067325094ca8ba 100644 (file)
@@ -17,7 +17,15 @@ Which is pretty much welcomed and encouraged. As the number of them can be quite
 
 CNF type tags are script based, parsed tags of text, everything else is ignored. DOM based parsed tags, require definitions and are hierarchy specific, path based. Even comments, have specified format. A complete different thing. However, in a CNF file you, can nest and tag, DOM based scripts. But not the other way. DOM based scripts are like HTML, XML. They might scream errors if you place in them CNF stuff.
 
-Quick Jump: [CNF Tag Formats](#cnf-tag-formats)  |  [CNF Collections Formatting](#cnf-collections-formatting) | [Instructions & Reserved Words](#instructions-and-reserved-words) | [Scripted Data Related Instructions](#scripted-data-related-instructions)
+
+
+*Quick Jump* :[
+  *[CNF Tag Formats](#cnf-tag-formats)* |
+  *[CNF Collections Formatting](#cnf-collections-formatting)* |
+  *[Instructions & Reserved Words](#instructions-and-reserved-words)* |
+  *[Scripted Data Related Instructions](#scripted-data-related-instructions)* ]
+  <span id="content" class="span-content">[CNF Data Tables](docs/PerlCNF/Specifications_For_CNF_Data_Tables.md).</span>
+]
 
 ## General CNF Formatting Rules
 
@@ -120,17 +128,22 @@ Quick Jump: [CNF Tag Formats](#cnf-tag-formats)  |  [CNF Collections Formatting]
     4. Reserve anon if present is usually a placeholder, lookup setting, that in contrast if not found there, might rise exceptions from the application using CNF.
 
     ```CNF Example 3:
-                Notice to Admin, following please don't modify in any way! 
-                Start --> { 
+                Notice to Admin, following please don't modify in any way!
+                Start --> {
                 <<^RELEASE>2.3>>
                 <<^REVISION>5>>
-                <<META><DATA>^INIT=1`^RUN=1`^STAGES_EXPECTED=5>> } <-- End 
+                <<META><DATA>^INIT=1`^RUN=1`^STAGES_EXPECTED=5>> } <-- End
     ```
 
 
 ## CNF Tag Formats
 
-Quick Jump: [Introduction](#introduction)  |  [CNF Collections Formatting](#cnf-collections-formatting) | [Instructions & Reserved Words](#instructions-and-reserved-words) | [Scripted Data Related Instructions](#scripted-data-related-instructions)
+*Quick Jump* :[
+    [Introduction](#introduction) |
+    [CNF Collections Formatting](#cnf-collections-formatting) |
+    [Instructions & Reserved Words](#instructions-and-reserved-words) |
+    [Scripted Data Related Instructions](#scripted-data-related-instructions)
+]
 
 ### Property Value Tag
 
@@ -150,7 +163,7 @@ Quick Jump: [Introduction](#introduction)  |  [CNF Collections Formatting](#cnf-
         {value\n...valuen\n}>>>
    ```
 
-### Full Tag 
+### Full Tag
 
 ```CNF
     <<{$sig}{name}<{INSTRUCTION}>
@@ -196,19 +209,19 @@ Quick Jump: [Introduction](#introduction)  |  [CNF Collections Formatting](#cnf-
 
     ```cnf
        <<APP_HELP_TXT<CONST
-       This is your applications help text in format of an constance. 
+       This is your applications help text in format of an constance.
        All you see here can't be dynamically changed.
-       You might be able to change it in the script though. 
+       You might be able to change it in the script though.
        And re-run your app.
-       >>        
+       >>
     ```
 
 4. Example. Tag name mauled:
 
     ```cnf
        <<<CONST
-       $APP_HELP_TXT='This is your applications help text in format of an constance.'       
-       >>        
+       $APP_HELP_TXT='This is your applications help text in format of an constance.'
+       >>
     ```
 
 5. Example. Instruction mauled or being disabled for now:
@@ -216,12 +229,17 @@ Quick Jump: [Introduction](#introduction)  |  [CNF Collections Formatting](#cnf-
     2. Introduced with CNF release v.2.5.
 
     ```cnf
-       <<PWD<>path/to/something>>        
+       <<PWD<>path/to/something>>
     ```
 
 
 ## CNF Collections Formatting
-Quick Jump: [Introduction](#introduction)  | [CNF Tag Formats](#cnf-tag-formats)  | [Instructions & Reserved Words](#instructions-and-reserved-words) | [Scripted Data Related Instructions](#scripted-data-related-instructions)
+*Quick Jump* : [
+    [Introduction](#introduction) |
+    [CNF Tag Formats](#cnf-tag-formats) |
+    [Instructions & Reserved Words](#instructions-and-reserved-words) |
+    [Scripted Data Related Instructions](#scripted-data-related-instructions)
+]
 
 1. CNF collections are named two list types.
    1. Arrays
@@ -253,13 +271,21 @@ Quick Jump: [Introduction](#introduction)  | [CNF Tag Formats](#cnf-tag-formats)
         AppName = "UDP Server"
         port    = 3820
         buffer_size = 1024
-        pool_capacity = 1000    
+        pool_capacity = 1000
     >>
    ```
 
 ## Instructions And Reserved Words
 
-Quick Jump: [Introduction](#introduction)  | [CNF Tag Formats](#cnf-tag-formats)  | [CNF Collections Formatting](#cnf-collections-formatting) | [Scripted Data Related Instructions](#scripted-data-related-instructions)
+<span id="content" class="span-content">
+*Quick Jump* :[
+     [Introduction](#introduction) |
+     [CNF Tag Formats](#cnf-tag-formats) |
+     [CNF Collections Formatting](#cnf-collections-formatting) |
+     [Scripted Data Related Instructions](#scripted-data-related-instructions) |
+      <span id="content" class="span-content">[CNF Data Tables](docs/PerlCNF/Specifications_For_CNF_Data_Tables.md).</span>
+</span>
+]
 
    1. Reserved words relate to instructions, that are specially treated, and interpreted by the parser to perform extra or specifically processing on the current value.
    2. Reserved instructions can't be used for future custom ones, and also not recommended tag or property names.
@@ -286,9 +312,9 @@ Quick Jump: [Introduction](#introduction)  | [CNF Tag Formats](#cnf-tag-formats)
           2. Parsing abruptly stops if this abstract property specified is not found.
           3. Macro format specifications, have been aforementioned in this document. However, make sure that your macro a constant also including the *$* signifier if desired.
 
-## Database and SQL Instruction Formatting
+## Database and SQL Instruction Formatting Rules
 
-(Note - this documentation section not complete, as of 2020-02-14)
+<span id="content" class="rz">This is a separate section of this specification, going more in details about the DATA instruction ⇾ [CNF Data Tables](docs/PerlCNF/Specifications_For_CNF_Data_Tables.md).</span>
 
 ### About
 
@@ -472,7 +498,13 @@ CNF supports basic SQL Database structure statement generation. This is done via
 
 ## Sample Perl Language Usage
 
-Quick Jump: [Introduction](#introduction) | [CNF Collections Formatting](#cnf-collections-formatting) | [Instructions & Reserved Words](#instructions-and-reserved-words) | [Scripted Data Related Instructions](#scripted-data-related-instructions) | [CNF Tag Formats](#cnf-tag-formats)
+*Quick Jump* : [
+ [Introduction](#introduction) |
+ [CNF Collections Formatting](#cnf-collections-formatting) |
+ [Instructions & Reserved Words](#instructions-and-reserved-words) |
+ [Scripted Data Related Instructions](#scripted-data-related-instructions) |
+ [CNF Tag Formats](#cnf-tag-formats)
+]
 
 1. *DO*
    1. CNF DO instruction is *experimental*, purely Perl programming language related.
@@ -537,9 +569,9 @@ $APP_NAME="My Application Sample"
 
 ***
 
-   Document is from project ⇾  <https://github.com/wbudic/PerlCNF/>
+   Document is from project ⇾ <https://lifelog.hopto.org/gitweb/?p=PerlCNF.git>
+   The original project location  ⇾ <https://github.com/wbudic/PerlCNF/>
 
    An open source application.
 
-<center>Sun Stage - v.2.8 2023</center>
-
+<center>Sun Stage - PerlCNF v.3.2 2024</center>
index 7c05de96d94107028dd40839cfe8c5bcee354ec2..709b41c8ed32a4ad31fe39f3d354d0438281a02e 100644 (file)
Binary files a/htdocs/cgi-bin/images/VS-on-METABOX-42.png and b/htdocs/cgi-bin/images/VS-on-METABOX-42.png differ
index 29b12207028332217efa406c3bfa5636be7e8f93..20067e08013e1d79b79ac0557572e8e4a5d3487e 100755 (executable)
@@ -76,6 +76,10 @@ sub listFiles ($){
     my $path = $script_path.$dir;
     my $spec = $GLOB_HTML_SERVE; $spec =~ s/{}/$path/gp;
     my @files = glob ($spec);
+       @files =  sort {
+            ( $a=~m/\w+[_-]*/ eq $b=~m/\w+[_-]*/ && length $a > length $b) ||
+              $a <=> $b
+    }  @files;
     foreach my $file(@files){
             ($file =~ m/(\w+\.\w*)$/g);
             my $name = $1;
@@ -86,6 +90,7 @@ sub listFiles ($){
                 $ret .= qq(\t\t\t<li><a href="$dir/$name">$name</a></li>\n);
             }
     }
+
     return $ret;
 }
 
@@ -109,4 +114,3 @@ EContactHash  : 990MWWLWM8C2MI8K (https://github.com/wbudic/EContactHash.md)
 Source        : https://github.com/wbudic/LifeLog
 Open Source Code License -> https://github.com/wbudic/PerlCNF/blob/master/ISC_License.md
 =cut copyright
-
index d65beab1311bf479256ccee1c00b412415338e13..e1419e8d1707b3048f97d3aa45f7a1b9e124778b 100644 (file)
 
     div#tabs .ui-tabs-anchor {
         padding: .01em 1em;
+        color:black;
     }
     div#tabs ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header, .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover {
     border: 1px solid #050506;
     #menu_page .menu_head a {
         background: rgba(255,255,255,.6)
     }
-
+    .span-content{
+            border: 1px solid black;
+            text-align: left;
+            background-color: #e6ffff;
+            vertical-align: top;
+    }
 
 ]#]
 >STYLE>
@@ -327,22 +333,7 @@ function onIndexBodyLoad(){
     $("#status").html("Index page is ready!").show();
     $("#status").fadeOut(2000);
 
-    $("#content a").click(
-        function(e){
-            e.preventDefault();
-                if(PREV_DIR_ELE){
-                   PREV_DIR_ELE.parentElement.setAttribute("style","");
-                }
-            e.target.parentElement.setAttribute("style","color:  rgb(136, 58, 200); background-color: rgba(244, 241, 241, 0.386); font-size: large;  padding-left:1em;border-radius:15px; text-align:center;");
-            PREV_DIR_ELE = e.target;
-            $("#status").prependTo(e.target.parentElement);
-            $("#status").html("Loading: " + e.target.href).show();
-
-            $.post('index.cgi', {action:'load', doc:e.target.getAttribute('href')}, loadDocResult).fail(
-                    function(response) {$('#doc_display').html("Service Error: "+response.status,response.responseText)}
-            );
-        }
-    );
+    selectIDAnchors();
     $("#content a").prop("visitied",false);
     onBodyLoadGeneric();
 
@@ -351,15 +342,35 @@ function onIndexBodyLoad(){
     });
     $( "#tabs" ).show();
 }
+
 function loadDocResult(content){
     $('#doc_display').html(content);
     $("#status").fadeOut(2000);
-    $(document).scrollTop($("#doc_display").offset().top);
+    $(document).scrollTop($("#content_pane").offset().top);
     if(window.mermaid){
        window.mermaid.run();
     }
+    selectIDAnchors();
     $('#tab_display').click();
 }
+
+function  selectIDAnchors(){
+   $("#content a").click(
+        function(e){
+            e.preventDefault();
+            $("#status").html("Loading: " + e.target.href).show();
+            $("#status").prependTo(e.target.parentElement);
+                if(PREV_DIR_ELE){
+                   PREV_DIR_ELE.parentElement.setAttribute("style","");
+                }
+            e.target.parentElement.setAttribute("style","color:  rgb(136, 58, 200); background-color: rgba(244, 241, 241, 0.386); font-size: large;  padding-left:1em;border-radius:15px; text-align:center;");
+            PREV_DIR_ELE = e.target;
+            $.post('index.cgi', {action:'load', doc:e.target.getAttribute('href')}, loadDocResult).fail(
+                    function(response) {$('#doc_display').html("Service Error: "+response.status,response.responseText)}
+            );
+        }
+    );
+}
 function gotoTabDirListing(){
     $('#tab_dir_listing').click();
 }
@@ -431,7 +442,7 @@ style:"height:100vh"
             style="height:auto;display:none;"
                 <ul<
                 <#<
-                    <li><a id="tab_dir_listing" href="#listing" selected>Dir</a></li>
+                    <li><a id="tab_dir_listing" href="#listing" selected>Directory Listing</a></li>
                     <li><a id="tab_display" href="#display">Display</a></li>
                 >#>
                 >ul>
index e56910fb7d5be3b2464bca36464f7478ca5f732b..3e51030de7ceb744be2ace77b45a42a3513ddfcf 100644 (file)
@@ -28,6 +28,14 @@ sub _meta {
 # Priority order no. for instructions.
 use constant PRIORITY => qr/(\s*\_+PRIORITY\_(\d+)\_+\s*)/o;
 
+###
+# Global, there is possible only four CNF data types.
+our %CNF_DATA_TYPES;#         ^    #   %      @    $ (default)
+BEGIN{my $cnt =0;  foreach(qw{BOOL INT NUMBER DATE TEXT}){$CNF_DATA_TYPES{$_}=++$cnt}}
+###
+# Global setting for SQL TEXT to CNF _TEXT_ specified data type range. Programatically changable.
+our $SQL_CNF_VAR_LENGTH = 2024;
+
 sub import {
     my $caller = caller;    no strict "refs";
     {
@@ -47,12 +55,14 @@ sub import {
          # resulting in unintended placings.
          *{"${caller}::meta_node_in_shortife"} = sub {return _meta("IN_SHORTIFE")};
          # Execute via system shell.
+         *{"${caller}::meta"}  = \&_meta;
          *{"${caller}::SHELL"}  = sub {return _meta("SHELL")};
          # Returns the regular expresion for any of the meta constances.
-         *{"${caller}::meta"}  = \&_meta;
     }
     return 1;
 }
+
+
 ###
 # CNF DATA instruction headers can contain extra expected data type meta info.
 # This will strip them out and build the best expected SQL create table body, based on this meta.
@@ -60,7 +70,7 @@ sub import {
 ###
 sub _metaTranslateDataHeader {
     my $isPostgreSQL = shift;
-    my @array = @_;
+    my @array = @_; my @spec;
     my ($idType,$body,$primary)=('NONE');
     my ($INT,$BOOL,$TEXT,$DATE,$ID, $CNFID, $INDEX) = (
             _meta('INT'),_meta('BOOL'),_meta('TEXT'),_meta('DATE'),
@@ -76,32 +86,41 @@ sub _metaTranslateDataHeader {
                $body   .= "\"$hdr\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n";
             }
             # DB provited sequence, you better don't set this when inserting a record.
+            $spec[$i] = $CNF_DATA_TYPES{INT};
             $idType = 'AUTOINCREMENT'
         }elsif($hdr =~ s/$CNFID/""/ei){
             #This is where CNF provides the ID uinque int value (which doesn't have to be autonumbered i.e. '#', but must be unique).
             $body   .= "\"$hdr\" INTEGER NOT NULL PRIMARY KEY CHECK (\"$hdr\">0),\n";
+            $spec[$i] = $CNF_DATA_TYPES{INT};
             $idType = 'CNF_INDEX'
         }elsif($hdr =~ s/$ID/""/ei){
             #This is ID prefix to some other data id stored in this table, usually one to one/many relationship.
             $body   .= "\"$hdr\" INTEGER CHECK (\"$hdr\">0),\n";
+            $spec[$i] = $CNF_DATA_TYPES{INT};
         }elsif($hdr =~ s/$INDEX/""/ei){
             # This is where CNF instructs to make a indexed lookup type field,
             # for inside database fast selecting, hashing, caching and other queries.
             $body   .= "\"$hdr\" varchar(64) NOT NULL PRIMARY KEY,\n";
+            $spec[$i] = $CNF_DATA_TYPES{TEXT};
         }elsif($hdr =~ s/$INT/""/ei){
             $body   .= "\"$hdr\" INTEGER NOT NULL,\n";
+            $spec[$i] = $CNF_DATA_TYPES{INT};
         }elsif($hdr =~ s/$BOOL/''/ei){
             if($isPostgreSQL){
                $body   .= "\"$hdr\" BOOLEAN NOT NULL,\n";
             }else{
                $body   .= "\"$hdr\" BOOLEAN NOT NULL CHECK (\"$hdr\" IN (0, 1)),\n";
             }
+            $spec[$i] = $CNF_DATA_TYPES{BOOL};
         }elsif($hdr =~ s/$TEXT/""/ei){
-            $body   .= "\"$hdr\" TEXT NOT NULL CHECK (length(\"$hdr\")<=2024),\n";
+            $body   .= "\"$hdr\" TEXT NOT NULL CHECK (length(\"$hdr\")<=$SQL_CNF_VAR_LENGTH),\n";
+            $spec[$i] = $CNF_DATA_TYPES{TEXT};
         }elsif($hdr =~ s/$DATE/""/ei){
             $body   .= "\"$hdr\" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n";
+            $spec[$i] = $CNF_DATA_TYPES{DATE};
         }else{
             $body   .= "\"$hdr\" TEXT NOT NULL,\n";
+            $spec[$i] = $CNF_DATA_TYPES{TEXT};;
         }
         $array[$i] = $hdr;
     }
@@ -110,6 +129,21 @@ sub _metaTranslateDataHeader {
     }else{
         $body =~ s/,$//
     }
-return [\@array,\$body,$idType];
+return \[\@array,\$body,$idType,\@spec];
 }
+
+sub _deRefArray {
+    my $ret = shift;
+
+    if ( ref($ret) eq 'ARRAY' ){
+         my @arr =  @{$ret};
+         if(@arr==1 && ref($arr[0]) eq 'ARRAY'){
+            @arr = @{$arr[0]};
+         }
+         return @arr
+    }
+    return $ret
+}
+
+
 1;
\ No newline at end of file
index 84ea9e1abbd9dc929cedc16d3238a4ef29a08f13..ad42b2ed34f1c94b0a1634b9e114928fa677ff8f 100644 (file)
@@ -19,8 +19,7 @@ require CNFDateTime;
 ##no critic qw(Subroutines::RequireFinalReturn)
 ##no critic Perl::Critic::Policy::ControlStructures::ProhibitMutatingListFunctions
 
-use constant VERSION  => '3.2';
-use constant APPSET   => 'APP_SETTINGS';
+use constant VERSION => '3.2';
 our @files;
 our %lists;
 our %properties;
@@ -93,7 +92,7 @@ sub new { my ($class, $path, $attrs, $del_keys, $self) = @_;
     $self->{RUN_PROCESSORS}  = 1 if not exists $self->{RUN_PROCESSORS}; #By default enabled, disable during script dev.
     # Autoload  the data type properties placed in a separate file, from a FILE instruction.
     $self->{AUTOLOAD_DATA_FILES} =1 if not exists $self->{AUTOLOAD_DATA_FILES};
-    $self->{CNF_VERSION}     = VERSION;
+    $self->{CNF_VERSION}     = VERSION; #Get's overwritten via parsing.
     $self->{__DATA__}        = {};
     undef $SQL;
     bless $self, $class; $self -> parse($path, undef, $del_keys) if($path);
@@ -156,7 +155,7 @@ __JSON
 sub _isTrue{
     my $value = shift;
     return 0 if(not $value);
-    return ($value =~ /1|true|yes|on|t|da/i)
+    return ($value =~ /1|true|yes|on|t|da/i) ? 1:0
 }
 
 ###
@@ -173,8 +172,8 @@ package InstructedDataItem {
         if(exists $counters{$ele}){
            $dataItemCounter = $counters{$ele};
         }else{
-           $dataItemCounter = {aid=>int(0)};
-           $counters{$ele} = $dataItemCounter;
+            $dataItemCounter = {aid=>int(0)};
+            $counters{$ele} = $dataItemCounter;
         }
         bless {
                 ele => $ele,
@@ -331,7 +330,7 @@ sub property { my($self, $name) = @_;
        if($ref eq 'ARRAY'){
           return  @{$ret}
        }elsif($ref eq 'PropertyValueStyle'){
-          return ${$ret->{plugin}} if $ret->{instructor} eq APPSET;
+          return ${$ret->{plugin}} if $ret->{instructor} eq 'APP_SETTINGS';
           return $ret;
        }
        else{
@@ -565,8 +564,8 @@ sub doInstruction { my ($self,$e,$t,$v) = @_;
     elsif($t eq 'MACRO'){
         $instructs{$e}=$v;
     }
-    elsif($t eq 'APPSET'){
-        $self->instructPlugin(InstructedDataItem -> new($e, APPSET, $v));
+    elsif($t eq 'APP_SETTINGS'){
+        $self->instructPlugin(InstructedDataItem -> new($e, 'APP_SETTINGS', $v));
     }
     elsif(exists $instructors{$t}){
         if(not $instructors{$t}->instruct($e, $v) && $self->{STRICT}){
@@ -636,11 +635,24 @@ sub loadDataFile {  my ($self,$e,$path,$v,$i)=@_;
             }
         }
 }
+##
+# DATA instructions are not preserved as CNF script values as would be redundand and a waist.
+# They by default are only META translated into tables for efficiancy by data property name.
 #private
 sub doDataInstruction_{ my ($self,$e,$v,$t,$d)=@_;
         my $add_as_SQLTable = $v =~ s/${meta('SQL_TABLE')}/""/sexi;
         my $isPostgreSQL    = $v =~ s/${meta('SQL_PostgreSQL')}/""/sexi;
-        my $isHeader        = 0;
+        my $isAutonumber    = $v =~ s/${meta('AUTO_NUMBERED')}|${meta('AUTONUMBER')}/""/sexi;
+        my $isHeader        = $v =~ s/${meta('HAS_HEADER')}/""/sexi;
+           $isHeader        = 1 if !$isHeader && ($isAutonumber||$add_as_SQLTable||$isPostgreSQL);
+        my @hdr; my @rows; my $autonumber = 0;
+        my $ref = $self->{__DATA__}{$e};
+        if($ref){
+            $ref = $$ref;
+            @hdr = @{$ref->{header}};
+            @rows= @{$ref->{data}};
+            $autonumber = $ref->{auto}; $isAutonumber = 1 if($autonumber || $isAutonumber);
+        }
         $v=~ s/^\s*//gm;
         foreach my $row(split(/~\s/,$v)){
             my @a;
@@ -654,10 +666,10 @@ sub doDataInstruction_{ my ($self,$e,$v,$t,$d)=@_;
                     $v =  $d;            #capture specked value.
                     $d =~ s/\$$|\s*$//g; #trim any space and system or constant '$' end marker.
                     if($v=~m/\$$/){
-                        $v = $self->{$d};
+                       $v = $self->{$d};
                     }
                     else{
-                        $v = $d;
+                       $v = $d;
                     }
                     $v="" if not $v;
                     push @a, $v;
@@ -665,35 +677,32 @@ sub doDataInstruction_{ my ($self,$e,$v,$t,$d)=@_;
                 else{
                     if($d =~ /^\#(.*)/) {#First is usually ID a number and also '#' signifies number.
                         $d = $1;
-                        $d=0 if !$d; #default to 0 if not specified.
-                        push @a, $d
+                        if(!$d){
+                           if($isAutonumber){ $d= ++$autonumber }else{$d=0}
+                        }
                     }
                     else{
-                        $d="" if not $d;
-                        push @a, $d;
+                        $d="" if $d ne '0' && not $d;
                     }
+                    push @a, $d;
                 }
             }
-            if($add_as_SQLTable){
-                my ($INT,$BOOL,$TEXT,$DATE) = (meta('INT'),meta('BOOL'),meta('TEXT'),meta('DATE'));
-                my $ret = CNFMeta::_metaTranslateDataHeader($isPostgreSQL,@a);
-                my @hdr = @$ret;
-                @a = @{$hdr[0]};
-                $self->SQL()->createTable($e,${$hdr[1]},$hdr[2]);
-                $add_as_SQLTable = 0;$isHeader=1;
-            }
 
-            my $existing = $self->{'__DATA__'}{$e};
-            if(defined $existing){
-                if($isHeader){$isHeader=0;next}
-                my @rows = @$existing;
-                push @rows, [@a] if scalar @a >0;
-                $self->{'__DATA__'}{$e} = \@rows
-            }else{
-                my @rows; push @rows, [@a];
-                $self->{'__DATA__'}{$e} = \@rows if scalar @a >0;
+            if(!@hdr && $isHeader){
+                my $ptr = CNFMeta::_metaTranslateDataHeader($isPostgreSQL,@a);
+                @hdr = @{$$ptr}; $isHeader =  0;
+                $self->SQL()->createTable($e,${$hdr[1]},$hdr[2]) if $add_as_SQLTable
+            }elsif(scalar @a > 0){
+               if($isHeader){
+                  $isHeader =  0;
+               }else{
+                  push @rows, [@a]
+               }
             }
         }
+        my $ret = {name=>$e,header=>\@hdr,data=>\@rows,auto=>$autonumber};
+        $self->{__DATA__}{$e} = \$ret
+
 }
 
 ###
@@ -728,10 +737,14 @@ sub parse {  my ($self, $cnf_file, $content, $del_keys) = @_;
            $self->{CNF_CONTENT} = 'script'
         }
     }
-    $content =~ m/^\!(CNF\d+\.\d+)/;
-    my $CNF_VER = $1; $CNF_VER="Undefined!" if not $CNF_VER;
-    $self->{CNF_VERSION} = $CNF_VER if not defined $self->{CNF_VERSION};
-
+    $content =~ m/^\!(CNF(\d+\.\d+))/;
+    my $CNF_VER = $1;
+    if (not $CNF_VER){
+            $CNF_VER="Undefined!"
+    }elsif(VERSION()<$2){
+        $self->warn("CNF Script version is newer, are you using the latest parser version $CNF_VER?");
+    }
+    $self->{CNF_VERSION} = $CNF_VER;
 
     my $spc =   $content =~ /\n/ ? '(<{2,3}?)(<*.*?>*)(>{2,3})' : '(<{2,3}?)(<*.*?>*?)(>{2,3})$';
     @tags   =  ($content =~ m/$spc/gms);
@@ -743,26 +756,22 @@ sub parse {  my ($self, $cnf_file, $content, $del_keys) = @_;
            my $t = $1;
            my $v = $2;
            if(isReservedWord($self, $t)){
-              my $isAppSts =  ($t eq APPSET);
               my $isVar = ($t eq 'VARIABLE' || $t eq 'VAR');
-              if($t eq 'CONST' or $isVar or $isAppSts){ #multiple values property.
-                my %app_sts;
-                foreach  my $line(split '\n', $v) {
-                    my  $isMETAConst = $line =~ s/$meta_const//se;
+              if($t eq 'CONST' or $isVar){ #constant multiple properties.
+                foreach my $line (split '\n', $v) {
+                     my $isMETAConst = $line =~ s/$meta_const//s;
                         $line =~ s/^\s+|\s+$//;  # strip unwanted spaces
                         $line =~ s/\s*>$//;
                         $line =~ m/([\$\w]*)(\s*=\s*)(.*)/g;
                         my $name = $1;
                            $line = $3; $line =~ s/^\s*(['"])(.*)\g{1}$/$2/ if $line;#strip quotes
                         if(defined $name){
-                            if($isAppSts){
-                               $app_sts{$name} = $line if $line;
-                            }elsif($isVar && not $isMETAConst){
-                                $anons -> {$name} = $line if $line
+                            if($isVar && not $isMETAConst){
+                                 $anons ->{$name} = $line if $line
                             }else{
                                 $name =~ s/^\$// if $isMETAConst;
                                 # It is NOT allowed to overwrite a constant, so check an issue warning.
-                                if(not exists($self->{$name})){
+                                if($line and not $self->{$name}){
                                    $self->{$name} = $line;
                                 }else{ my
                                    $w =  "Skipping and keeping a previously set constance of -> [$name] in ". $self->{CNF_CONTENT}." the new value ";
@@ -771,9 +780,6 @@ sub parse {  my ($self, $cnf_file, $content, $del_keys) = @_;
                             }
                         }
                 }
-                if($isAppSts){
-                   $properties{CNFParser::APPSET} = \%app_sts
-                }
               }else{
                 doInstruction($self,$v,$t,undef);
               }
@@ -1055,7 +1061,7 @@ sub instructPlugin {
     my ($self, $struct) = @_;
     try{
         $properties{$struct->{'ele'}} = doPlugin($self, $struct);
-        $self->log("Plugin instructed ->". $struct->{'ele'});
+        $self->log("CNFParser plugin instructed -> ". $struct->{'ele'});
     }catch($e){
         if($self->{STRICT}){
             CNFParserException->throw(error=>$e);
@@ -1201,7 +1207,7 @@ sub doPlugin {
     my $pck = $plugin->{package};
     my $prp = $plugin->{property};
     my $sub = $plugin->{subroutine};
-    if($instructor eq APPSET){
+    if($instructor eq 'APP_SETTINGS'){
         $pck = 'ClassicAppSettings' if ! $pck;
         ## no critic (RequireBarewordIncludes)
         require "$pck.pm";
@@ -1230,7 +1236,7 @@ sub doPlugin {
            $plugin->{instructor} = $instructor;
            return $plugin;
         }else{
-            die "Sorry, the PLUGIN feature has not been Implemented Yet!"
+            die "Sorry, the PLUGIN in <<".$plugin->{element}.">> feature has failed or not been fully implemented yet!"
         }
     }
     else{
@@ -1431,12 +1437,12 @@ sub dumpENV{
 }
 
 sub  SQL {
+    my ($self,$e,$v) = @_;
     if(!$SQL){##It is late compiled package on demand.
-        my $self = shift;
         my $data = shift;
         require CNFSQL; $SQL  = CNFSQL->new({parser=>$self});
     }
-    $SQL->addStatement(@_) if @_;
+    $SQL->addStatement($e,$v) if $e;
     return $SQL;
 }
 our $JSON;
index e58aa91895439cd2926658fcd45352f1efc0a667..c9b7e877170880005c4bdfaa992d6905d357f9b8 100644 (file)
@@ -13,7 +13,7 @@ use Tie::IxHash;
 
 use constant VERSION => '2.0';
 
-our %tables = (); our %tables_id_type = ();
+our (%tables, %tables_id_type, %tables_data_map);
 our %views  = ();
 our %mig    = ();
 our @sql    = ();
@@ -39,11 +39,13 @@ sub isPostgreSQL{shift; return $isPostgreSQL}
 
 ##
 # Required to be called when using CNF with an database based storage.
-# This subrotine is also a good example why using generic driver is not recomended.
+# This subrotine is also a good example why using generic driver is not recomended.
 # Various SQL db server flavours meta info is def. handled differently and not updated in them.
 #
-# $map - In general is binding of an CNF table to its DATA property, header of the DATA instructed property is self column resolving.
-#        If assinged to an array the first element must contain the name,
+# $map - The synch binding of an CNF TABLE to its CNF DATA property,
+#         a header of the DATA instructed property with a meta  _SQL_TABLE_ tag is self column resolving
+#         based on ID not requiring this mapping now. To better explain, CNF data can have several data properties,
+#         with the map we programatically instruct which on is the right one, per various possible tables?
 #        @TODO 20231018 - Specifications page to be provided with examples for this.
 #
 sub initDatabase { my($self, $db, $do_not_auto_synch, $map, $st) = @_;
@@ -115,6 +117,7 @@ try{
                 }
         }
     }}
+    ###
     # By default we automatically data insert synchronize script with database state on every init.
     # If set $do_not_auto_synch = 1 we skip that if table is present, empty or not,
     # and if has been updated dynamically that is good, what we want. It is of external config. implementation choice.
@@ -179,26 +182,33 @@ try{
         $qinto =~ s/,$//;
         $q =~ s/,$//;
         $ins = $db -> prepare("INSERT INTO $tbl ($qinto)\nVALUES ($q);");
-
-
         my $data = $self->{parser} -> {'__DATA__'};
         if($data){
             my  $data_prp = %$data{$t};
             if(!$data_prp && $self->{data}){
-                $data_prp = %{$self->{data}}{$t};
+                if(%tables_data_map){
+                   $data_prp = %$data{$tables_data_map{$t}};
+                   if(!$data_prp){
+                      $self->{parser} ->error("Invalid data mapping for table $t -> $tables_data_map{$t}")
+                   }
+                }
+                $data_prp = %{$self->{data}}{$t} if !$data_prp;
             }
             if($data_prp){
                 my @hdr;
-                my @rows = @$data_prp;
+                my @header = CNFMeta::_deRefArray($$data_prp->{header}); @header = CNFMeta::_deRefArray($header[0]);
+                my @rows   = CNFMeta::_deRefArray($$data_prp->{data});
                 my $auto_increment=0;
+                for my $i(0 .. $#header){
+                   $hdr[@hdr]={'_'=>$header[$i],'i'=>$i}
+                }
+                $self->{parser} ->error("Header not set for table -> $t") if ! @hdr;
+
             $db->begin_work();
+
                 for my $row_idx (0 .. $#rows){
                     my @col = @{$rows[$row_idx]};
-                    if($row_idx==0){
-                        for my $i(0 .. $#col){
-                            $hdr[@hdr]={'_'=>$col[$i],'i'=>$i}
-                        }
-                    }elsif(@col>0){
+                    if(@col>0){
                         ##
                         #sel tbl section
                         if(@spec){
@@ -259,7 +269,7 @@ try{
                                 }
                              }
                         }
-                        $self->{parser}->log("CNFParser-> Insert into $tbl -> ". join(',', @ins)."\n");
+                        $self->{parser}->log("CNFParser-> Insert into $tbl -> [". join(',', @ins)."]\n");
                         if($auto_increment){
                            $auto_increment--;
                            splice @ins, $auto_increment, 1
@@ -269,7 +279,7 @@ try{
                 }
                 $db->commit()
             }else{
-                $self->{parser}->log("CNFParser-> No data collection is available for $tbl\n");
+                $self->{parser}->log("CNFParser-> No data collection is available or mapped to $tbl\n");
             }
         }else{
             $self->{parser}->log("CNFParser-> No data collection scanned for $tbl\n");
@@ -293,7 +303,7 @@ catch{
 }
 return $self->{parser}-> const('$RELEASE_VER');
 }
-
+###
 sub _connectDB {
     my ($user, $pass, $source, $store, $path) = @_;
     if($path && ! -e $path){
@@ -313,6 +323,17 @@ sub _credentialsToArray{
 }
 
 sub createTable { my ($self, $name, $body, $idType) = @_;
+        if($body =~ s/${CNFMeta::_meta('MAP_TO')}/""/sexi){
+           $body =~ m/\s*(\w*)(.*)/gs;
+           $tables_data_map{$name} = $1;
+           $body = $2;
+        }
+        elsif($body =~ s/${CNFMeta::_meta('MAP_CNF_DB_VIEW')}/""/sexi){
+           $body =~ m/\s*(\w*)(.*)/gs;
+           $tables_data_map{$1} = $2;
+           $tables_id_type{$name} = $idType;
+           return;
+        }
         $tables{$name} = "CREATE TABLE $name(\n$body);";
         $tables_id_type{$name} = $idType;
 }
@@ -339,10 +360,10 @@ sub getStatement { my ($self, $name) = @_;
 sub hasEntry{  my ($sel, $uid) = @_;
     return 0 if !$hasRecords;
     if(ref($uid) eq 'ARRAY'){
-           $sel -> execute(@$uid)
+           $sel -> execute(@$uid+1)
     }else{
            $uid=~s/^["']|['"]$//g;
-           $sel -> execute($uid)
+           $sel -> execute($uid+1)
     }
     my @r=$sel->fetchrow_array();
     return scalar(@r);
index 7b40d093768fa1881dec6994a7c4bdbf041a3831..3bc25bb4bed10c5325bddacd998fb18cdbf7bcf0 100644 (file)
@@ -11,7 +11,7 @@ use Clone qw(clone);
 use CGI;
 use CGI::Session '-ip_match';
 
-use constant VERSION => '1.0';
+use constant VERSION => '1.1';
 
 our $TAB = ' 'x4;
 
@@ -115,7 +115,8 @@ sub loadDocument($self, $parser, $doc) {
     };
     if($doc =~/\.md$/){
         require MarkdownPlugin;
-        my @r = @{MarkdownPlugin->new($self)->parse($slurp)};
+        my $md = MarkdownPlugin->new($self);
+        my @r = @{$md->parse($slurp)};
         return $r[0];
     }
     return \$slurp
index 0380f04128be96d0d6eb486dd79ad6dee081dca7..c087c55763df2e1bc2cbc50456bf1a3278acb942 100644 (file)
@@ -1,5 +1,5 @@
 ###
-# HTML converter Plugin from PerlCNF to HTML from TREE instucted properties.
+# HTML converter Plugin from PerlCNF to HTML from TREE instructed properties.
 # Processing of these is placed in the data parsers data.
 ###
 package HTMLProcessorPlugin;
index 39484d95a9a1e4f65540bc59231d4381bf3b1616..3bed6daf52338e8b4c07b0675c6ee84891467a30 100644 (file)
@@ -80,7 +80,7 @@ try{
 # It is a very complex part of the parsing algorithm routine.
 # This mentioned, here look as the last place to correct any possible translation errors.
 # @CREATED 20230709
-# @TODO possible to be extended ot account for CSS specified bullet types then the HTML default.
+# @TODO possible to be extended to account for CSS specified bullet types then the HTML default.
 ###
 package HTMLListItem {
     sub new{
@@ -230,7 +230,8 @@ try{
                undef $list_root;
                undef $list_item;
             }
-            $buff .= qq(<$h>$title</$h><a name=").scalar(@titels)."\"></a>\n"
+            my $anchor = $title; $anchor =~ s/[_\s+]/-/g; $anchor = lc $anchor;
+            $buff .= qq(<a name="$anchor"></a><$h>$title</$h>\n)
         }
         elsif(!$code &&  ($ln =~ /^(\s*)(\d+)\.\s(.*)/ || $ln =~ /^(\s*)([-+*])\s(.*)/)){
             my $spc = length($1);