DAO Classes
Overview
You can work directly with the database or you can use a simple database-access-class (aka dao) which would cover all the fields in a row.
Postmodern allows you to have a relatively simple but straight forward matching of clos classes to a database table. In its simplest form, a dao object would contain the values of the rows of a database table. This is not intended as a full-fledged object-relational magic system ― while serious ORM systems have their place, they are notoriously hard to get right, and are outside of the scope of a humble SQL library like this.
At the heart of Postmodern's DAO system is the dao-class metaclass. It allows you to define classes for your database-access objects as regular CLOS classes. Some of the slots in these classes will refer to columns in the database.
Metaclass dao-class
Basic Dao Definition Examples
A simple dao definition could look like this:
(defclass users () ((name :col-type string :initarg :name :accessor name) (creditcard :col-type (or db-null integer) :initarg :card :col-default :null) (score :col-type bigint :col-default 0 :accessor score) (payment-history :col-type (or (array integer) db-null) :initarg :payment-history :accessor payment-history)) (:metaclass dao-class) (:keys name))
In this case the name of the users will be treated as the primary key (the :keys parameter at the end) and the database table is assumed to be named users because that is the name of the class and there was no :table-name parameter provided. (It might be worth noting that "user" is a reserved word for Postgresql and using reserved words, while possible using quotes, is generally not worth the additional trouble they cause.)
In our example, the name and score slots cannot be null because :col-type does not provide for db-null as an optiona. The creditcard slot can be null and actually defaults to null. The :col-default :null specification ensures that the default in the database for this field is null, but it does not bound the slot to a default form. Thus, making an instance of the class without initializing this slot will leave it in an unbound state.
The payment-history slot is matched to a Postgresql column named payment_history
(remember that Postgresql uses underscores rather than hyphens) and that Postgresql
column is an array of integers. If we wanted a two dimensional array of integers,
the col-type would look like:
:col-type (or (array (array integer)) db-null)
If the value contained in the Postgresql slot payment-history is a common lisp array, Postmodern will seamless handle the conversion to and from the common lisp array and the Postgresql array.
An example of a class where the keys are set as multiple column keys is here:
(defclass points () ((x :col-type integer :initarg :x :reader point-x) (y :col-type integer :initarg :y :reader point-y) (value :col-type integer :initarg :value :accessor value)) (:metaclass dao-class) (:keys x y))
In this case, retrieving a points record would look like the following where 12 and 34 would be the values you are looking to find in the x column and y column respectively.:
(get-dao 'points 12 34)
Now look at a slightly more complex example.
(defclass country () ((id :col-type integer :col-identity t :accessor id) (name :col-type string :col-unique t :check (:<> 'name "") :initarg :name :reader country-name) (inhabitants :col-type integer :initarg :inhabitants :accessor country-inhabitants) (sovereign :col-type (or db-null string) :initarg :sovereign :accessor country-sovereign) (region-id :col-type integer :col-references ((regions id)) :initarg :region-id :accessor region-id)) (:documentation "Dao class for a countries record.") (:metaclass dao-class) (:table-name countries))
In this example we have an id column which is specified to be an identity column. Postgresql will automatically generate a sequence of of integers and this will be the primary key.
We have a name column which is specified as unique and is not null.
We have a region-id column which references the id column in the regions table. This is a foreign key constraint and Postgresql will not accept inserting a country into the database unless there is an existing region table with an id that matches this number. Postgresql will also not allow deleting a region if there are countries that reference that region's id. If we wanted Postgresql to delete countries when regions are deleted, that column would be specified as:
(region-id :col-type integer :col-references ((regions id) :cascade) :initarg :region-id :accessor region-id)
Now you can see why the double parens.
We also specified that the table name is not "country" but "countries". (Some style guides recommend that table names be plural and references to rows be singular.) NOTE: You can provide a fully qualified table name. In other words, if you have
(:table-name a.countries)
Postmodern will look for the countries table in the "A" schema.
When inheriting from DAO classes, a subclass' set of columns also contains all the columns of its superclasses. The primary key for such a class is the union of its own keys and all the keys from its superclasses. Classes inheriting from DAO classes should probably always use the dao-class metaclass themselves.
When a DAO is created with make-instance, the :fetch-defaults keyword argument can be passed, which, when T, will cause a query to fetch the default values for all slots that refers to columns with defaults and were not bound through initargs. In some cases, such as serial and identity columns, which have an implicit default, this will not work. You can work around this by creating your own sequence, e.g. "my_sequence", and defining a (:nextval "my_sequence") default.
Finally, DAO class slots can have an option :ghost t to specify them as ghost slots. These are selected when retrieving instances, but not written when updating or inserting, or even included in the table definition. The only known use for this to date is for creating the table with (oids=true), and specify a slot like this:
(oid :col-type integer :ghost t :accessor get-oid)
Slot Options
The slot definitions in a table have several additional optional keyword parameters:
- :col-type To specify that a slot refers to a column, give it a :col-type option containing an S-SQL type expression (useful if you want to be able to derive a table definition from the class definition). The (or db-null integer) form is used to indicate a column can have NULL values otherwise the column will be treated as NOT NULL.
:col-default When using
dao-table-definition
, having :col-default in a slot definition will tell Postgresql to use this default value if no value is provided when inserting a new row. In the following example, Postgresql would insert the default value of 12 if no value was provided when inserting a new row.(defclass col-default () ((id :col-type integer :col-identity t :accessor id) (name :col-type text :col-unique t :col-check (:<> 'name "") :initarg :name :accessor name :col-collate "de_DE.utf8") (data :col-type integer :col-default 12 :accessor data :initarg :data)) (:metaclass dao-class) (:table-name col-default))
- :col-identity Often used for an id slot when you are going to define a Postgresql table by referring to this dao and you want the primary key to be an identity column automatically generated by Postgresql. This column must have a :col-type integer.
:col-primary-key When using
dao-table-definition
, specifying :col-primary-key in a slot definition will tell Postgresql that this column is the primary key for the table. You will also need to set :unique to t for this column. In the following example, the username is the primary key, not the id column.(defclass test-data-col-primary-key () ((id :col-type integer :accessor id) (username :col-type text :col-primary-key t :col-unique t :initarg :username :accessor username) (department-id :col-type integer :initarg :department-id :accessor department-id)) (:metaclass dao-class) (:table-name users1))
- :col-unique When you want to specify that the values in the table column associated with this slot must be unique. See an example in the username slot definition in the discussion of :col-primary-key immediately above.
- :col-export Specifies a function name to be called when you have to convert a slot value from a CL datatype to a Postgresql datatype that Postmodern does not automatically handle. More about this below.
- :col-import Specifies a function name to be called when you have to convert a slot value from a Postgresql datatype to a CL datatype that Postmodern does not automatically handle. More about this below.
:col-name You can use the :col-name initarg (whose unevaluated value will be passed to to-sql-name) to specify the slot's column's name. In other words, you want a slot name that is different from the database table's column name. This tells Postmodern what that database table column's name when getting data from a table. This is NOT used in
dao-table-definition
in creating tables.(defclass test-col-name () ((a :col-type string :col-name aa :initarg :a :accessor test-a) (b :col-type string :col-name bb :initarg :b :accessor test-b) (c :col-type string :initarg :c :accessor test-c) (from :col-type string :col-name from :initarg :d :accessor test-d) (to-destination :col-type string :col-name to :initarg :e :accessor test-e)) (:metaclass dao-class) (:keys a))
- :col-collate
When using
dao-table-definition
, having :col-collate in a slot definition will tell Postgresql to use this collation when sorting this column. You can have different collations in different columns of the same table. In the following example, Postgresql would use a German UTF8 collation in the name column.
(defclass col-collate () ((id :col-type integer :col-identity t :accessor id) (name :col-type text :col-unique t :col-check (:<> 'name "") :initarg :name :accessor name :col-collate "de_DE.utf8") (:metaclass dao-class) (:table-name col-collate))
:col-check When using
dao-table-definition
, having :col-check in a slot definition will tell Postgresql to ensure that any data entered into that column must meet certain requirements. In the following example, Postgresql would ensure that values in the name column can never be an empty string.(defclass col-check () ((id :col-type integer :col-identity t :accessor id) (name :col-type text :col-unique t :col-check (:<> 'name "") :initarg :name :accessor name :col-collate "de_DE.utf8") (:metaclass dao-class) (:table-name col-check))
:col-references This specifies that the column references a column in another table. In the following example, the department-id slot references the id column in the departments table:
(defclass test-data-col-identity-with-references () ((id :col-type integer :col-identity t :accessor id :col-primary-key t) (username :col-type text :unique t :initarg :username :accessor username) (department-id :col-type integer :col-references ((departments id)) :initarg :department-id :accessor department-id)) (:metaclass dao-class) (:table-name usersr))
Table options
DAO class definitions support two extra class options: :table-name to give the name of the table that the class refers to (defaults to the class name), and :keys to provide a set of primary keys for the table if they have not been specified in a single column. If more than one key is provided, this creates a multi-column primary key and all keys must be specified when using operations such as update-dao and get-dao. When no primary keys are defined, operations such as update-dao and get-dao will not work.
IMPORTANT: Class finalization for a dao class instance are wrapped with a thread lock. However, any time you are using threads and a class that inherits from other classes, you should ensure that classes are finalized before you start generating threads that create new instances of that class.
Dao Query and Selection
The base query and selection methods and macros are:
- get-dao A method that create an instance of a dao object class based on a query of the rows of a database table based on its primary keys.
- select-dao: A macro to select dao objects for the rows in the associated table for which the given test (either an S-SQL expression or a string) holds. When sorting arguments are given, which can also be S-SQL forms or strings, these are used to sort the result.
- do-select-dao: A macro like
select-dao
but iterates over the results rather than returning them. - query-dao: A macro that executes a given query and returns the results as daos of a given type.
- do-query-dao: A function which operates like
query-dao
but iterates over the results rather than returning them.
Dao Reference
Dao Export and Import Functions (Postmodern v. 1.33.1 and newer)
There may be times when the types of values in a dao slot do not have comparable types in Postgresql. For purposes of the following example, assume you have slots that you want to contain lists. Postgresql does not have a "list" data type. Postgresql arrays must be homogeneous but CL lists do not have that limitation. What to do?
One method would be to use text columns or jsonb columns in Postgresql and have functions that convert as necessary going back and forth. In the following example we will use text columns in Postgresql and write CL list data to string when we "export" the data to Postgresql and then convert from string when we "import" the data from Postgresql into a dao-class instance.
One use of the col-import and col-export capabilities is with respect to enums: storing a CL enum as text in the database and then "re-symbolizing them" them again when the DAO classes are read.
Consider the following dao-class definition. We have added additional column keyword parameters :col-export and :col-import. These parameters refer to functions which will convert the values from that slot to a valid Postgresql type (in our example, a string) on export to the database and from that Postgresql type to the type we want in this slot on import from the database (in this example a symbol). NOTE that you use an unquoted symbol for the functions being specified in :col-export and :col-import.
(defclass orchard () ((id :col-type integer :col-identity t :accessor id :col-primary-key t) (name :col-type text :col-unique t :col-check (:<> 'name "") :initarg :name :accessor name) (orchard-type :col-type orchard_type_enum :initarg :orchard-type :accessor orchard-type :col-import intern :col-export string)) (:metaclass dao-class) (:table-name orchards))
Here we have the benefit that our export and import functions are already predefined by CL.
To make things slightly more interesting, we create a different dao which has two slots which are going to contain lists, but one will export to a Postgresql column that contains strings and the other will export to a Postgresql column that contains arrays of integers.
(defclass listy () ((id :col-type integer :col-identity t :accessor id :col-primary-key t) (name :col-type text :col-unique t :col-check (:<> 'name "") :initarg :name :accessor name) (r-list :col-type (or text db-null) :initarg :r-list :accessor r-list :col-export list->string :col-import string->list) (l-array :col-type (or (array integer) db-null) :initarg :l-array :accessor l-array :col-export list->arr :col-import array->list)) (:metaclass dao-class) (:table-name listy))
Now we are going to define the import functions. When writing your import functions, pay attention to how you want to handle nil or :NULL values as well as how you might want to error check the conversion from a Postgresql datatype to a CL datatype. Just to show some of the differences, we are going to translate :NULL strings in Postgresql to :NULL in common lisp and we are going to translate :NULL arrays in Postgresql to nil in common lisp.
(defun string->list (str) "Take a string representation of a list and return a lisp list. Note that you need to handle :NULLs." (cond ((eq str :NULL) :NULL) (str (with-input-from-string (s str) (read s))) (t nil))) (defun array->list (arry) "Here we have decided that we want the list be be nil rather than :NULL if the array is empty." (cond ((eq arry :NULL) nil) ((vectorp arry) (coerce arry 'list)) (t nil)))
And now the export functions. In our example we are just going to be using format to write the CL value to a string unless it is not a list. You are responsible for writing an export function that does what you need. This example just tells Postgresql to insert :NULL if the slot value is not a list. In real life you would need more error checking and condition handling.
The list to array export function inserts :NULL if not a list and otherwise coerces the list to a vector so that Postgresql will accept it as an array.
(defun list->string (lst) "Here we have decided to insert :null if the input list is nil." (if (listp lst) (format nil "~a" lst) :null)) (defun list->arr (lst) (if (null lst) :null (coerce lst 'vector)))
method dao-keys (class)
→ list
Returns list of slot names that are the primary key of DAO class. This is likely interesting if you have primary keys which are composed of more than one slot. Pay careful attention to situations where the primary key not only has more than one column, but they are actually in a different order than they are in the database table itself. You can check this with the internal find-primary-key-info function. Obviously the table needs to have been defined. The class must be quoted.
(pomo:find-primary-key-info 'country1) (("name" "text") ("id" "integer"))
method dao-keys (dao)
→ list
Returns list of values that are the primary key of dao. Explicit keys takes priority over col-identity which takes priority over col-primary-key.
This is likely interesting if you have primary keys which are composed of more than one slot. Pay careful attention to situations where the primary key not only has more than one column, but they are actually in a different order than they are in the database table itself. Obviously the table needs to have been defined. You can provide a quoted class-name or an instance of a dao.
method find-primary-key-column
→ symbol
Loops through a class's column definitions and returns the first column name that has bound either col-identity or col-primary-key.
method dao-exists-p (dao)
→ boolean
Test whether a row with the same primary key as the given dao exists in the database. Will also return NIL when any of the key slots in the object are unbound.
method make-dao (type &rest args &key &allow-other-keys)
→ dao
Combines make-instance with insert-dao. Make the instance of the given class and insert it into the database, returning the created dao.
method fetch-defaults (dao)
→ dao if there were unbound slots with default values, otherwise nil
Used to fetch the default values of an object on creation. An example would be creating a dao object with unbounded slots. Fetch-defaults could then be used to fetch the default values from the database and bind the unbound slots which have default values. E.g.
(let ((dao (make-instance 'test-data :a 23))) (pomo:fetch-defaults dao))
method find-primary-key-column (class)
→ symbol
Loops through a class's column definitions and returns the first column name that has bound either col-identity or col-primary-key. Returns a symbol.
macro define-dao-finalization (((dao-name class) &rest keyword-args) &body body)
Create an :around-method for make-dao. The body is executed in a lexical environment where dao-name is bound to a freshly created and inserted DAO. The representation of the DAO in the database is then updated to reflect changes that body might have introduced. Useful for processing values of slots with the type serial, which are unknown before insert-dao.
method get-dao (type &rest keys)
→ dao
Get the single DAO object from the row that has the given primary key values, or NIL if no such row exists. Objects created by this function will have initialize-instance called on them (after loading in the values from the database) without any arguments ― even :default-initargs are skipped. The same goes for select-dao and query-dao.
(get-dao 'country "The Netherlands")
#<COUNTRY {1010F0DCF3}>
From an sql perspective, the standard call to get-dao translates as:
select * from table
NOTE: if you have added fields to the database table without updating the class
definition, get-dao and select-dao will throw errors. This may cause your
application to appear to hang unless you have the necessary condition handling
in your code. Usually this will only happen during development, so throwing an
error is not a bad idea. If you want to ignore the errors,
set *ignore-unknown-columns*
to t.
macro select-dao (type &optional (test t) &rest sort)
→ list
Select DAO objects for the rows in the associated table for which the given test (either an S-SQL expression or a string) holds. When sorting arguments are given, which can also be S-SQL forms or strings, these are used to sort the result.
(Note that, if you want to sort, you have to pass the test argument.)
(select-dao 'country) (#<COUNTRY {101088F6F3}> #<COUNTRY {101088FAA3}>) 2 (select-dao 'country (:> 'inhabitants 50000000)) NIL 0 (select-dao 'country (:> 'inhabitants 5000000)) (#<COUNTRY {10108AD293}>) 1 (select-dao 'country (:> 'inhabitants 5000)) (#<COUNTRY {10108CA773}> #<COUNTRY {10108CAB23}>) 2 (select-dao 'country (:> 'inhabitants 5000) 'name) ;sorted by name (#<COUNTRY {10108EF423}> #<COUNTRY {10108EF643}>) (mapcar 'country-name (select-dao 'country (:> 'inhabitants 5000) 'name)) ("Croatia" "The Netherlands") (mapcar 'country-name (select-dao 'country (:> 'inhabitants 5000))) ("The Netherlands" "Croatia")
If for some reason, you wanted the list in reverse alphabetical order, then:
(select-dao 'country (:> 'id 0) (:desc 'name))
macro do-select-dao (((type type-var) &optional (test t) &rest sort) &body body)
Like select-dao, but iterates over the results rather than returning them. For each matching DAO, body is evaluated with type-var bound to the DAO instance.
Example:
(do-select-dao (('user user) (:> 'score 10000) 'name) (pushnew user high-scorers))
macro query-dao (type query &rest args)
→ list of daos
Execute the given query (which can be either a string or an S-SQL expression) and return the result as DAOs of the given type. If the query contains placeholders ($1, $2, etc) their values can be given as extra arguments. The names of the fields returned by the query must either match slots in the DAO class, or be bound through with-column-writers.
function do-query-dao (((type type-var) query &rest args) &body body)
→ list of daos
Like query-dao, but iterates over the results rather than returning them. For each matching DAO, body is evaluated with type-var bound to the instance.
Example:
(do-query-dao (('user user) (:order-by (:select '* :from 'user :where (:> 'score 10000)) 'name)) (pushnew user high-scorers))
variable *ignore-unknown-columns*
Normally, when get-dao, select-dao, or query-dao finds a column in the database that's not in the DAO class, it will raise an error. Setting this variable to a non-NIL will cause it to simply ignore the unknown column. This allows you to create daos which are subsets of a table.
method insert-dao (dao)
→ dao
Insert the given dao into the database. Column slots of the object which are unbound implies the database defaults. Hence, if these columns has no defaults defined in the database, the the insertion of the dao will be failed. (This feature only works on PostgreSQL 8.2 and up.)
method update-dao (dao)
→ dao
Update the representation of the given dao in the database to the values in the object. This is not defined for tables that do not have any non-primary-key columns. Raises an error when no row matching the dao exists.
function save-dao (dao)
→ boolean
Tries to insert the given dao using insert-dao. If the dao has unbound slots, those slots will be updated and bound by default data triggered by the database. If this raises a unique key violation error, it tries to update it by using update-dao instead. In this case, if the dao has unbound slots, updating will fail with an unbound slots error.
Be aware that there is a possible race condition here ― if some other process deletes the row at just the right moment, the update fails as well. Returns a boolean telling you whether a new row was inserted.
This function is unsafe to use inside of a transaction ― when a row with the given keys already exists, the transaction will be aborted. Use save-dao/transaction instead in such a situation.
See also: upsert-dao.
function save-dao/transaction (dao)
→ boolean
The transaction safe version of save-dao. Tries to insert the given dao using insert-dao. If this raises a unique key violation error, it tries to update it by using update-dao instead. If the dao has unbound slots, updating will fail with an unbound slots error. If the dao has unbound slots, those slots will be updated and bound by default data triggered by the database.
Be aware that there is a possible race condition here ― if some other process deletes the row at just the right moment, the update fails as well. Returns a boolean telling you whether a new row was inserted.
Acts exactly like save-dao, except that it protects its attempt to insert the object with a rollback point, so that a failure will not abort the transaction.
See also: upsert-dao.
method upsert-dao (dao)
→ dao
Like save-dao or save-dao/transaction but using a different method that doesn't involve a database exception. This is safe to use both in and outside a transaction, though it's advisable to always do it in a transaction to prevent a race condition. The way it works is:
If the object contains unbound slots, we call insert-dao directly, thus the behavior is like save-dao.
Otherwise we try to update a record with the same primary key. If the PostgreSQL returns a non-zero number of rows updated it treated as the record is already exists in the database, and we stop here.
If the PostgreSQL returns a zero number of rows updated, it treated as the record does not exist and we call insert-dao.
The race condition might occur at step 3 if there's no transaction: if UPDATE returns zero number of rows updated and another thread inserts the record at that moment, the insertion implied by step 3 will fail.
Note, that triggers and rules may affect the number of inserted or updated rows returned by PostgreSQL, so zero or non-zero number of affected rows may not actually indicate the existence of record in the database.
This method returns two values: the DAO object and a boolean (T if the object was inserted, NIL if it was updated).
IMPORTANT: This is not the same as insert on conflict (sometimes called an upsert) in Postgresq. An upsert in Postgresql terms is an insert with a fallback of updating the row if the insert key conflicts with an already existing row. An upsert-dao in Postmodern terms is the reverse. First you try updating an existing object. If there is no existing object to oupdate, then you insert a new object.
method delete-dao (dao)
Delete the given dao from the database.
function dao-table-name (class)
→ string
Get the name of the table associated with the given DAO class (or symbol naming such a class).
function dao-table-definition (class)
→ string
Given a DAO class, or the name of one, this will produce an SQL query string with a definition of the table. This is just the bare simple definition, so if you need any extra indices or or constraints, you'll have to write your own queries to add them, in which case look to s-sql's create-table function.
macro with-column-writers ((&rest writers) &body body)
Provides control over the way get-dao, select-dao, and query-dao read values from the database. This is not commonly needed, but can be used to reduce the amount of queries a system makes. writers should be a list of alternating column names (strings or symbols) and writers, where writers are either symbols referring to a slot in the objects, or functions taking two arguments ― an instance and a value ― which can be used to somehow store the value in the new instance. When any DAO-fetching function is called in the body, and columns matching the given names are encountered in the result, the writers are used instead of the default behaviour (try and store the value in the slot that matches the column name).
An example of using this is to add some non-column slots to a DAO class, and use query-dao within a with-column-writers form to pull in extra information about the objects, and immediately store it in the new instances.
Another example would be to convert something that is in one format in Postgresql e.g. a string to something else in your dao. Suppose your dao has slots that contain a regular list, an alist and a plist but for whatever reason the data is stored in Postgresql as text:
(defclass listy () ((id :col-type integer :col-identity t :accessor id) (name :col-type text :col-unique t :col-check (:<> 'name "") :initarg :name :accessor name) (rlist :col-type text :initarg :rlist :accessor rlist) (alist :col-type text :initarg :alist :accessor alist) (plist :col-type text :initarg :plist :accessor plist)) (:metaclass dao-class) (:table-name listy))
Table definition and creation using a dao
It can be useful to have the SQL statements needed to build an application's tables available from the source code, to do things like automatically deploying a database. The following macro and functions allow you to group sets of SQL statements under symbols, with some shortcuts for common elements in table definitions.
macro deftable (name &body definition)
Define a table. name can be either a symbol or a (symbol string) list. In the
first case, the table name is derived from the symbol's name by S-SQL's rules.
In the second case, the name is given explicitly. The body of definitions can
contain anything that evaluates to a string, as well as S-SQL expressions. The
variables *table-name*
and *table-symbol*
are bound to the relevant values in
the body. Note that the evaluation of the definition is ordered, so you'll
generally want to create your table first and then define indices on it.
variable *table-name*
Used inside deftable to find the name of the table being defined.
variable *table-symbol*
Used inside deftable to find the symbol naming the table being defined.
function !dao-def ()
Should only be used inside a deftable form. Define this table using the corresponding DAO class' slots. Adds the result of calling dao-table-definition on table-symbol to the definition.
function !index (&rest columns), !unique-index (&rest columns)
Used inside a deftable form. Define an index on the table being defined. The columns can be given as symbols or strings.
function !foreign (target fields &rest target-fields/on-delete/on-update/deferrable/initially-deferred)
Used inside a deftable form. Add a foreign key to the table being defined. target-table is the referenced table. columns is a list of column names or single name in this table, and, if the columns have different names in the referenced table, target-columns must be another list of column names or single column name of the target-table, or :primary-key to denote the column(s) of the target-table's primary key as referenced column(s).
The on-delete and on-update arguments can be used to specify ON DELETE and ON UPDATE actions, as per the keywords allowed in create-table. In addition, the deferrable and initially-deferred arguments can be used to indicate whether constraint checking can be deferred until the current transaction completed, and whether this should be done by default. Note that none of these are really &key arguments, but rather are picked out of a &rest arg at runtime, so that they can be specified even when target-columns is not given.
function !unique (target-fields &key deferrable initially-deferred)
Constrains one or more columns to only contain unique (combinations of) values, with deferrable and initially-deferred defined as in !foreign
function create-table (symbol)
Takes the name of a dao-class and creates the table identified by symbol by
executing all forms in its definition as found in the *tables*
list.
function create-all-tables ()
Creates all defined tables.
function create-package-tables (package)
Creates all tables identified by symbols interned in the given package.
variables *table-name*
, *table-symbol*
Used inside deftable to find the name of the table being defined.
Used inside deftable to find the symbol naming the table being defined.
function drop-table (table-name &key if-exists cascade)
If a table exists, drop a table. Available additional key parameters are :if-exists and :cascade.
Out of Sync Dao Objects
What Happens when dao classes are out of sync with the database table? Let's establish our baseline
(defclass test-data () ((id :col-type serial :initarg :id :accessor test-id) (a :col-type (or (varchar 100) db-null) :initarg :a :accessor test-a) (b :col-type boolean :col-default nil :initarg :b :accessor test-b) (c :col-type integer :col-default 0 :initarg :c :accessor test-c) (d :col-type numeric :col-default 0.0 :initarg :d :accessor test-d)) (:metaclass dao-class) (:table-name dao-test) (:keys id)) #<DAO-CLASS S-SQL-TESTS::TEST-DATA> (execute (dao-table-definition 'test-data))
Now we define a class that uses the same table, but does not have all the columns.
(defclass test-data-short () ((id :col-type serial :initarg :id :accessor test-id) (a :col-type (or (varchar 100) db-null) :initarg :a :accessor test-a)) (:metaclass dao-class) (:table-name dao-test) (:keys id))
We create an instance of the shortened class and try to save it, then check the results.
(let ((dao (make-instance 'test-data-short :a "first short"))) (save-dao dao)) (query (:select '* :from 'dao-test) :alists) (((:ID . 1) (:A . "first short") (:B) (:C . 0) (:D . 0)))
It was a successful save, and we see that the missing columns took their default values.
Now we define a shortened class, but the a slot is now numeric or null instead of a string and try to save it and check it.
(defclass test-data-short-wrong-1 () ((id :col-type serial :initarg :id :accessor test-id) (a :col-type (or numeric db-null) :initarg :a :accessor test-a)) (:metaclass dao-class) (:table-name dao-test) (:keys id)) (let ((dao (make-instance 'test-data-short-wrong-1 :a 12.75))) (save-dao dao)) (query (:select '* :from 'dao-test) :alists) (((:ID . 1) (:A . "first short") (:B) (:C . 0) (:D . 0)) ((:ID . 2) (:A . "12.75") (:B) (:C . 0) (:D . 0))
Notice that the 12.75 has been converted into a string when it was saved. Postgresql did this automatically. Anything going into a text or varchar column will be converted to a string.
Now we will go the other way and define a dao with the right number of columns, but col d is a string when the database expects a numeric and check that.
(defclass test-data-d-string () ((id :col-type serial :initarg :id :accessor test-id) (a :col-type (or (varchar 100) db-null) :initarg :a :accessor test-a) (b :col-type boolean :col-default nil :initarg :b :accessor test-b) (c :col-type integer :col-default 0 :initarg :c :accessor test-c) (d :col-type text :col-default "" :initarg :d :accessor test-d)) (:metaclass dao-class) (:table-name dao-test) (:keys id)) (let ((dao (make-instance 'test-data-d-string :a "D string" :b nil :c 14 :d "Trying string"))) (save-dao dao)) Database error 22P02: invalid input syntax for type numeric: "Trying string" QUERY: INSERT INTO dao_test (d, c, b, a) VALUES (E'Trying string', 14, false, E'D string') RETURNING id [Condition of type DATA-EXCEPTION]
Ok. That threw a data exception. What happens if we try to force a numeric into an integer column?
(let ((dao (make-instance 'test-data-d-string :a "D string" :b nil :c 14.37 :d 18.78))) (save-dao dao)) Database error 22P02: invalid input syntax for type integer: "14.37" [Condition of type CL-POSTGRES-ERROR:DATA-EXCEPTION]
Ok. Postgresql is enforcing the types.
(let ((dao (make-instance 'test-data-d-string :a "D string" :b nil :c 14 :d 18.78))) (save-dao dao)) (query (:select '* :from 'dao-test) :alists) (((:ID . 1) (:A . "first short") (:B) (:C . 0) (:D . 0)) ((:ID . 2) (:A . "12.75") (:B) (:C . 0) (:D . 0)) ((:ID . 3) (:A . "D string") (:B) (:C . 14) (:D . 939/50)))
Notice that postmodern returned a ratio 939/50 for the numeric 18.78.
We have looked at saving daos. Now look at returning a dao from the database where the dao definition is different than the table definition. First checking to see if we can get a correct dao back.
(get-dao 'test-data 3) #<TEST-DATA {100C82AA33}>
Ok. That worked as expected.
Second using a shortened dao that is correct in type of columns, but incorrect n the number of columns compared to the database table.
(get-dao 'test-data-short 3)
No slot named b in class TEST-DATA-SHORT. DAO out of sync with table, or
incorrect query used.
[Condition of type SIMPLE-ERROR]
Restarts:
0: [RETRY] Retry SLIME REPL evaluation request.
1: [*ABORT] Return to SLIME's top level.
2: [ABORT] abort thread (#<THREAD "new-repl-thread" RUNNING {100C205083}>)
Not only did it throw an exception, but I needed to actually use an interrupt
from the repl to get back in operation. And then use (reconnect *database*
).
Very Bad result.
THIS ERROR IS CONTROLLABLE BY THE VARIABLE *IGNORE-UNKNOWN-COLUMNS*
Now if we setf the default global variable *ignore-unknown-columns*
to t
(setf *ignore-unknown-columns* t) (get-dao 'test-data-short 3) #<TEST-DATA-SHORT {10054DFED3}> (describe (get-dao 'test-data-short 3)) #<TEST-DATA-SHORT {100B249783}> [standard-object] Slots with :INSTANCE allocation: ID = 3 A = "D string"
We now have a dao that is a subset of the database table it pulled from. Just to validate that:
(query (:select '* :from 'dao-test :where (:= 'id 3))) ((3 "D string" NIL 14 939/50))
Just to be thorough, let's use a dao that has more slots than the database table.
(defclass test-data-long () ((id :col-type serial :initarg :id :accessor test-id) (a :col-type (or (varchar 100) db-null) :initarg :a :accessor test-a) (b :col-type boolean :col-default nil :initarg :b :accessor test-b) (c :col-type integer :col-default 0 :initarg :c :accessor test-c) (d :col-type numeric :col-default 0.0 :initarg :d :accessor test-d) (e :col-type text :col-default "sell by date" :initarg :e :accessor test-e)) (:metaclass dao-class) (:table-name dao-test) (:keys id))
Now if we make an instance of this dao and try to save it in the dao-class table:
(let ((dao (make-instance 'test-data-long :a "first short" :d 37.3))) (save-dao dao)) Database error 42703: column "e" does not exist QUERY: INSERT INTO dao_test (d, a) VALUES ($1, $2) RETURNING e, c, b, id [Condition of type CL-POSTGRES-ERROR:UNDEFINED-COLUMN]
Postgresql rejected the attempted insert with an undefined column error.
Introduction to Multi-table dao class objects
Postmodern's dao-class objects are not required to be tied down to a specific table. They can be used simply as classes to hold data for whatever purpose your application may use.
For this introduction, we will use two sets of tables: (1) country-d and region-d and (2) country-n and region-n. In each case the country table will have a foreign key tied to a region.
A foreign key is a "constraint" referencing a primary key in another table. The table containing the foreign key is the referencing or child table and the table referenced by the foreign key is the referenced or parent table. The foreign key enforces a requirement that the child table column refering to another table must refer to a row that exists in the other table. In other words, you cannot create a row in table country-d that references a region-d name "Transylvania" if the region-d name "Transylvania" does not yet exist in the region-d table. At the same time, you could not later delete the region-d row with "Transylvania" if the country-d row referencing it still exists.
Do you remember the slightly more complicated version of country from earlier on the page?
(defclass country () ((id :col-type integer :col-identity t :accessor id) (name :col-type string :col-unique t :check (:<> 'name "") :initarg :name :reader country-name) (inhabitants :col-type integer :initarg :inhabitants :accessor country-inhabitants) (sovereign :col-type (or db-null string) :initarg :sovereign :accessor country-sovereign) (region-id :col-type integer :col-references ((regions id)) :initarg :region-id :accessor region-id)) (:documentation "Dao class for a countries record.") (:metaclass dao-class) (:table-name countries))
That one specified a foreign key reference in the region-id column, so we cannot insert the data from a country dao unless there is already a region table with an id column equal to the region-id in the country dao.
Lets look at two slightly different ways of handling countries and regions.
In our first set of tables, country-d will have a region column that references the name column in a region-d table (so the name column in region-d must be the primary key for region-d).
This looks relatively straight forward and it is in this simple case. Things start getting more complicated if you start having to reference a table where there are many items with the same name. An example would be tracking library books. There may be multiple copies of a book title, but you need to know which book was checked out to which library patron. In these types of situations, the primary key cannot be the name of the region, it needs to reference some particular id.
In our second set of tables, country-n will have a region-id column that references an id column in a region-d table (so the id column in region-d must be the primary key for region-d).
Simple Version
Lets start by declaring our classes and we will use the deftable make to create
a definition for our tables that gets stored in the *tables*
special variable.
We can then use the (create-table 'class-name) function to create the table in
the database.
Just to be slightly different, we are going to declare the classes without the :col-reference and :col-unique modifiers and put those into the (deftable) macro call. We will set the id as a serial in the -d version because we want to use name as the primary key and seting id as an identity would cause it to be the primary key.
(defclass region-d () ((id :col-type serial :initarg :id :reader region-id) (name :col-type string :initarg :name :accessor region-name)) (:metaclass pomo:dao-class) (:keys name)) (deftable region-d (!dao-def) (!unique 'name)) (create-table 'region-d) (defclass country-d () ((id :col-type serial :initarg :id :reader country-id) (name :col-type string :initarg :name :reader country-name) (region-name :col-type string :initarg :region-name :accessor region-name)) (:metaclass pomo:dao-class) (:keys name)) (deftable country-d (!dao-def) (!unique 'name) (!foreign 'region-d 'region-name 'name)) (create-table 'country-d)
The new function !foreign insde the deftable adds a foreign key which requires that a region with that id already exist before you can insert a country. By the way, because of the foreign key constraint, postgresql will require that the region-d table be created before the country-d table.
Look at *tables*
for a moment:
*tables* ((REGION-D . #<FUNCTION (LAMBDA ()) {534D126B}>) (COUNTRY-D . #<FUNCTION (LAMBDA ()) {52A1484B}>))
The region-d lambda looks like this:
(LAMBDA () (LET ((*TABLE-NAME* "region_d") (*TABLE-SYMBOL* 'REGION-D)) (DOLIST (STAT (LIST (!DAO-DEF) (!UNIQUE 'NAME))) (EXECUTE STAT))))
The country-d lambda looks like this:
(LAMBDA () (LET ((*TABLE-NAME* "country_d") (*TABLE-SYMBOL* 'COUNTRY-D)) (DOLIST (STAT (LIST (!DAO-DEF) (!UNIQUE 'NAME) (!FOREIGN 'REGION-D 'REGION-NAME 'NAME))) (EXECUTE STAT))))
Less Simple Version
In the -n version, we are going to use the id columns as the primary key. We will not need to tell deftable t
(defclass region-n () ((id :col-type integer :col-identity t :initarg :id :reader region-id) (name :col-type string :initarg :name :accessor region-name)) (:metaclass pomo:dao-class)) (deftable region-n (!dao-def) (!unique 'name)) (create-table 'region-n) (defclass country-n () ((id :col-type integer :col-identity t :initarg :id :reader country-id) (name :col-type string :initarg :name :reader country-name) (region-id :col-type integer :initarg :region-id :accessor region-id)) (:metaclass dao-class)) (deftable country-n (!dao-def) (!unique 'name) (!foreign 'region-n 'region-id 'id)) (create-table 'country-n)
How do you find the region-id? While we set the primary key as name for both country and region in the simple version, it will be a little more work in the less simple version. Lets start by inserting a couple of regions and we will stick with the dao method for the moment:
(insert-dao (make-instance 'region-d :name "Western Europe")) (insert-dao (make-instance 'region-n :name "Western Europe")) (insert-dao (make-instance 'region-d :name "Southern Europe")) (insert-dao (make-instance 'region-n :name "Southern Europe"))
Now we can add a few countries to country-d:
(insert-dao (make-instance 'country-d :name "The Netherlands" :region-name "Western Europe")) (insert-dao (make-instance 'country-d :name "Croatia" :region-name "Southern Europe"))
Now we can add a few countries to country-n, remembering that for this version, name is not the primary key so how to get the region dao with the name "Western Europe"? For region-d it is easy because the name is the primary key. So
(get-dao 'region-d "Western Europe")
#<REGION-D {100A322D43}>
For region-n it is a little more complicated because the primary key is the id column, not the name column. So there are a couple of ways to do it. First is select-dao which will return a list of daos meeting a test criteria, in a sorted order if that third parameter is also provided. Eg.
(select-dao 'region-n (:= 'id 1)) (#<REGION-N {100AAC6E13}>) (select-dao 'region-n (:= 'name "Western Europe")) (#<REGION-N {100A813CF3}>) (select-dao 'region-n t 'name) (#<REGION-N {100AC90FA3}> #<REGION-N {100AC911B3}>)
Another method with is query-dao, which takes a row and inserts it into a dao. That gets us a list of daos meeting the select criteria.
(query-dao 'region-n "select * from region_n where name = 'Western Europe'")
(#<REGION {1009E75E63}>)
or, using s-sql expression
(query-dao 'region-n (:select '* :from 'region-n :where (:= 'name "Western Europe"))) (#<REGION-D {100A50DA13}>)
Here are two different ways of generating the region-id so we can insert a new dao into country-n:
(insert-dao (make-instance 'country-n :name "The Netherlands" :region-id (region-id (first (select-dao 'region-n (:= 'name "Western Europe")))))) #<COUNTRY-N {1002AD79B3}> (insert-dao (make-instance 'country-n :name "Croatia" :region-id (query (:select 'id :from 'region-n :where (:= 'name "Southern Europe")) :single))) #<COUNTRY-N {1002ADE2B3}>
But the returned row need not be the result from a single table. Suppose we create a third table that has population by year and inserted a couple of rows. This time we will do it with s-sql.
(query (:create-table 'country-population ((id :type bigserial) (country-id :type integer) (year :type integer) (population :type integer)))) (let ((country-id (query (:select 'id :from 'country-d :where (:= 'name "The Netherlands")) :single))) (query (:insert-rows-into 'country-population :columns 'country-id 'year 'population :values `((,country-id 2014 16830000) (,country-id 2015 16900000) (,country-id 2016 16980000) (,country-id 2017 17080000))))) (let ((country-id (query (:select 'id :from 'country-d :where (:= 'name "Croatia")) :single))) (query (:insert-rows-into 'country-population :columns 'country-id 'year 'population :values `((,country-id 2014 4255518) (,country-id 2015 4232873) (,country-id 2016 4208611) (,country-id 2017 4182846)))))
Now we create a class that pulls from all three tables (country, region and country-population).
(defclass country-with-population () ((country-name :col-type string :initarg :country-name :reader country-name) (region-name :col-type string :initarg :region-name :accessor region-name) (year :col-type integer :initarg :year :reader year) (population :col-type integer :initarg :population :reader population)) (:metaclass dao-class) (:keys country-name))
Can we use query-dao to get a list of country-with-population daos with the most recent population data? The answer is yes. That would give us a class that maybe our application can use without having to worry about constantly going back to the database to look for the region's name or whatever.
Of course you still need to get the data into the class instances. You could write the following one time as a function to generate your list of countries with the most recent population data. Note that you need to rename the columns to the appropriate initarg name (e.g. 'country-n.name is selected as 'country-name). You do not need to worry about the order of the selected rows. So long as the selections are renamed properly, the slots will be populated properly.
In the data that we have in the system, we happen to know that the years available are the same for every country. In that case, we just want the information for the maximum year. One way to do that would be:
(query-dao 'country-with-population (:select (:as 'country-n.name 'country-name) 'year (:as 'region-n.name 'region-name) 'population :from 'country-n :inner-join 'region-n :on (:= 'country-n.region-id 'region-n.id) :inner-join 'country-population :on (:= 'country-n.id 'country-population.country-id) :where (:= 'year (:select (:max 'year) :from 'country-population))))
But what happens if the data is not the same for both countries? Lets drop the 2017 population data row for Croatia and make sure it still returns the most current year that we have for both countries.
(query (:delete-from 'country-population :where (:and (:= 'country-id 2) (:= 'year 2017))))
If we run the same query from above, we only get an instance for The Netherlands because that was the only data available for the maximum year (2017). We need to approach the data slightly differently.Because this is postmodern and we only care about the Postgresql database, we can use its DISTINCT ON extension to the SQL standard.
See https://www.postgresql.org/docs/current/sql-select.html#SQL-DISTINCT for more documentation.
The following query will pull the most recent year for both countries. How did that happen? We limited the select clause to distinct country names so we would only pull one of each country, then ordered the result by country-name, but most importantly by year descending.
(query-dao 'country-with-population (:order-by (:select (:as 'country-n.name 'country-name) 'year (:as 'region-n.name 'region-name) 'population :distinct-on 'country-n.name :from 'country-n :inner-join 'region-n :on (:= 'country-n.region-id 'region-n.id) :inner-join 'country-population :on (:= 'country-n.id 'country-population.country-id)) 'country-name (:desc 'year))) (#<COUNTRY-WITH-POPULATION {1009AFAEC3}> #<COUNTRY-WITH-POPULATION {1009AFC963}>)
At this point you could write a function that gets a country-with-population dao pulling the most recent population year from the database:
(defun get-country-with-most-recent-population (country) (car (query-dao 'country-with-population (:order-by (:select (:as 'country-n.name 'country-name) 'year (:as 'region-n.name 'region-name) 'population :distinct-on 'country-n.name :from 'country-n :inner-join 'region-n :on (:= 'country-n.region-id 'region-n.id) :inner-join 'country-population :on (:= 'country-n.id 'country-population.country-id) :where (:= 'country-n.name '$1)) 'country-name (:desc 'year)) country)))
Obviously it is not get-dao, which is simpler but just pulls everything in a single row from a table and this pulls just the data you want from three different tables and it is bespoken for that class. Because get-dao is a generic function, with the normal method being applied when passing a symbol, you could write a new method for get-dao that would apply if you passed it an actual country-with-population class instance.
If you want to display fields in a record which matches a dao class that you have set up, you can call get-dao with the name of table and the primary key. In this example, the table is "countries and the primary key happens to be the field "id" with a value of 1.
For example, assume we pull a dao object out of our country-n table for Croatia:
(describe (get-dao 'country-n 2)) #<COUNTRY-N {1005BF7273}> [standard-object] Slots with :INSTANCE allocation: ID = 2 NAME = "Croatia" REGION-ID = 2
Notice that the region-id field has an integer value. This works. But assume it has a slot of region-id, which refers to an id in the table "regions" and you want the name of the region displayed rather than the region-id. There is a hack using with-column-writers which essentially writes the name into the link slot. Now, we write a function that uses the with-column-writers macro and pull in the actual region name from the regions table.
(defun get-country2 (country-name ) (first (with-column-writers ('region-n 'region-id) (query-dao 'country-n (:select 'country-n.* (:as 'region-n.name 'region-n) :from 'country-n :left-join 'region-n :on (:= 'country-n.region-id 'region-n.id) :where (:= 'country-n.name country-name)))))) (describe (get-country2 "Croatia")) #<COUNTRIES {1003AD23D1}> [standard-object] (describe (get-country2 "Croatia")) #<COUNTRY-N {100593DF03}> [standard-object] Slots with :INSTANCE allocation: ID = 2 NAME = "Croatia" REGION-ID = "Southern Europe" (region-id (get-country2 "Croatia")) "Southern Europe"
Normally calling the accessor region-id would return an integer, but now it is returning the name of the region. if you are using the dao as a simple way to get the relevant data out of the database and you are just going to display this value, this saves you from having to make additional database calls. Otherwise, you would have to make an additional call to get the information from all the foreign tables.


Version 4.0.0-beta.1¶
Release Date: Not released
Highlights:
New View Layouts provide simple way to create site site view templates.
Fixed user guide CSS for proper wide table display
Converted UploadedFile to use system messages
Numerous database, migration & model bugs fixed
Refactored unit testing for appstarter & framework distributions
New messages:
Database.tableNotFound
HTTP.uploadErr…
App changes:
app/Config/Cache has new setting: database
app/Views/welcome_message has logo tinted
composer.json has a case correction
env adds CI_ENVIRONMENT suggestion
The list of changed files follows, with PR numbers shown.
- app/
- Config/
Cache #1719
- Views/
welome_message #1774
- system/
- Cache/Handlers/
RedisHandler #1719, #1723
- Config/
Config #37dbc1
Services #1704, #37dbc1
- Database/
Exceptions/DatabaseException #1739
- Postgre/
Builder #1733
- SQLite3/
Connection #1739
Forge #1739
Table #1739
BaseBuilder #36fbb8, #549d7d
BaseConnection #549d7d, #1739
Forge #1739
MigrationRunner #1743
Query #36fbb8
Seeder #1722
- Debug/
Exceptions #1704
- Files/
UploadedFile #1708
- Helpers/
date_helper #1768
number_helper #1768
security_helper #1768
text_helper #1768
url_helper #1768
- HTTP/
Request #1725
- Language/en/
Database #1739
HTTP #1708
View #1757
- Router/
RouteCollection #1709, #1732
Router #1764
- Test/
ControllerResponse #1740
ControllerTester #1740
DOMParser #1740
FeatureResponse #1740
- Validation/
Rules #1738, #1743
Validation #37dbc1, #1763
- View/
View #1729
Common #1741
Entity #6e549a, #1739
Model #4f4a37, #6e549a, #37dbc1, #1712, #1763
- tests/system/
- Database/
BaseQueryTest #36fbb8
- Live/
SQLite3/AlterTableTest #1739, #1740
ForgeTest #1739, #1745
ModelTest #37dbc1, #4ff1f5, #1763
Migrations/MigrationRunnerTest #1743
- Helpers/
FilesystemHelperTest #1740
- I18n/
TimeTest # 1736
- Test/
DOMParserTest #1740
- Validation/
ValidationTest #1763
- View/
ViewTest #1729
EntityTest #6e549a, #1736
- user_guide_src/
- _themes/…/
citheme.css #1696
- changelogs/
v4.0.0-alpha.5 #1699
- database/
migrate #1696
- dbmgmt/
forge #1751
- installation/
install_manual #1699
running #1750
- intro/
psr #1752
- libraries/
caching #1719
validation #1742
- models/
entities #1744
- outgoing/
index #1729
view_layouts #1729
- testing/
controllers #1740
- tutorial/
static_pages #1763
composer.json #1755
.env #1749
PRs merged:¶
#1774 Housekeeping for beta.1
#1768 Helper changes - signatures & typos
#1764 Fix routing when no default route has been specified. Fixes #1758
#1763 Ensure validation works in Model with errors as part of rules. Fixes #1574
#1757 Correct the unneeded double-quote (typo)
#1755 lowercase ‘vfsStream’ in composer files
#1752 Fixed typo preventing link format
#1751 Guide: Moving misplaced text under correct heading
#1750 Remove reference to Encryption Key in User Guide
#1749 Adding environment to .env
#1745 Updated composite key tests for SQLite3 support. Fixes #1478
#1744 Update entity docs for current framework state. Fixes #1727
#1743 Manually sort migrations found instead of relying on the OS. Fixes #1666
#1742 Fix required_without rule bug.
#1741 Helpers with a specific namespace can be loaded now. Fixes #1726
#1740 Refactor test support for app starter
#1739 Fix typo
#1738 Fix required_with rule bug. Fixes #1728
#1737 Added support for dropTable and modifyTable with SQLite driver
#1736 Accommodate long travis execution times
#1733 Fix increment and decrement errors with Postgres
#1732 Don’t check from CLI in Routes. Fixes #1724
#1729 New View Layout functionality for simple template
#1725 Update Request.php
#1723 Log an error if redis authentication is failed
#1722 Seeder adds default namespace to seeds
#1719 Update Cache RedisHandler to support select database
#4ff1f5 Additional tests for inserts and required validation failing (#1717)
#549d7d Another try at getting escaping working correctly both when in and out of models
#1712 Minor readability changes
#37dbc1 Ensure Model validation rules can be a group name
#1709 Fix resource routing websafe method order checking
#1708 Language for UploadedFile
#36fbb8 BaseBuilder should only turn off Connection’s setEscapeFlags when running a query…
#6e549a Provide default baseURL that works with the development server for easier first time setup (Fixes #1646)
#1704 Fix viewsDirectory bug (#1701)
#4f4a37 remove debugging from Model.
#1699 Fix install link in user guide
#1696 Fix page structure etc
#1695 Tidy up code blocks in the user guide


This module reads either a formatted or unformatted multiblock PLOT3D data set consisting of the grid and data vector (Q file).
Parameters
The following lists all of the parameters found in the parameter block ReadPlot3dParams, which are accessed by the module ReadPlot3dFile and the UI Macro ReadPlot3dUI.
Name Type Description UI Control filename_xyz string The selected grid file (x.dat) XYZ (Grid) Filename filename_q string The selected data file (q.dat) Q (Results) Filename iblanks integer Indicate presence of iblank values in the data files IBlanks format integer Select the file format: ASCII, Binary, or Binary with Padding File Format use_q integer Process Q file; otherwise ignore only building mesh data structure Use Q file data trigger integer Start the read process Read dims3d integer Assume data is 3D if selected, if not, assume 2D only 3D multiblock integer Assume multiblock format or else simple 1-block binary files Multiblock <none> <none> Clear the filename entries Clear Ouput Ports
Name Type Description out Multi_Block (link) Multi-block output containing array of fields fields field array (mlink) Link to the fields sub-object of the multi-block output
This module reads either a formatted or unformatted multiblock PLOT3D data set consisting of the grid and data vector (Q file). 3D, 2D, ASCII, binary or Fortran unformatted files are handled. No corrections are made for block edge overlap and no co-incident node removal is attempted between blocks. The cells of the output field structure created are all hexahedra. If no Q (result data) is present, visualizations can be made of the mesh file only.
ReadPlot3dFile reads in several of the possible plot3d file types, a multiblock (with or without iblanks) stored in the whole field format, or a single 1-block file. The Q vector is labeled with the default names of the primative variables.
File formats may be ASCII formatted, and two types of binary file. In the "binary" mode, the file is accessed as a continuous stream. In the "unformatted" mode, padding records are assumed at the end of logical blocks, such as caused by FORTRAN I/O, if the padding option is turned on, otherwise straight binary with no padding is assumed.
If non-multiblock is selected, just one block is output, and no leading header is assumed.
The reader automatically checks and detects BigEndian/LittleEndian format mode, and does byte swapping on the fly. This means that data generated on a UNIX machine can be viewed on an Intel PC, or that data generated on a Dec Alpha can be visualized on a Sun or SGI.
The reader is written in an "omethod" style in C, with a multi-block (arrays of fields) output data structure. The DVswitch module can be used to select just one of the blocks for visualization with Main-Page modules, otherwise use the ARR modules for multiblock processing.
Typical Usage: You have to have some idea of what the files contain before reading, or just experiment by pushing various combinations of parameters.
- Single block PLOT3D files from AVS5: bluntfin
- blntfinq.bin, blntfinx.bin
- [3D, no iblanks, binary, no multiblock]
- Ascii multiblock files from AVS/Express
- multb_q.dat, multb_x.dat
- [3D, iblanks, ASCII, multiblock]
- Unformatted 2D grid files from a Dec Alpha System:
- [2D, no iblanks, binary w/padding, multiblock]
&ReadPlot3dFileParams
Reference to the parameter block, which contains real instances of the various toggles and filenames.
filename_xyz
The selected grid file (x.dat)
filename_q
The selected data file (q.dat)
iblanks
A boolean parameter to indicate the presence of iblank values in the data files.
format
Select the file format: ASCII, Binary, or Binary with Padding
use_q
If selected, will try to process Q file; otherwise, will ignore and only build the mesh data structure.
trigger
Button to actually do the read. All other parameter interfaces may be set or changed beforehand, without triggering the read process.
dims3d
Assume data is 3D if selected, if not, assume 2D only
multiblock
Assume multiblock format or else simple 1-block binary files.
out
Multi-block output containing array of fields.
fields
Link to the fields sub-object of the multi-block output.
The low-level ReadPlot3dFile module is used in the Functional Macro ReadPlot3d and the User Macro read_plot3d. Additionally, the module, the Functional Macro and the UI Macro ReadPlot3dUI have references to the parameter block ReadPlot3dParams. There is a real instance of the parameter block in read_plot3d.
An example application ReadPlot3dEg is provided, which reads the bluntfin plot3d data found in the AVS/Express installation directories, and then renders an orthogonal slice through the dataset.
Note that a link object is used to extract a single field from the field array output of the module.
xp_comm_proj/rdplot3d/rdp3macs.v contains the read_plot3d User Macro, the ReadPlot3d Functional Macro, the ReadPlot3dUI UI Macro, and the example application ReadPlot3dEg V definitions.
The read_plot3dMacs library inherits its process. As this library contains no procedural code, the process is not important. The low-level ReadPlot3dFile module, executes under the process specified in its library, not the process defined in the high-level library.
Ian Curington, AVS Inc (AVS/Express Port) Michael J. Rangitsch (AVS5 version, 11 Oct 1994)
Paul G. Lever
ReadPlot3dParams, ReadPlot3dFile, ReadPlot3dUI and ReadPlot3d.
Plot3d_Multi_Block


[React] array map function
When I was writing the project dictionary, in
MeaningBlock.js file, I tried to iterate the meanings array to list all the meaning
following a number. Here is the code:
{meaningsBlock.DefaultMeanings.map((id, meaning) => {
return (

{id}
{meaning}

);
})}
But it didn't turn out to be what I wanted. It has meaning followed by
the number, then I realised content come first than id in array.map
argument. So it should be:
{meaningsBlock.DefaultMeanings.map((meaning, id) => {
return (

{id}
{meaning}

);
})}
Or:
{meaningsBlock.DefaultMeanings.map((meaning, id) => (

{id}
{meaning}

))}
But you know, you can always use ol and li tag to list items.
And I was confused at the beginning by the documentation, as it seems
like when you iterate the array, it can return the transforming item as
part of the new array without return keyword but in some examples, it
returns something with the keyword. The item could be numbers, strings
or even jsx objects. Now I understand that returning transforming array
is one situation. In the other situation, there are more things you want
to do during iterating so it can't be made into only one line of code so
it has to be a function. In function, you return the item with the
return keyword.


A dashboard where you can look at weather conditions from searched cities
Allows users to generate passwords with multiple options, such as characters and length
A timed multiple choice quiz game on various topics anime related
A deployed app for keeping track of the burgers you've eaten and want to eat
A node based employee management system


Enter username you would like to have below
Enter your e-mail below
Enter password you would like to have below
Confirm the password below
Registration successful.
Registration unsuccessful.


I am a final year graduate student in Applied Mathematics and Statistics at SUNY Stony Brook. My interest lies in machine learning and its wide applications in different domains. Recently, I completed my internship in health care domain at Express Scripts Inc. Before coming to Stony Brook, I've worked in manufacturing and retail sector as a data scientist. I have worked in projects involing predictive analytics (supervised and unsupervised), natural language processing and data mining techniques. I'm a graduate of IIT Kharagpur (Batch of 2015), with a B.Tech-M.Tech Dual degree in Industrial and Systems Engineering.
Worked at the headquarters of a fortune 22 company in health care analytics domain. I was responsible to build therapy level member engagement models. They were assigned to me as a part of a clinical technology solutions product to go live in January 2019. The linear models, on average had an accuracy over 80%. I was working on a fast paced analytic support team that allowed me to work in collaboration with teams handling the business requirements. The product as a whole are expected to pave a revenue stream of 20M $ over the next two years.
Worked for Client, Sears Holdings. Part of a 5 member team that worked directly with Senior Director, Machine Learning. Was instrumental in building gradient boosting models in Python for improving the sales across 80 different business units. The models were further improved by performing feature engineering. Embeddings were created to accommodate the historical buying pattern of the customer and fed back to the model. The new improved models increased the sales by ~4%. I had to ensure smooth deployment of the models in the system.
I started my professional career with this manufacturing giant. I gained enough exposure to the applicability of machine learning techniques to the real life datasets. I worked on building a support vector machine model to identify anaemia severity using non- invasive sensor data. The project was a part of John-Hopkins University. I had to use data mining methods to exploit and understand the sensor data. I also used hierarchial clustering to tackle class imbalance problem.
The internship here introduced me to statistical tools like R and SAS. I built basic Market Mixed Models on R. By the end of the internship I had a deep understanding of market mixed models and could derive insights from the model to be delivered to the customer. A small part of my work also included creating presentations that would summarize the models.
Track - Statistics Coursework highlight : Probability, Data Analysis, Multivariate Data Analysis, Time Series analysis, Regression, Big Data, Machine Learning
Worked in a team to expliot the Credit card defaulters data in Taiwan. Came up with interesting hypothesis on the projects and tested them using R. Hypothesis included on trend of spending pattern of defaulters. Identifying the factors affecting the credit limit and the ones affecting defaulters.
Here, I decided to explore the applicability of my knowledge in a real life situation. I examined the assembly line at TATA Bearings, Kharagpur for Inventory and Sustainability analysis. This topic was of interest to me as TATA, is known to survive the market over decades and it would be interesting to look at one of its vertical critically. I planned to apply Theory of Constraints techniques to optimize the inventory replenishment process of spares and consumables. I primarily used Holt-Winters model to improve throughput of the inventory management system by reducing the in-hand inventory by ~3%.
As a part of my bachelors thesis, I decided to explore genetic algorithms beyond a black box. I implemented a research paper with suitable tweaking to suit the needs of my defined problem. I implemented it to solve the well documented problem of job shop scheduling. I used MATLAB to code the algorithm. I also did a time and space complexity analysis of the code and suggested a few improvements while defending my thesis.


Deploy a TypeScript app using Docker
An application developed in TypeScript actually runs as JavaScript application. When deploying into a Docker image, wwe want to keep it small, here's how.
Docker with a side of Docker
Deployment has a few steps:
- Compile to JavaScript
- Successfully run all test
- Run code quality (e.g. Sonar)
- Finally package all up into the smallest of containers
Using last weeks example these are the moving parts.
Dockerfile
# build container using an LTS Node version
# does not get deployed to runtime
FROM node:18-alpine
# Create app directory
WORKDIR /usr
COPY package*.json ./
COPY tsconfig.json ./
COPY src ./src
COPY test ./test
RUN npm install
RUN npm run build
# Actual runtime container using an LTS Node version
FROM node:18-alpine
# Create app directory
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --omit=dev
#Only compiled JS source
COPY --from=0 /usr/dist .
# Labels
LABEL org.opencontainers.image.source="https://github.com/[yourorg]/[yourrepo]"
# Run it
EXPOSE 8080
CMD ["node","index.js"]
A few pointers/explanations are warranted:
- This builds two containers, one to compile and run tests, one to be deployed to its runtime environment (DigialOcean, Linode or one of the big boys)
- for deployments stick to LTS versions
npm ci
is similar tonpm install
, just less verbose for CI use
GitHub action
A GitHub Action is a convenient way to automate build & deployment
name: Build and deploy docker
on:
push:
branches:
- develop
- main
jobs:
dockerbackend:
name: Build and store backend docker
runs-on: ubuntu-latest
steps:
- name: Checkout Backend
uses: actions/checkout@v3
- run: npm install
# Setup hardware emulator using QEMU
# needed so we can also run on ARM/Mac
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Setup Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Docker Hub login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: GitHub container Registry login
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get current date
id: date
run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
- name: Build and Push
id: docker_build
uses: docker/build-push-action@v4
with:
context: ./
file: ./Dockerfile
builder: ${{ steps.buildx.outputs.name }}
push: true
platforms: linux/amd64, linux/arm64
tags: |
ghcr.io/[yourorg]/[your repo]:${GITHUB_REF##*/}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
- name: deploy to runtime host
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DEPLOYMENT_HOST }}
username: ${{ secrets.DEPLOYMENT_USER }}
key: ${{ secrets.DEPLOYMENT_KEY }}
script: ~/bin/update-${GITHUB_REF##*/}
- This action runs on push/merge to
main
ordevelop
${GITHUB_REF##*/}
returns that branch name- container images are build for Intel and Arm architecture, so it runs nicely on your M1/M2 Mac too
- container images are saved to the Github Container registry, you might want to change that to you registry of choice
- All sensitive values are kept in GitHub secrets, you need to update your repository with them
local script
The final step is to get the deployment host to reload. Mine uses a docker-compose.yml
file to define the container runtime parameters, but command line would work as well.
The last line of the GitHub action script: ~/bin/update-${GITHUB_REF##*/}
uses
a variable to compute the script name. So it will either run update-main
or update-develop
. Both files should be in th ~/bin
directory of the user
#!/bin/bash
cd /opt/myapp
docker-compose pull
docker-compose up -d
As usual YMMV
Posted by Stephan H Wissel on 04 June 2023 | Comments (0) | categories: Docker JavaScript TypeScript


Solomon M. Kamanga is a software developer. He primarily works on Android Application Development, Web
Development and many
other beautiful things using beautiful code. He lives in Gaborone, Botswana. And interestingly enough
he's
the one who wrote this bio and yet it's in 3rd person...
Please feel free to contact him about any software project you may need his services for.
Self-employed
Freelance Software Developer
DigitalHorn
Android Mobile Applications Developer
Businesoft
Trainee Support Consultant
Modi Investments (PTY) LTD
Trainee Support Technician


Good job!
Posted: Sun Sep 21, 2008 10:36 pm
Ok I want to start off by saying thanks to Karl and his crew. I've been hearing of project volucris for about a year probably, and seen or heard no faces or names... then I was introduced to this site, and with skepticism I proceeded to join and become a part. Now I see there's actual dedication and it's coming along very quickly. I found myself actually exited when reading your updates list. Great job, great listener! hooray for karl. This game could be a great investment of time. and I'm starting to feel glad to be partaking. that's a good thing. YOURE ALMOST THERE....months away from the best game ever.
-prehistohizzle
-prehistohizzle


Pat's Salmon Cookies
Home
Sales Page
Store
Gallery
Hourly Cookies Needed By Location
Add a New Store
Store Name
Minimum Hourly Customers
Maximum Hourly Customers
Average Hourly Customers
Add Store
Hourly Staff Requirements By Location


Methods
- A
- G
- I
- M
- P
- S
- T
Instance Public methods
issues()
Link
Get only assigned issues
Source: show
# File app/controllers/groups_controller.rb, line 29 def issues @user = current_user @issues = current_user.assigned_issues.opened @issues = @issues.of_group(@group).recent.page(params[:page]).per(20) @issues = @issues.includes(:author, :project) respond_to do |format| format.html format.atom { render layout: false } end end
merge_requests()
Link
Get authored or assigned open merge requests
Source: show
# File app/controllers/groups_controller.rb, line 23 def merge_requests @merge_requests = current_user.cared_merge_requests.opened @merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20) end
people()
Link
Source: show
# File app/controllers/groups_controller.rb, line 49 def people @project = group.projects.find(params[:project_id]) if params[:project_id] @users = @project ? @project.users : group.users @users.sort_by!(&:name) if @project @team_member = @project.users_projects.new else @team_member = UsersProject.new end end
search()
Link
Source: show
# File app/controllers/groups_controller.rb, line 41 def search result = SearchContext.new(project_ids, params).execute @projects = result[:projects] @merge_requests = result[:merge_requests] @issues = result[:issues] end
show()
Link
Source: show
# File app/controllers/groups_controller.rb, line 11 def show @events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0) @last_push = current_user.recent_push respond_to do |format| format.html format.js format.atom { render layout: false } end end
team_members()
Link
Source: show
# File app/controllers/groups_controller.rb, line 61 def team_members @group.add_users_to_project_teams(params[:user_ids], params[:project_access]) redirect_to people_group_path(@group), notice: 'Users was successfully added.' end
Instance Protected methods
group()
Link
Source: show
# File app/controllers/groups_controller.rb, line 68 def group @group ||= Group.find_by_path(params[:id]) end


This privacy policy has been compiled to better serve those who are concerned with how their 'Personally Identifiable Information' (PII) is being used online. PII, as described in US privacy law and information security, is information that can be used on its own or with other information to identify, contact, or locate a single person, or to identify an individual in context. Please read our privacy policy carefully to get a clear understanding of how we collect, use, protect or otherwise handle your Personally Identifiable Information in accordance with our website.
What personal information do we collect from the people that visit our blog, website or app?
When ordering or registering on our site, as appropriate, you may be asked to enter your name, email address, mailing address, phone number, credit card information or other details to help you with your experience.
When do we collect information?
We collect information from you when you fill out a form or enter information on our site.
How do we use your information?
We may use the information we collect from you when you register, make a purchase, sign up for our newsletter, respond to a survey or marketing communication, surf the website, or use certain other site features in the following ways:
• To improve our website in order to better serve you.
• To quickly process your transactions.
• To follow up with them after correspondence (live chat, email or phone inquiries)
How do we protect your information?
We do not use vulnerability scanning and/or scanning to PCI standards.
An external PCI compliant payment gateway handles all CC transactions.
We do not use Malware Scanning.
We do not use an SSL certificate
• We do not need an SSL because:
We are in the process of getting one at this time.
Do we use 'cookies'?
We do not use cookies for tracking purposes
You can choose to have your computer warn you each time a cookie is being sent, or you can choose to turn off all cookies. You do this through your browser settings. Since browser is a little different, look at your browser's Help Menu to learn the correct way to modify your cookies.
If you turn cookies off, Some of the features that make your site experience more efficient may not function properly.that make your site experience more efficient and may not function properly.
Third-party disclosure
We do not sell, trade, or otherwise transfer to outside parties your Personally Identifiable Information.
Third-party links
Occasionally, at our discretion, we may include or offer third-party products or services on our website. These third-party sites have separate and independent privacy policies. We therefore have no responsibility or liability for the content and activities of these linked sites. Nonetheless, we seek to protect the integrity of our site and welcome any feedback about these sites.
Google
We have not enabled Google AdSense on our site but we may do so in the future.
California Online Privacy Protection Act
CalOPPA is the first state law in the nation to require commercial websites and online services to post a privacy policy. The law's reach stretches well beyond California to require any person or company in the United States (and conceivably the world) that operates websites collecting Personally Identifiable Information from California consumers to post a conspicuous privacy policy on its website stating exactly the information being collected and those individuals or companies with whom it is being shared. - See more at:
http://consumercal.org/california-online-privacy-protection-act-caloppa/#sthash.0FdRbT51.dpuf
According to CalOPPA, we agree to the following:
Users can visit our site anonymously.
Once this privacy policy is created, we will add a link to it on our home page or as a minimum, on the first significant page after entering our website.
Our Privacy Policy link includes the word 'Privacy' and can easily be found on the page specified above.
You will be notified of any Privacy Policy changes:
• On our Privacy Policy Page
Can change your personal information:
• By emailing us
• By calling us
How does our site handle Do Not Track signals?
We honor Do Not Track signals and Do Not Track, plant cookies, or use advertising when a Do Not Track (DNT) browser mechanism is in place.
Does our site allow third-party behavioral tracking?
It's also important to note that we do not allow third-party behavioral tracking
COPPA (Children Online Privacy Protection Act)
When it comes to the collection of personal information from children under the age of 13 years old, the Children's Online Privacy Protection Act (COPPA) puts parents in control. The Federal Trade Commission, United States' consumer protection agency, enforces the COPPA Rule, which spells out what operators of websites and online services must do to protect children's privacy and safety online.
We do not specifically market to children under the age of 13 years old.
Do we let third-parties, including ad networks or plug-ins collect PII from children under 13?
Fair Information Practices
The Fair Information Practices Principles form the backbone of privacy law in the United States and the concepts they include have played a significant role in the development of data protection laws around the globe. Understanding the Fair Information Practice Principles and how they should be implemented is critical to comply with the various privacy laws that protect personal information.
In order to be in line with Fair Information Practices we will take the following responsive action, should a data breach occur:
We will notify you via email
• Other
As soon as possible.
We also agree to the Individual Redress Principle which requires that individuals have the right to legally pursue enforceable rights against data collectors and processors who fail to adhere to the law. This principle requires not only that individuals have enforceable rights against data users, but also that individuals have recourse to courts or government agencies to investigate and/or prosecute non-compliance by data processors.
CAN SPAM Act
The CAN-SPAM Act is a law that sets the rules for commercial email, establishes requirements for commercial messages, gives recipients the right to have emails stopped from being sent to them, and spells out tough penalties for violations.
We collect your email address in order to:
• Send information, respond to inquiries, and/or other requests or questions
To be in accordance with CANSPAM, we agree to the following:
• Not use false or misleading subjects or email addresses.
• Identify the message as an advertisement in some reasonable way.
• Include the physical address of our business or site headquarters.
• Monitor third-party email marketing services for compliance, if one is used.
• Honor opt-out/unsubscribe requests quickly.
• Allow users to unsubscribe by using the link at the bottom of each email.
If at any time you would like to unsubscribe from receiving future emails, you can
• Follow the instructions at the bottom of each email.
and we will promptly remove you from
ALL correspondence.
If there are any questions regarding this privacy policy, you may contact us using the information below.
5955 Sunrise Ave.


ÁVision Build Log
Tool Versions:
IDE-Version: Ž╠Vision V<IP_ADDRESS> Copyright (C) 2018 ARM Ltd and ARM Germany GmbH. All rights reserved. License Information: a a, a, LIC=7YKSB-2FZ6R-IMI9B-2DPHW-BZKPW-U3W2I Tool Versions: Toolchain: MDK-ARM Professional Version: <IP_ADDRESS> Toolchain Path: D:\Keil_v5\ARM\ARMCC\Bin C Compiler: Armcc.exe V5.06 update 6 (build 750) Assembler: Armasm.exe V5.06 update 6 (build 750) Linker/Locator: ArmLink.exe V5.06 update 6 (build 750) Library Manager: ArmAr.exe V5.06 update 6 (build 750) Hex Converter: FromElf.exe V5.06 update 6 (build 750) CPU DLL: SARMCM3.DLL V<IP_ADDRESS> Dialog DLL: DCM.DLL V<IP_ADDRESS> Target DLL: STLink\ST-LINKIII-KEIL_SWO.dll V<IP_ADDRESS> Dialog DLL: TCM.DLL V<IP_ADDRESS>Project:
E:\RTTOS\qsdk_rtos\stm32l151\7_M5310A_UDP\project.uvprojx Project File Date: 06/28/2019Output:
*** Using Compiler 'V5.06 update 6 (build 750)', folder: 'D:\Keil_v5\ARM\ARMCC\Bin' Build target 'rt-thread' compiling qsdk_nb.c... compiling qsdk_net.c... packages\qsdk-latest\src\qsdk_net.c(242): warning: #550-D: variable "result" was set but never used char *result=RT_NULL; packages\qsdk-latest\src\qsdk_net.c(243): warning: #550-D: variable "rev_socket" was set but never used char *rev_socket=RT_NULL; packages\qsdk-latest\src\qsdk_net.c(244): warning: #550-D: variable "rev_ip" was set but never used char *rev_ip=RT_NULL; packages\qsdk-latest\src\qsdk_net.c(245): warning: #550-D: variable "rev_port" was set but never used char *rev_port=RT_NULL; packages\qsdk-latest\src\qsdk_net.c(246): warning: #550-D: variable "rev_len" was set but never used char *rev_len=RT_NULL; packages\qsdk-latest\src\qsdk_net.c(387): warning: #550-D: variable "eventid" was set but never used char *eventid=NULL; packages\qsdk-latest\src\qsdk_net.c(412): warning: #550-D: variable "head" was set but never used char *head=NULL; packages\qsdk-latest\src\qsdk_net.c: 7 warnings, 0 errors compiling qsdk_callback.c... compiling main.c... linking... Program Size: Code=76622 RO-data=11750 RW-data=776 ZI-data=4528 After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin ".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 7 Warning(s).Software Packages used:
Package Vendor: Keil http://www.keil.com/pack/Keil.STM32L1xx_DFP.1.2.0.pack Keil.STM32L1xx_DFP.1.2.0 STMicroelectronics STM32L1 Series Device Support and ExamplesCollection of Component include folders:
.\RTE\_rt-thread D:\Keil_v5\ARM\PACK\Keil\STM32L1xx_DFP\1.2.0\Device\IncludeCollection of Component Files used:
Build Time Elapsed: 00:00:14


Objective
Seeking a summer internship position in the technology industry, with interests in web and application development, user interface, and cybersecurity
Education
New Jersey Institute of TechnologyB.S. in Information Technology
Concentration: Web Applications
Expected Graduation: May 2021
Minors: Applied Mathematics, Designing the User Experience
Cumulative GPA: 3.957
Skills
Software: Microsoft Office, Google Suite, Adobe Photoshop, Lightroom, Premier Pro
Programming: Python, Java, MATLAB, HTML, CSS
Languages: Fluent in Spanish
Projects
Chat System Socket Program- • Coded a chat system in Java that connects to a server and works across a local network.
Users are able to interact with a chat frame box where they can enter a username, send messages to everyone connected, and send private messages. A list of all members updates as users connect and disconnect.
- • Created a tip calculator application for iOS phones using Xcode and Swift. Users can enter the amount of their bill and select the percentage they wish to tip. The app then calculates the tip amount and provides a total of the bill plus tip.
Work Experience
Social Media Intern | Fairry Land Group NJ May 2019 – July 2019
Headed the social media department at the Fairry Land Group NJ in Hoboken, NJ
- • Responsible for the daily creation, curation, and moderation of content across all Fairry Land Group NJ social media platforms, including their website, Facebook, Instagram, Pinterest, and LinkedIn
- • Conceptualized, produced, directed, and edited brand video content for YouTube, Facebook, and Instagram
- • Responsible for the social activation of local advertising campaigns to promote the business and encourage consumer engagement
Activities & Honors
Dean’s List: Fall 2017, Spring 2018, Fall 2018, Spring 2019
NJIT GirlHacks Volunteer
Research Assistant at NJIT’s Social Interaction Lab
NJIT Women in Computing Society
Rutgers-Newark Student Government Association
Rutgers-Newark Latinos United Networking America
Commercial Photography Certification, Hudson County Schools of Technology 2017
Hudson County Alliance of Teen Artists Judges Award 2016, 2017


Actor Patrick Shai wounded during Dobsonville protests: 'I was shot 11 times with rubber bullets'
Nikita Coetzee
WARNING: This article contains graphic images
Johannesburg – Speaking to Channel24 from his hospital bed on Monday morning, actor Patrick Shai said that he had been wounded after being struck by 11 rubber bullets during a protest in Dobsonville.
The community in the south of Johannesburg has been protesting due to electricity cuts.
Patrick says he stood between disgruntled residents and police, trying to calm the situation when he was shot.
"I was trying to mediate between cops and residents."
About his injuries, he says: "I've got an open wound on my leg. They're putting in a drip now." He added that he was going to have x-rays done to determine if he had incurred any other structural damage to tissue or bone.
The former Generations and Zone 14 actor said that while his thigh was left wounded, most of the rubber bullets hit him the back when he was trying to get away.
"When we say that there is no need for violence, we are also saying that to police," Shai says, calling cops on the scene "trigger happy".
The star who resides in Dobsonville says that his area had not been affected by power cuts, but he decided to join protests anyway as a means of keeping the peace among residence and police.
UPDATE: A statement sent to Channel24 from South African Police Services' Brigadier Mathapelo Peters confirms that police had fired rubber bullets "to disperse a group of about 200 protesters", saying that protesters had allegedly "started pelting the police while the JMPD were clearing the debris on the barricaded Elias Motswaledi Road."
According to the statement, no arrests have been made. Police will remain in the area to "ensure no further violence erupts."
(Photos: Supplied by Patrick Shai)


procedure DrawTo(Dst: TCustomBitmap32); overload;
procedure DrawTo(Dst: TCustomBitmap32; DstX, DstY: Integer); overload;
procedure DrawTo(Dst: TCustomBitmap32; DstX, DstY: Integer; const SrcRect: TRect); overload;
procedure DrawTo(Dst: TCustomBitmap32; const DstRect: TRect); overload;
procedure DrawTo(Dst: TCustomBitmap32; const DstRect, SrcRect: TRect); overload;
The DrawTo method renders the bitmap (or part of it specified by SrcRect parameter) onto another bitmap specified by Dst parameter. It works similar to Draw method but instead of copying data from some other source, the bitmap renders itself to destination object. See the Draw description for details.


Makes 'deck.gl' <https://deck.gl/>, a WebGL-powered open-source JavaScript framework for visual exploratory data analysis of large datasets, available within R via the 'htmlwidgets' package. Furthermore, it supports basemaps from 'mapbox' <https://www.mapbox.com/> via 'mapbox-gl-js' <https://github.com/mapbox/mapbox-gl-js>.
| Version: | 0.1.8 |
| Depends: | R (≥ 3.3) |
| Imports: | htmlwidgets, htmltools, magrittr, base64enc, yaml, jsonlite, readr, tibble |
| Suggests: | knitr, rmarkdown, testthat, rprojroot |
| Published: | 2018-11-19 |
| Author: | Stefan Kuethe [aut, cre] |
| Maintainer: | Stefan Kuethe <crazycapivara at gmail.com> |
| BugReports: | https://github.com/crazycapivara/deckgl/issues/ |
| License: | MIT + file LICENSE |
| URL: | https://github.com/crazycapivara/deckgl/, https://crazycapivara.github.io/deckgl/ |
| NeedsCompilation: | no |
| Materials: | README NEWS |
| CRAN checks: | deckgl results |
| Reference manual: | deckgl.pdf |
| Vignettes: |
ArcLayer ContourLayer GeoJsonLayer GridLayer HexagonLayer IconLayer LineLayer PathLayer PointCloudLayer PolygonLayer ScatterplotLayer ScreenGridLayer Shiny integration TextLayer |
| Package source: | deckgl_0.1.8.tar.gz |
| Windows binaries: | r-devel: deckgl_0.1.8.zip, r-release: deckgl_0.1.8.zip, r-oldrel: deckgl_0.1.8.zip |
| OS X binaries: | r-release: deckgl_0.1.8.tgz, r-oldrel: deckgl_0.1.8.tgz |
Please use the canonical form https://CRAN.R-project.org/package=deckgl to link to this page.


Girl Scouts
Plans for 2017-2018
Ideas for Scout Activities
- CampingIn the winter
- Kayaking
- Escape room$18 per person. We each can contribute $10Zombie versionOctober 20 or 21Groupon?
- Harry Potter and the Sorcerer's Stone in concert 9/29
- Spook Hill
- Chocolate tour in Deytona
- Dinosaur World
- Skunk Ape Research Headquarters
- Johny the Doughnut Seed
- World's Largest Lobster
- The Bubble Room restaurant
- End of the year trip
- Service projects
- Trinity Cafe
- Total Teen Takeover Day 1/13 or 1/20
- Christmas cookie decorating


is a community-run directory of everything python in
NYC: a list of who uses python, how they use it,
and everything else.
Got questions? We've got answers!
I'm just learning...
Wonderful! Sign up as a programmer. We'll handle the details later.
I'm a recruiter, but I want to sign up as a programmer.
 We'll blacklist you if you get spammy.
I don't want to be spammed.
Neither do we. We're very clear about what's public, what's private, and how we communicate with you. We promise to be conscientious and defend your inbox and privacy with positive community-building, and if that doesn't work, then with spammer-shaming and banhammers.


--- layout: post title: My health taken a beating date: 2006-11-27 23:10:00.000000000 +11:00 type: post published: true status: publish categories: [] tags: [] meta: lj_itemid: '23' lj_permalink: http://jus4kix.livejournal.com/5894.html lj_current_mood: disappointed author: login: ajaysusarla email<EMAIL_ADDRESS>display_name: partha first_name: '' last_name: '' ---
My health took a beating yet again - i was down with diarrhea, and have lost more than a few kilos over the weekend. And all this had to happen right in time for foss.in
I missed foss.in :(
Waaahhhh!!!!


Imagine walking through the neighborhood and smelling your neighbor's apple pie or cinnamon rolls. At A Wheetly Affair we hope to remind of you of simpler, delicious times.
A Wheetly Affair is open Tuesday through Saturday, 10 am - 6 pm.Imagine walking through the neighborhood and smelling your neighbor's apple pie or cinnamon rolls. At A Wheetly Affair we hope to remind of you of simpler, delicious times.
A Wheetly Affair is open Tuesday through Saturday, 10 am - 6 pm.


Service: Baidu
Baidu
Yandex
En
EN
RU
Speed: Normal
Slow
Normal
Fast
Voice: Female-1
Female-1
Female-2
Female-3
Male-1
Male-2
Play


We believe that influencers are the designers of the future
That's why we're looking for social media's hottest tastemakers to join bodysong as founding members.
They will design their dream activewear collection and retail it on the bodysong platform, benefiting from its growth as equal partners.
You can reach us at:
creators@bodysong.co


Enter names in the fields, then click "Submit" to submit the form:
ID
Location
Timestamp
Resolution Time