Created
December 18, 2019 10:35
-
-
Save LFReD/53f4054e264773796f578b47017d442b to your computer and use it in GitHub Desktop.
Atomica for Ren-C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Rebol [ | |
Title: "Atomica for Ren-C" | |
Author: "Terry Brownell" | |
File: %atomica.r | |
Version: 0.0.1 | |
Rights: "Copyright (C) 2019 Terry W. Brownell" | |
License: { | |
Distributed under the Apache 2 License | |
See https://www.apache.org/licenses/LICENSE-2.0 | |
} | |
] | |
if not exists? %data/atomica.db [make-dir %data write %data/atomica.db ""] | |
saveit: does [ | |
dbsave: to block! atomica | |
save/all %data/atomica.db dbsave | |
dbsave: copy [] | |
] | |
loadit: does [ | |
atomica: load %data/atomica.db | |
atomica: to-hash atomica | |
] | |
cleanit: func [s1 p1][trim replace/all s1 " " "" trim replace/all p1 " " ""] | |
atomexists?: func [s1 p1 v1][ | |
cleanit s1 p1 | |
v1: trim to-string v1 | |
if find/skip atomica reduce [s1 p1 v1] 3[return true] | |
return false | |
] | |
; --- Insert Atom - creates or updates a unique predicate eg: insertatom "bob" "firstname" "Robert" | |
insertatom: func [s1 p1 v1 /local updated? i i2][ | |
atomica: head atomica | |
cleanit s1 p1 | |
updated?: false | |
v1: trim v1 | |
if series? i: find atomica reduce[s1 p1][i2: index? i i2: i2 + 2 atomica/:i2: v1 updated?: true] | |
if updated? = false [append atomica reduce [s1 p1 v1]] | |
saveit | |
] | |
; --- Insert Atoms - use this for multiple predicates eg: insertaoms "bob" "haspet" "Fido" | |
insertatoms: func [s1 p1 v1 /local is?][ | |
atomica: head atomica | |
cleanit s1 p1 | |
v1: trim to-string v1 | |
is?: atomexists? s1 p1 v1 | |
if is? = false [append atomica reduce [s1 p1 v1] saveit] | |
] | |
; --- Single Value - Returns value of subject and predicate | |
singlev: func [s1 p1 /local sub pred][ | |
atomica: head atomica | |
cleanit s1 p1 | |
if error? try [return third find/skip atomica reduce [s1 p1] 3][return none] | |
] | |
; --- Value of Subject and Predicate | |
vofsandp: func [s1 p1 /local output][ | |
atomica: head atomica | |
cleanit s1 p1 | |
output: copy [] | |
while [not tail? atomica][if all [atomica/1 = s1 atomica/2 = p1 ][append output atomica/3] atomica: skip atomica 3] | |
return output | |
] | |
; --- Subject of Predicate and Value - Returns unique block of all subjects of specific pred and val | |
sofpandv: func [p1 v1 /local output][ | |
atomica: head atomica | |
p1: trim replace/all p1 " " "" | |
v1: trim v1 | |
output: copy [] | |
while [not tail? atomica][if all [atomica/2 = p1 atomica/3 = v1 ][append output atomica/1] atomica: skip atomica 3] | |
return output | |
] | |
; --- Subject of Predicate - Returns block of unique subjects | |
sofp: func [p1 /local output][ | |
atomica: head atomica | |
p1: trim p1: trim replace/all p1 " " "" | |
output: copy [] | |
while [not tail? atomica][if atomica/2 = p1 [append output atomica/1] atomica: skip atomica 3] | |
output: unique output | |
return output | |
] | |
; --- Value of Predicate - Returns block of unique values | |
vofp: func [p1 /local output][ | |
atomica: head atomica | |
p1: trim p1: trim replace/all p1 " " "" | |
output: copy [] | |
while [not tail? atomica][if atomica/2 = p1 [append output atomica/3] atomica: skip atomica 3] | |
output: unique output | |
return output | |
] | |
; --- Delete atom requires the subject, predicate and value of atom to delete. | |
deleteatom: func [s1 p1 v1 /local flagit][ | |
atomica: head atomica | |
cleanit s1 p1 | |
v1: trim to-string v1 | |
flagit: false | |
while [not tail? atomica][if all [atomica/1 = s1 atomica/2 = p1 atomica/3 = v1] [remove/part atomica 3 flagit: true] atomica: skip atomica 3] | |
if flagit = true [atomica: head atomica saveit] | |
] | |
loadit |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Atomica for Ren-C Getting Started
Atomica for Ren-C is a flat-file semantic network DBMS
ITo get a clearer understanding of what we're trying to achieve, have a read of this Wikipedia article on Semantic Networks https://en.wikipedia.org/wiki/Semantic_network
Features
Runs in memory for blazing performance.
Eight simple functions perform 95% of database interaction.
Strong Semantic Network / Graphing capabilities
Dead simple to learn.
100% Rebol code, no dependencies.
4kb in size
Maps to SQL DBs with ease, using the same functions. No need to learn SQL
CRUD - Create, Retrieve, Update and Delete is at the core of Atomica
DRY - Don’t Repeat Yourself
“Every piece of knowledge must have a single, unambiguous, authoritative representation within a system”
Single Source of Truth - "structuring information models such that the element is stored once and no more than a single row in a single table"
Atomica is built on the idea that all languages, including computer languages are built on two main principles.
All language is made up of only three types of sentences.
Declarations: Statements of facts eg: “The color of the dog is black” or “Bob went shopping.”
Queries: “What color is the dog?” “Where is Bob?”
Commands: “Give the dog to Bob”
That’s it! Everything you say falls under one of those categories. (<- That sentence is a declaration.)
A database is nothing more than a collection of declarations, and we access those declarations using queries.
B. All sentences are composed of three parts.
The Subject: The subject is the ‘thing’ being discussed eg: “dog” or “Bob”
The Predicate: The predicate is like the verb of a sentence eg: “has color” or “ current location”
The Object/Value: Although the official term is the “object”, we prefer to use “the value” for clarity eg: “black” or “shopping”
To store these declarations in the Atomica database, we simplify the sentences, and save them as subject, predicate and value.
For example, to save the declaration “John has brown hair.” We would save it as;
subject: “John”
predicate: “hair color”
value: “brown”
We call each of these declarations an ‘atom’ as it’s the absolute minimum amount of data to form a declarative sentence.
A few things to note….
Every subject must be unique. There can only ever be one “john”, and in reality there is only one John… that guy there.. that John! But the world is full of johns? How do with differentiate them from another?
To solve this issue, we give each John a unique id for a subject. For example to identify this John in question, we could use “John1” or “btrsd” .. it doesn’t matter as long as that ‘subject’ is unique to this John, and only associated with him.. So then we can add this John to our database with everything we may want to know.
Of course we could go on, and add “john1” “hair color” “brown” or “john1” “age” “42”
All predicates used must remain consistent. It won’t help if one time you use “hair color” as the predicate, and then “color of hair” the next.
To make these declarations in Atomica for Red, we use the insertatom and insertatoms (note the s) functions. There’s a difference between the two, and it’s important to understand.
Insert Atom
If we’re entering a value that there is only one of... like a person’s hair color or first name, then we use the insertatom function ;
insertatom(“john1” “age” “42”)
John only has one age. In the future if we want to update his age, we use the same function and it will change ‘42’ to whatever age we enter, RATHER than adding a new entry. We don’t want this in our database…
“john1” “age” “42”
“john1” “age” “43”
Insert Atoms
However there are some things that John might have multiples of, like ‘has pet”. In that case we use the insertatoms function;
insertatoms (“john1” “has pet” “Fido”)
insertatoms (“john1” “has pet “Whiskers”)
insertatoms (“john1” “is a” “client”)
insertatoms (“john1” “is a” “developer”)
Queries
To access the our new database of declarations, like any language, we use queries.
Single Value Query
For example, let's say we want to answer the question “What age is John?”. We determine that by “john” we mean “john1” (vs “john2” or any other subject!)
For this query we want the subject, which is “john1” and the predicate, which is “age”. In this case we use the “singlev” function. (v s and p are short for value, subject and predicate, so in this case, it’s the ‘single value” that we want. Single because John only has one age. So in Atomica for Red we enter the query as so.
theage: singlev “john1” “age”
This will set ‘theage” to “42”.
Value of Subject and Predicate
Sometimes we want a block of values, such as the pets that John owns. For this we use the vofsandp (short for value of subject and predicate.. you’ll get used to it :) function
johnspets: vofsandp “john1” “has pet”
which will return a block [“Fido” “Whiskers”]
Subject of Predicate and Value
Similar, we may want to know who owns the pet named “Fido”. In which case we use the sofpandv (subject of predicate and value)function.
whoisowner: sofpandv “has pet” “Fido”
which will return a block [“john1”]
Subject of Predicate
At time, you may want to know who all owns pets in the corporation, but don’t care about the pet’s name. In this case you would use the sofp function.. you want the ‘subject’ that have a particular predicate eg:
petowners: sofp “has pet”
which returns a block [“john1”]
Lets add Mary and her pets, then run the same query..
insertatoms “mary42” “has pet” “Smokey”
petowners: sofp “has pet”
returns [“john1” “mary42”]
Value of Predicate
Returns the values of a particular predicate. For example, if we want all the pet names.. we use the vofp function
petnames: vofp “has pet”
returns [“Fido” “Whiskers” “Smokey”]
Deleting Atoms
Naturally, there comes a time when we need to delete an entire atom.. For this we use the deleteatom function; In order to delete an atom, you need to know the subject, predicate and value. (There’s other methods that we’ll be adding shortly)
deleteatom “mary42” “has pet” “Smokey”
These eight functions are the lion’s share of functions used with Atomica, and a good start, however the real power of Atomica lies in its semantic and AI capabilities.
Over the next weeks, we’ll be adding additional functions and functionality, so be sure to check back often!