Rel Doc |
Методы декларативного описания баз данных
Поля с автоматическим заданием значений
Первичные и внешние ключи таблицы
Методы формирования запросов к БД
Группировка записей и методы–агрегаторы
Методы создания объектов по их описаниям
Методы библиотеки разбиваются на две группы
Описания схемы – абстрактные, не привязанные к конкретной базе. Одно описание может работать с несколькими базами, одна база может описываться несколькими эквивалентными схемами.
Можно строить схемы для существующих баз, а затем работать через них.
Действующие примеры работы с базами: http://alpaca.teacode.com/doc/520
Схема – пространство имен, в котором определяются основные объекты базы – таблицы, индексы, последовательности и т.д.
Можно как работать в рамках схемы, заданной в СУБД по умолчанию, так и определить схему явно:
def schema(name:String!) // создание объекта схемы def defaultSchema // объект дефолтной схемы (схемы, заданной по умолчанию)
Определение таблицы в схеме по умолчанию:
def table(name:String!): Table!Определение таблицы в фиксированной схеме:
fix myschema = rel/schema('MY_SCHEMA) fix mytable = myschema.table('MY_TABLE)Объект таблицы описывается в рамках схемы
myschema
.
Поля типов данных.
Поле целых чисел:
def Table intColumn(name:String!)
Опции поля целых чисел:
def IntColumn bigInt // опция переключения на тип BIGINT def IntColumn tinyInt // опция переключения на TINYINT, пока не работает def IntColumn smallInt // опция переключения на SMALLINT, пока не работает
Поле вещественных чисел:
def Table realColumn(name:String!)
Опции поля вещественных чисел:
def RealColumn decimal(precision:Int!, scale:Int?) // тип DECIMAL(precision, scale) def RealColumn decimal(precision:Int!) // тип DECIMAL(precision)
Поле строковых значений:
def Table stringColumn(name:String!)Опции поля строковых значений:
def StringColumn char(length:Int!) // тип CHAR def StringColumn max(length:Int!) // максимальная длина – для всех типов def StringColumn clob // тип CLOB def StringColumn ignoreCase // тип VARCHAR_IGNORECASE
IdentityColumn
:
def Table identityColumn(name:String!) // реализация IDENTITY, первичный ключОпции
identityColumn
:
def _ start(ss:Int!) // первое значение, по умолчанию = 1 def _ step(st:Int!) // шаг, по умолчанию = 1
AutoIncrementColumn
:
def Table autoIncrementColumn(name:String!) // реализация AUTO_INCREMENT
Опции AutoIncrementColumn
:
def _ start(ss:Int!) // первое значение, по умолчанию = 1 def _ step(st:Int!) // шаг, по умолчанию = 1
SequenceColumn
:
def Table sequenceColumn(name:String!, seq:Sequence!)Поле, управляемое глобальной последовательностью
seq
. Позволяет организовать сквозную нумерацию записей нескольких таблиц.
def Table refColumn( name:String!, column: Column!) //
У значений данного поля тот же тип, что и у поля column
.
def _ default(val: Const!) // задание значения по умолчанию (вместо `NULL`) def _ notNull // запрещены NULL вместо значений def _ unique // все значения должны быть различными def _ comment(text:String!) // комментарий к полю
Пример формирования таблицы:
fix coffees = rel/table('COFFEES) fix id = coffees.identityColumn('ID).start(5).step(10) fix name = coffees.stringColumn('COF_NAME).char(15).unique.default("Arabica") fix price = coffees.realColumn('PRICE).decimal(4,2).notNull fix amount = coffees.intColumn('AMOUNT).bigInt
Получение полей таблицы
def Table getCols: Column* // table columns
Первичный ключ таблицы определяется с помощью
def Table setPrimary(cols: Column*)В
cols
задаются поля, которые в совокупности определяют первичный ключ. Если первичный ключ определяется полем типа identityColumn
, то в использовании setPrimary
нет необходимости.
Метод для формирования внешнего ключа таблицы:
def Table setReference(cols: Column*, refcols:Column*)Здесь
cols
– поля, формирующие внешний ключ, refcols
– поля, на которые ссылаются поля внешнего ключа. Поля cols
должны принадлежать таблице из контекста метода.
В отличие от setPrimary
, метод setReference
может быть задействован в таблице несколько раз. Это делается в случае, когда таблица содержит более одного внешнего ключа.
Если внешний ключ содержит только одно поле, то вместо общего ограничения setReference
можно использовать специальное поле refColumn
.
NULL
представляется методом rel/null
. Метод
def _ isNull: Unit?проверяет, является ли объект нулом или нет.
Описание последовательности
def sequence(name: String!) // определение последовательности в дефолтной схеме def Schema sequence(name: String!) // определение в фиксированной схеме
Опции последовательностей:
def Sequence start(ss:Int!) // стартовое значение последовательности def Sequence step(st:Int!) // шаг последовательности (может быть отрицательным)
from
:
def from(tables: Table+) def from(t1:Table!, t2:Table!) def from(t1:Table!, t2:Table!, t3:Table!) def from(t1:Table!, t2:Table!, t3:Table!, t4:Table!)
select
:
struct SelectTable = Column | Table | Arith def Query select(rt: SelectTable*) def Query select(rt0: SelectTable!, rt1: SelectTable!) ... def Query select(rt0: SelectTable!, ..., rt9: SelectTable!)
where
:
def Query where(cond: Condition!)Реализованы бинарные отношения (пока нужно вставлять в обратные кавычки).
`==`, `<`, `>`, `and`, `or`.
Оператор сортировки:
def Query `^`(params: (Column | Desc)+) ... def Query `^`(param: (Column | Desc)!, ..., param4: (Column | Desc)?) def desc(column: Column!):Desc! // упорядочить значение поля по убыванию
def Query join(table: Table!, condition: Condition!) def Query innerJoin(table: Table!, condition: Condition!) def Query leftJoin(table: Table!, condition: Condition!) def Query rightJoin(table: Table!, condition: Condition!)
Пример:
rel/from(books). join(authors, authorID `==` authorID). where((published `>` 1820)). select(title, name, surname)
Алиасы в Rel определяются с помощью метода a/1
:
def Table a(als: (String | Int)!) def Column a(als: (String | Int)!)
Здесь als
– задаваемый псевдоним таблицы или поля. В качестве алиасов могут браться как строки, так и целые числа. Для вариантов a(0),.., a(9)
имеются сокращения a0, .., a9
. Алиасы в Rel используются в постфиксном виде. Пример:
fix getspouses = rel/from(persons.a1, persons.a2). where(pid.a1 `==` spouse.a2). select(name.a1, name.a2)
Метод
def Query group(gr: Column+)группирует записи по значениям полей
gr
(может быть одно или более полей). Агрегаторы выполняют групповые операции взятия минимального и максимального значений, вычисления среднего, и общего количества строк в группе:
struct Arith = Avg | Max | Min | Sum | Count def Query max(cl: NColumn!): Max! def Query min(cl: NColumn!): Min! def Query avg(cl: NColumn!): Avg! def Query sum(cl: NColumn!): Sum! def Query count(cl: Column!): Count!Пример:
rel/from(stats). group(stats_id). select(max(temp_f), min(temp_f), avg(rain_i), stats_id)
def Table row(columns: ManualColumn*, values: Const*):Insert! def Table row(values: Const*):Insert!В одноместном
row
происходит вставка значений для всех полей, управляемых "вручную". Операция row
является абстрактной, и не привязана к СУБД. Например:
persons.row(("John", null))Чтобы осуществить эту операцию в рамках конкретной базы данных, используется метод
insert
.
Если необходимо, чтобы вставка возвращала первичный ключ вставляемой записи, используется опция key
:
Данные методы описывают операции удаления и изменения значений в таблицах.
Метод удаления строк (записей) таблиц:
def delete(table: Table!):Query!
Пример:
fix shipdel = rel/delete(shippers). where(shipperID `==` 2)
Методы, организующие изменения значений полей:
def update(table: Table!) def Query set(%:Query assign) def Query `=`(col:Column!, val:Const!)
Для применения этих описаний в конкретных СУБД используйте метод run
в рамках транзакций.
Индексы (наряду со схемами, таблицами, последовательностями и строками) являются базовыми объектами модели Rel. Объект индекса создается с помощью метода
def Table indexx(name:String!, columns:Column+)
Здесь name
– имя индекса, columns
– индексируемые столбцы. Если столбцов несколько, то все они должны принадлежать одной таблице. Для индекса доступны следующие опции:
def Indexx hash // хэш-индекс (для таблиц в памяти, для остальных игнорируется) def Indexx unique // запрещаются повторения значений
Пример создания объекта индекса:
fix idx1 = table1.indexx('IDX_1, (col1, col2)). unique
Все методы, представленные выше, обеспечивают абстрактное описание структуры базы данных, и не привязаны к конкретной СУБД. Для применения этих описаний к конкретным базам данных используются следующие методы.
def db(base:Base!)Здесь
base
– хендлер реляционной БД. Примеры (СУБД H2):
use com/teacode/rel use libretto/h2 def main = { fix tempbase = rel/db(h2/temp) fix permbase = rel/db( h2/dir(io/p("bases/forms1")) ) ... }
def Schema create // создание схемы в БД def Table create // создание таблицы в БД def Sequence create // создание глобальной последовательности в БД def Indexx create // создание индекса в БД
def Schema drop // удаление схемы из БД def Table drop // удаление таблицы из БД def Sequence drop // удаление глобальной последовательности из БД def Indexx drop // удаление индекса из БД
def Insert insertМетоды создания и вставки выполняются в контексте транзакции СУБД:
use com/teacode/rel use libretto/h2 use libretto/io def main = { fix persons = rel/table("PERSONS") fix name = persons.stringColumn('NAME) fix insJohn = persons.row(("John")) fix permbase = rel/db( h2/dir(io/p("bases/forms1")) ) permbase.w: { persons.create fix johnPrimaryKey = insJohn.key.insert } }Опция
key
позволяет получить и присвоить переменной johnPrimaryKey
первичный ключ только что вставленной строки.
Метод out
запускает запросы в базе данных – в рамках транзакции. Пример:
fix q = rel/from(climate). group(quarter). select(city, quarter, count(quarter), min(temp), max(temp)) fix result = q.out
Результат выполнения запроса (метода out
) представляется в виде структур Result
и Row
:
struct Const = Real | String | Int | Null | Boolean struct Result(columns: (Column|Arith)*, rows: Row*) struct Row(vals: Const*)
Поле columns
содержит объекты полей или арифметических операций.
Поле rows
– последовательность объектов Row
, каждый из которых представляет строку ответа – последовательность объектов структуры Const
.
Методы получения значений:
// взятие значения у поля номер col строки номер row def Result get(row:Int!, col:Int!) // взятие в первой строке поля с номером col def Result get(col:Int!) // взятие целочисленного значения или пустоты (для NULL) // в поле номер col строки номер row def Result intNull(row:Int!, col:Int!) // взятие целочисленного значения или пустоты (для NULL) // в поле номер col первой строки def Result intNull(col:Int!) // взятие целочисленного значения или пустоты (для null) // в поле номер col данной строки def Row intNull(col:Int!) // получение целых чисел без null: def Result int(row:Int!, col:Int!):Int! def Result int(col:Int!):Int! def Row int(col:Int!):Int!
Аналогично для строк и вещественных чисел:
def Result stringNull(row:Int!, col:Int!):String? def Result stringNull(col:Int!):String? def Row stringNull(col:Int!):String? def Result string(row:Int!, col:Int!):String! def Result string(col:Int!):String! def Row string(col:Int!):String! def Result realNull(row:Int!, col:Int!):Real? def Result realNull(col:Int!):Real? def Row realNull(col:Int!):Real? def Result real(row:Int!, col:Int!):Real! def Result real(col:Int!):Real! def Row real(col:Int!):Real!
Взятие всех значений столбца (соответствующего поля из каждой строки)
def Result getCol(col:Int!):Const*
и всех полей строки:
def Result getRow(row:Int!):Const*
Проверка результата запроса на пустоту:
def Result empty def Result nonEmpty
Метод run
исполняет запросы на удаление и изменение значений в конкретных базах данных.
Пример:
fix shipupdate = rel/update(shippers). where(shipperID `==` 1). set: { shipperName `=` "Hehe Packing" phone `=` "223-322" } ... permbase.w: { shipupdate.run }