--- /dev/null
+# 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>
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
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
{value\n...valuen\n}>>>
```
-### Full Tag
+### Full Tag
```CNF
<<{$sig}{name}<{INSTRUCTION}>
```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:
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
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.
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
## 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.
***
- 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>
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;
$ret .= qq(\t\t\t<li><a href="$dir/$name">$name</a></li>\n);
}
}
+
return $ret;
}
Source : https://github.com/wbudic/LifeLog
Open Source Code License -> https://github.com/wbudic/PerlCNF/blob/master/ISC_License.md
=cut copyright
-
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>
$("#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();
});
$( "#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();
}
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>
# 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";
{
# 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.
###
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'),
$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;
}
}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
##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;
$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);
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
}
###
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,
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{
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}){
}
}
}
+##
+# 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;
$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;
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
+
}
###
$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);
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 ";
}
}
}
- if($isAppSts){
- $properties{CNFParser::APPSET} = \%app_sts
- }
}else{
doInstruction($self,$v,$t,undef);
}
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);
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";
$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{
}
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;
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 = ();
##
# 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 a 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) = @_;
}
}
}}
+ ###
# 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.
$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){
}
}
}
- $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
}
$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");
}
return $self->{parser}-> const('$RELEASE_VER');
}
-
+###
sub _connectDB {
my ($user, $pass, $source, $store, $path) = @_;
if($path && ! -e $path){
}
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;
}
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);
use CGI;
use CGI::Session '-ip_match';
-use constant VERSION => '1.0';
+use constant VERSION => '1.1';
our $TAB = ' 'x4;
};
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
###
-# 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;
# 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{
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);