[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/triples ac12a6b7fe 1/7: Add a default filename to encou
From: |
ELPA Syncer |
Subject: |
[elpa] externals/triples ac12a6b7fe 1/7: Add a default filename to encourage a shared triple database. |
Date: |
Sun, 1 Jan 2023 14:58:16 -0500 (EST) |
branch: externals/triples
commit ac12a6b7feb665c7ac80aebdf44523024a8e5c92
Author: Andrew Hyatt <ahyatt@gmail.com>
Commit: Andrew Hyatt <ahyatt@gmail.com>
Add a default filename to encourage a shared triple database.
Change `triples-connect' to connect to this filename by default, if nothing
is
passed in.
Create a changelog to note differences after the initial 0.1 checkin, and
bump
version to 0.2.
---
CHANGELOG.org | 6 +++---
README.org | 33 +++++++++++++++++++++++-------
triples-test.el | 7 +++++++
triples.el | 62 +++++++++++++++++++++++++++++++--------------------------
4 files changed, 70 insertions(+), 38 deletions(-)
diff --git a/CHANGELOG.org b/CHANGELOG.org
index 507c92161e..9b90dbc936 100644
--- a/CHANGELOG.org
+++ b/CHANGELOG.org
@@ -1,10 +1,10 @@
TITLE: Changelog for the triples module for GNU Emacs.
+* 0.2
+- Create a default database to encourage a shared triple database. Add
information on why this is an interesting idea in the README.
* 0.1.2
-- Bugfix release to remove backward compatibility with pre-Emacs 29 versions.
-
+- Bugfix release to remove backward compatibility with pre-Emacs 29 versions.
* 0.1.1
- Bugfix release to fix =triples-subject-with-predicate-object=.
-
* 0.1
- This is the initial version that contained basic triple functionality, and
was integrated into GNU ELPA.
diff --git a/README.org b/README.org
index a3f1387a2d..b7c2386ca1 100644
--- a/README.org
+++ b/README.org
@@ -1,6 +1,6 @@
#+TITLE: Triples
-The =triples= module is a standard database module designed for use in other
emacs modules. It works with either the builtin sqlite in Emacs 29 or the
[[https://github.com/magit/emacsql][emacsql]] module, and provides a simple way
of storing entities and their associated schema. The triples module is well
suited to graph-like applications, where links between entities are important.
The module has wrappers for most common operations, but it is anticipated that
occasionally client modu [...]
+The =triples= module is a standard database module designed for use in other
emacs modules. It works with either the builtin sqlite in Emacs 29 or the
[[https://github.com/magit/emacsql][emacsql]] module, and provides a simple way
of storing entities and their associated schema. The triples module is well
suited to graph-like applications, where links between entities are important.
The module has wrappers for most common operations, but it is anticipated that
occasionally client modu [...]
* Installing
This module is available through GNU ELPA, and can be installed as normal.
However, most of the time this module is only useful in concert with another
module which uses it as a library and will declare it as a dependency, so
unless you are planning on developing with it, there is usually no need to
install it directly.
@@ -8,8 +8,8 @@ This module is available through GNU ELPA, and can be installed
as normal. Howe
This module is very new should be considered alpha quality.
While it has basic functionality, there are significant parts, such as a
querying language, that are missing. Whether anyone needs such parts will
determine the priority in which they get built.
-
-* Types and Schema
+* Using the =triples= library
+** Types and Schema
=triples= employs a design in which each entity can be a member of many
/types/, and each /type/ has multiple /properties/. The properties that a type
has is defined by /schema/. Let's take an example:
#+begin_src emacs-lisp
@@ -28,13 +28,23 @@ This adds a type called =person=, which can be set on any
entity. There's anoth
The =person= has 2 properties, =name=, and =age=. They are both marked as
unique, so they take a single value, not a list. If =:base/unique= was not
true, the value would be a list. We also specify what type it is, which can be
any elisp type. =employee= is similarly constructed, but has an interesting
property, =reportees=, which is a =base/virtual-reversed= property, meaning
that it is supplied with values, but rather can get them from the reversed
relation of =employee/manager=.
We'll explore how these types are used can be used in the section after next.
-* The triples concept
+** The triples concept
A triple is a unit of data consisting of a /subject/, a /predicate/, an
/object/, and, optionally, internal metadata about the unit. The triple can be
thought of as a link between the subject and object via the predicate.
Let's say that, as in the example above, we want to store someone's name. The
triples would be a /subject/ that uniquely identifies the person, a /predicate/
that indicates the link between subject and object is about a name, and the
object, which is the name value.
The object can become the subject, and this explains how the
=base/virtual-reversed= predicate works. If Bob is the manager of Alice, then
there could be a triple with Alice as the subject, =manager= as the predicate,
and Bob as the object. But we can also find the reversed links, and ask who
all are all the people that Bob manages. In this case, Bob is the subject, and
Alice is the object. However, we don't actually need to store this information
and try to keep it in sync, we can [...]
-* Setting and retrieving
+** Connecting
+Before a database can be used, it should be connected with. This is done by
the =triples-connect= function, which can be called with a filename or without.
If a filename isn't given, a default one for the triples library, given in
=triples-default-database-filename= is used. This provides a standard database
for those that want to take advantage of the possibilities of having data from
different sources that can build on each other.
+
+An example of using this standard database is simply:
+#+begin_src emacs-lisp
+(let ((db (triples-connect)))
+ (do-something-with db)
+ (do-something-else-with db))
+#+end_src
+You could also use a global variable to hold the database connection, if you
need the database to be active during many user actions.
+** Setting and retrieving
A subject can be set all at once (everything about the subject), or dealt with
per-type. For example, the following are equivalent:
#+begin_src emacs-lisp
@@ -75,11 +85,11 @@ There are other useful functions, including:
- =triples-with-predicate=, gets all triples that is about a specific property,
- =triples-with-predicate-object=, get all subjects whose predicate is equal
to /object/,
- =triples-subjects-of-type=, get all subjects which have a particular type.
-* Predicates, with type and without
+** Predicates, with type and without
Sometimes the triples library will require predicates that are without type,
and sometimes with type, or "combined predicates". The rule is that if the
type is already specified in the function, it does not need to be respecified.
If the type is not specified, it is included in the combined predicate.
When returning data, if data is from just one type, the type is not returned
in the returned predicates. If the data is from multiple types, the type is
returned as combined predicates.
-* Using direct SQL access
+** Using direct SQL access
Sometimes clients of this library need to do something with the database, and
the higher-level triples functionality doesn't help. If you would like
lower-level functionality into handling triples, you can use the same low-level
methods that the rest of this library uses. These start with =triples-db-=.
- =triples-db-insert=: Add a triple. Uses SQL's =REPLACE= command, so there
can't be completely duplicate triples (including the property, which often can
serve as a disambiguation mechanism).
- =triples-db-delete=: Delete triples matching the arguments. Empty arguments
match everything, so =(triples-db-delete db)= will delete all triples.
@@ -88,3 +98,12 @@ Sometimes clients of this library need to do something with
the database, and th
- =triples-db-select=: Select triples matching any of the parts of the triple.
Like =triples-db-delete=, empty arguments match everything. You can specify
exactly what to return with a selector.
Sometimes this still doesn't cover what you might want to do. In that case,
you should write your own direct database access. However, please follow the
coding patterns for the functions above in writing it, so that the code works
with both Emacs 29's builtin sqlite, and =emacsql=.
+* Using =triples= to develop apps with shared data
+One possibility that arises from a design with entities (in triples terms,
+subjects) having multiple decomposable types like is done in the =triples=
library
+is the possibility of many modules using the same database, each one adding
+their own data, but being able to make use out of each other's data.
+
+For example, in the examples above we have a simple system for storing data
about people and employees. If another module adds a type for annotations, now
you can potentially annotate any entity, including people and employees. If
another module adds functionality to store and complete on email addresses, now
people, employees, and potentially types added by other modules such as
organizations could have email addresses.
+
+If this seems to fit your use case, you may want to try to just use the
default database. The downside of this is that nothing prevents other modules
from changing, corrupting or deleting your data.
diff --git a/triples-test.el b/triples-test.el
index d9774f52c8..44d92ab2da 100644
--- a/triples-test.el
+++ b/triples-test.el
@@ -68,6 +68,13 @@ easily debug into it.")
(skip-unless (featurep 'emacsql))
,@body)))))
+(triples-deftest triples-connect-default ()
+ (let* ((triples-default-database-filename (make-temp-file "triples-default"))
+ (db (triples-connect)))
+ (triples-db-insert db 1 'pred 2)
+ (triples-close db)
+ (should (file-exists-p triples-default-database-filename))))
+
(triples-deftest triples-test-insert ()
(triples-test-with-temp-db
(triples-db-insert db "sub" 'pred "obj")
diff --git a/triples.el b/triples.el
index 15276975f9..2e83223295 100644
--- a/triples.el
+++ b/triples.el
@@ -6,7 +6,7 @@
;; Homepage: https://github.com/ahyatt/triples
;; Package-Requires: ((seq "2.0") (emacs "25"))
;; Keywords: triples, kg, data, sqlite
-;; Version: 0.1.2
+;; Version: 0.2
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2 of the
@@ -46,38 +46,44 @@ available. Builtin is available when the version is Emacs
29 or
greater, and emacsql is usable when the `emacsql' package is
installed.")
-(defun triples-connect (file)
- "Connect to the database FILE and make sure it is populated."
+(defconst triples-default-database-filename (locate-user-emacs-file
"triples.db")
+ "The default filename triples database. If no database is
+specified, this file is used.")
+
+(defun triples-connect (&optional file)
+ "Connect to the database FILE and make sure it is populated.
+If FILE is nil, use `triples-default-database-filename'."
(unless (pcase-exhaustive triples-sqlite-interface
('builtin
(and (fboundp 'sqlite-available-p) (sqlite-available-p)))
('emacsql (require 'emacsql nil t)))
(error "The triples package requires either Emacs 29 or the emacsql
package to be installed."))
- (pcase triples-sqlite-interface
- ('builtin (let* ((db (sqlite-open file)))
- (sqlite-execute db "CREATE TABLE IF NOT EXISTS triples(subject
TEXT NOT NULL, predicate TEXT NOT NULL, object NOT NULL, properties TEXT NOT
NULL)")
- (sqlite-execute db "CREATE INDEX IF NOT EXISTS subject_idx ON
triples (subject)")
- (sqlite-execute db "CREATE INDEX IF NOT EXISTS
subject_predicate_idx ON triples (subject, predicate)")
- (sqlite-execute db "CREATE INDEX IF NOT EXISTS
predicate_object_idx ON triples (predicate, object)")
- (sqlite-execute db "CREATE UNIQUE INDEX IF NOT EXISTS
subject_predicate_object_properties_idx ON triples (subject, predicate, object,
properties)")
- db))
- ('emacsql
- (require 'emacsql)
- (let* ((db (emacsql-sqlite file))
- (triple-table-exists
- (emacsql db [:select name
- :from sqlite_master
- :where (= type table) :and (= name 'triples)])))
- (unless triple-table-exists
- (emacsql db [:create-table triples ([(subject :not-null)
- (predicate text :not-null)
- (object :not-null)
- (properties text :not-null)])])
- (emacsql db [:create-index subject_idx :on triples [subject]])
- (emacsql db [:create-index subject_predicate_idx :on triples [subject
predicate]])
- (emacsql db [:create-index predicate_object_idx :on triples
[predicate object]])
- (emacsql db [:create-unique-index
subject_predicate_object_properties_idx :on triples [subject predicate object
properties]]))
- db))))
+ (let ((file (or file triples-default-database-filename)))
+ (pcase triples-sqlite-interface
+ ('builtin (let* ((db (sqlite-open file)))
+ (sqlite-execute db "CREATE TABLE IF NOT EXISTS
triples(subject TEXT NOT NULL, predicate TEXT NOT NULL, object NOT NULL,
properties TEXT NOT NULL)")
+ (sqlite-execute db "CREATE INDEX IF NOT EXISTS subject_idx
ON triples (subject)")
+ (sqlite-execute db "CREATE INDEX IF NOT EXISTS
subject_predicate_idx ON triples (subject, predicate)")
+ (sqlite-execute db "CREATE INDEX IF NOT EXISTS
predicate_object_idx ON triples (predicate, object)")
+ (sqlite-execute db "CREATE UNIQUE INDEX IF NOT EXISTS
subject_predicate_object_properties_idx ON triples (subject, predicate, object,
properties)")
+ db))
+ ('emacsql
+ (require 'emacsql)
+ (let* ((db (emacsql-sqlite file))
+ (triple-table-exists
+ (emacsql db [:select name
+ :from sqlite_master
+ :where (= type table) :and (= name
'triples)])))
+ (unless triple-table-exists
+ (emacsql db [:create-table triples ([(subject :not-null)
+ (predicate text :not-null)
+ (object :not-null)
+ (properties text :not-null)])])
+ (emacsql db [:create-index subject_idx :on triples [subject]])
+ (emacsql db [:create-index subject_predicate_idx :on triples
[subject predicate]])
+ (emacsql db [:create-index predicate_object_idx :on triples
[predicate object]])
+ (emacsql db [:create-unique-index
subject_predicate_object_properties_idx :on triples [subject predicate object
properties]]))
+ db)))))
(defun triples-close (db)
"Close sqlite database DB."
- [elpa] externals/triples updated (d40e1754ae -> 0d7555226a), ELPA Syncer, 2023/01/01
- [elpa] externals/triples f8f7fa5a5f 5/7: Set the last-update-time when making a backup, ELPA Syncer, 2023/01/01
- [elpa] externals/triples 0d7555226a 7/7: Fix minor misspelling, ELPA Syncer, 2023/01/01
- [elpa] externals/triples ac12a6b7fe 1/7: Add a default filename to encourage a shared triple database.,
ELPA Syncer <=
- [elpa] externals/triples 5d70bb0c0d 3/7: Add `triples-backups' module., ELPA Syncer, 2023/01/01
- [elpa] externals/triples 09a78f5b80 6/7: Add `triples-mode-subject', for renaming a subject., ELPA Syncer, 2023/01/01
- [elpa] externals/triples 5520bf8852 4/7: Note new triples-backups module in CHANGELOG.org., ELPA Syncer, 2023/01/01
- [elpa] externals/triples b961d0bf1b 2/7: Create `triples-backup' and some surrounding functionality., ELPA Syncer, 2023/01/01