Personal Pascal Peas

Планы, идеология, архитектура и т.п.

Модератор: Модераторы

Personal Pascal Peas

Сообщение Brainenjii » 14.06.2012 23:03:04

Публикую свой кодогенератор и ищу сочувствующих ^_^
Суть такова - по json описанию классовой модели генерируется набор исходников для "транзакционной" модели работы с объектами. Подробнее - здесь.
На конкретном примере:
{
  "kind": 0,
  "version": 0,
  "peas": [{
    "id": 100,
    "caption": "PeaValue",
    "pluralCaption": "PeaValues",
    "sqlCaption": "PEA_VALUE",
    "kind": "plain",
    "properties": [{
      "caption": "Caption",
      "sqlCaption": "CAPTION",
      "kind": "string"
    }, {
      "caption": "IntValue",
      "sqlCaption": "INT_VALUE",
      "kind": "integer"
    }, {
      "caption": "Caption",
      "pluralCaption": "Captions",
      "sqlCaption": "CAPTIONS",
      "kind": "strings"
    }, {
      "caption": "MyIntValue",
      "pluralCaption": "MyIntValues",
      "sqlCaption": "MY_INT_VALUES",
      "kind": "integers"
    }]
  }, {
    "id": 105,
    "caption": "PeaValueHolder",
    "pluralCaption": "PeaValueHolder",
    "sqlCaption": "PEA_VALUE_HOLDER",
    "kind": "holder",
    "pea": "PeaValue",
    "properties": [{
      "caption": "SomeCaption",
      "sqlCaption": "SOME_CAPTION",
      "kind": "string"
    },{
      "caption": "SomeInt",
      "sqlCaption": "SOME_INT",
      "kind": "integer"
    }]
  }, {
    "id": 110,
    "caption": "PeaContainer",
    "pluralCaption": "PeaContainers",
    "sqlCaption": "PEA_CONTAINER",
    "kind": "plain",
    "properties": [{
      "caption": "Caption",
      "sqlCaption": "CAPTION",
      "kind": "string"
    }, {
      "caption": "Link",
      "sqlCaption": "LINK",
      "kind": "pea",
      "pea": "PeaValue"
    },{
      "caption": "HugePeaValue",
      "pluralCaption": "HugePeaValues",
      "sqlCaption": "HUGE_PEA_VALUES",
      "kind": "holders",
      "pea": "PeaValueHolder"      
    }, {
      "caption": "PeaValueFirst",
      "pluralCaption": "PeaValuesFirst",
      "sqlCaption": "PEA_VALUE_FIRST",
      "kind": "peas",
      "pea": "PeaValue"
    }, {
      "caption": "PeaValueLast",
      "pluralCaption": "PeaValuesLast",
      "sqlCaption": "PEA_VALUE_LAST",
      "kind": "peas",
      "pea": "PeaValue"
    }]
  }]
}это то самое json описание. После применения кодогенератора появятся три исходника
BPeaContainerUnit
BPeaValueHolderUnit
BPeaValueUnit
И SQL скрипт (объединил в один файл)
И теперь то, ради чего все затевалось:
Код: Выделить всё
program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}cthreads,{$ENDIF}
  BQueryUnit, BPeaValueUnit
  { you can add units after this };

Var
  aManager, aOtherManager: BPeaValuesManagerClass;
  aPeaValue, aBuffer: BPeaValueClass;
begin
  // Вызывается лишь единожды при старте программы - регистрирует базу
  DBManager.AddDatabase(DB_FB, 'localhost', 'dummy', 'SYSDBA', 'masterkey');
  DBManager.Connect;
  aManager := BPeaValuesManagerClass.Build;
  aOtherManager := BPeaValuesManagerClass.Build;
  Try
    aPeaValue := aManager.AddObject;
    aPeaValue.Initialize('Text', 100);

    aBuffer := aOtherManager.GetObject(aPeaValue.ID);
    If aBuffer = nil Then
      WriteLn('Второй менеджер ничего не знает об первом объекте');
    aManager.Commit;
    aBuffer := aOtherManager.GetObject(aPeaValue.ID);
    If aBuffer = nil Then
      WriteLn('Теперь уже знает')
    Else
      WriteLn(aBuffer.Caption);
  Finally
    aManager.Burn;
    aOtherManager.Burn;
  End;
end.

В таблице PEAVALUE появится соответствующая запись ^_^
Последний раз редактировалось Brainenjii 19.06.2012 09:38:16, всего редактировалось 1 раз.
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Personal Pascal Peas

Сообщение Brainenjii » 17.06.2012 14:16:06

Ех... Если есть какие-то вопросы - буду рад услышать ^_^
Немного описания ^_^
PPP - это генератор объектной модели для реляционных баз данных (пока только firebird). Задача - сконцентрировать работу с Базой Данных в методах Save и Load, хотя цель полностью абстрагироваться от базы не преследуется (но для многих проектов будет достаточно возможностях, предоставляемых объектной моделью). На данный момент генерируемый код не умеет получать объекты из базы по запросу, т.е. загружает сразу все объекты определённого типа, что довольно сильно ограничивает его применение, однако его можно использовать как основу для реализации данной задачи. Забегая вперёд, загрузку по запросу планируется указывать для объектов свойством onDemand: true.
Каждый объект модели называется горошиной (pea), в пику джавовским бобам ^_^
Весь код генерируется по описанию peas.json в формате, похожем на JSON. Свойства:
  • version - версия описания. Пока не используется, но в последствии будет сохраняться в комментариях к сгенерированным исходникам.
  • projectName - название проекта, для которых генерируется исходники. Пока тоже не используется, но будет нужен для формирования загрузчика и т.п.
  • podKind - вид базы данных. Пока поддерживается только firebird, не сложно реализовать и для других СУБД (дополнить методы загрузки и сохранения).
  • peas - массив горошин.
Каждая горошина - это JS literal-object. Его свойства:
  • id - уникальный номер класса. Доступ к нему можно получить из свойства ClassID
  • caption/pluralCaption - название класса и название во множественном числе. В sql скрипте создаётся одноименное название таблицы в верхнем регистре.
  • kind - тип горошины. Возможные значения:
    • plain - обычный объект с уникальным идентификатором (ID);
    • tree - объект с иерархическими связями - ссылкой на родителя, следующий и предыдущий объект;
    • holder - "держатель". Особая горошина, не имеет собственного ID. Использует ID держимого объекта. Используется, чтобы добавить какие-то параметры при использовании в качестве параметра к другой горошине
    • simple - не реализовано. Простая горошина. ID не имеет в принципе. Используется, чтобы миновать механизм менеджеров.
  • onDemand - не реализовано. Будет использоваться для определения - загружаются ли все соответствующие объекты сразу, или по запросу.
  • properties - массив свойств горошины.
    • caption/pluralCaption/sqlCaption - наименование свойства (во множественном числе и для sql скриптов)
    • kind - тип свойства. Могут быть следующие типы:
      • string,integer,double,date,datetime,time,boolean - элементарные типы
      • strings,integers,doubles,datetimes,booleans - списки элементарных типов. Пока под каждое такое поле заводится отдельная таблица. Возможно есть смысл объединить в одну, или сделать это опцией в отдельное поле к свойству
      • pea - ссылка на горошину. Обязательно указать поле pea у самого свойства.
      • peas - список горошин. Обязательно указать поле pea у самого свойства.
      • holders - список "держателей" горошин с соответствующими свойствами. Создаёт набор таблиц. Обязательно указать поле pea у самого свойства, причем тип горошины должен быть holder
    • onDemand - см. соответствующее свойство самой горошины
    • pea - ссылка на горошину, представляющее свойство
Вот как-то так ^_^
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Personal Pascal Peas

Сообщение vada » 18.06.2012 11:59:01

Прелестно! Прелестно! Идея очень понравилась. Буду знакомиться.
ЗЫ. С горошиной это вы здорово! Выборку можно стручком назвать :)
Аватара пользователя
vada
энтузиаст
 
Сообщения: 691
Зарегистрирован: 14.02.2006 13:43:17

Re: Personal Pascal Peas

Сообщение B4rr4cuda » 18.06.2012 20:28:07

Очень любопытная идея. Надо будет пощупать.
Аватара пользователя
B4rr4cuda
энтузиаст
 
Сообщения: 693
Зарегистрирован: 28.12.2007 07:48:35

Re: Personal Pascal Peas

Сообщение Brainenjii » 18.06.2012 21:59:37

Спасибо! ^_^
Несколько дополнений по держателям (теперь свойством держателя может быть другой держатель и т.д.) и начата работа на Controller'ами. Перед ними я вижу следующие задачи:
  • 1. Сериализация/десериализация горошин в формат JSON (нравится он мне ^_^)
  • 2. Организовать работу с менеджерами, принимая в параметры только элементарные типы (строки, числа и т.д.)
Поскольку последнее время я увлёкся веб-интерфейсами, вопрос обмена данными с представлением только через строки (не знаю, как передать запись или, того краше, объект через AJAX) для меня довольно важен. Плюс, такие контроллеры - задел на "сетевую прозрачность" горошин ^_^ Параллельно с реальным контроллером будет создаваться болванка контроллера, вызовы методов которой будут отправляться по сети настоящему контроллеру, который будет выполнять реальные действия и возвращать болванке результат (все теми же примитивными типами). По-моему, вполне реально ^_^
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Personal Pascal Peas

Сообщение Brainenjii » 27.06.2012 23:57:23

Ещё одна порция обновлений. Продолжена работа над парсингом JSON (десериализацией).
Напомню про механизм управляющих (*ManagerClass) и управляемых классов. Для каждой горошины строится 3 класса:
  • собственно сам класс с данными. Название строится как B<Caption>Class. В дальнейшем просто горошина или управляемый класс.
  • класс, осуществляющий "транзакционный" режим работы. Название строится как B<PluralCaption>ManagerClass. В дальнейшем менеджер или управляющий класс. Может быть есть смысл называть "Стручком" ^_^
  • класс, оборачивающий работу с менеджером в вызовы методов, параметры которых представлены только простыми типами. Я называю его контроллером и потому название строится как B<PluralCaption>ControllerClass.
Теперь обо всём этом подробнее ^_^ И чтобы было проще - попробуем разобраться на примере (а заодно может для маман так и доделаю плёвую программку по расчету рейтинга :-D).
Задача такая. Есть школа, а значит учителя, классы, ученики, контрольные, оценки и т.д. Нужно, чтобы преподаватель мог назначить контрольные, которым назначается максимальное количество баллов и "значимость" этой контрольной в учебном году. Затем, проставив сколько ученик набрал баллов из максимально возможного за контрольную, учитель возвращается результат - кто какую оценку получил, и как это повлияло на оценку ученика за год/четверть. Итак, начнём формировать наше JSON описание классовой модели:
Код: Выделить всё
{
  "version": 0,
  "projectName": "School",
  "podKind": "firebird",
  "peas": [{
    "id": 100,
    "caption": "Pupil",
    "pluralCaption": "Pupils",
    "kind": "plain",
    "properties": [{
      "caption": "FirstName",
      "sqlCaption": "FIRSTNAME",
      "kind": "string"
    }, {
      "caption": "MiddleName",
      "sqlCaption": "MIDDLENAME",
      "kind": "string"
    }, {
      "caption": "LastName",
      "sqlCaption": "LASTNAME",
      "kind": "string"
    }]
  }, {
    "id": 110,
    "caption": "Grade",
    "pluralCaption": "Grades",
    "kind": "plain",
    "properties": [{
      "caption": "Parallel",
      "sqlCaption": "PARALLEL",
      "kind": "integer"
    },{
      "caption": "Literal",
      "sqlCaption": "LITERAL",
      "kind": "string"
    },{
      "caption": "Pupil",
      "pluralCaption": "Pupils",
      "sqlCaption": "PUPILS",
      "kind": "peas",
      "pea": "Pupil"
    }]
  }, {
    "id": 120,
    "caption": "Teacher",
    "pluralCaption": "Teacher",
    "kind": "plain",
    "properties": [{
      "caption": "FirstName",
      "sqlCaption": "FIRSTNAME",
      "kind": "string"
    }, {
      "caption": "MiddleName",
      "sqlCaption": "MIDDLENAME",
      "kind": "string"
    }, {
      "caption": "LastName",
      "sqlCaption": "LASTNAME",
      "kind": "string"
    },{
      "caption": "Grade",
      "pluralCaption": "Grades",
      "sqlCaption": "GRADES",
      "kind": "peas",
      "pea": "Grade"
    }]
  }]
}

Начну с менеджеров. Эти классы упорядочивают работу с горошинами. Каждый менеджер содержит 2 списка горошин - основной (объявлен с ключевым словом Static) и частный - создаётся вместе с экземпляром менеджера.
В несколько отдалённом будущем планируется в конструкторе менеджера указывать флаг ReadOnly, при котором частный список создаваться не будет и вообще многие проверки будут неактуальными - некоторый запас "оптимизации" ^_^
"Транзакционность" работы с объектами заключается в следующем - новые/удаляемые/редактируемые горошины не сразу создаются/удаляются/редактируются в основном списке, а через вызовы соответствующих методов менеджеров, которые будут создавать копии горошин, помещаемые в частный список менеджера. И в общий список изменения попадают только после вызова метода Commit. Так же, метод Commit инициирует запись изменений в базу данных.
В более близком будущем планируется делать "двуфазный" коммит - когда сам Commit подготавливает все изменения для записи в статический список горошин, а запросы к базе данных выполняются, но без вызова Commit у транзакции до тех пор пока не будет вызван метод FinalCommit (условно). Это потребуется, когда одна горошина будет вызывать изменений многих других.
Несколько основных методов менеджеров:
  • AddObject - регистрирует новый объект в частном списке горошин текущего экземпляра менеджера с флагом "Новый"
  • ChangeObject - создаёт клон объекта и помещает её в частный список и ставит ей флаг "Изменён"
  • DeleteObject - вызывает ChangeObject, а затем помечает клон на удаление
  • Commit - пробегается по частному списку, вызывает у каждого объекта в нём метод Save и если всё хорошо - отправляет изменения в основной список горошин.
  • Load - загружает пока все горошины из базы
Таким образом, чтобы завести нового ученика в базу нам потребуется:
Код: Выделить всё
Var
  aManager: BPupilsManagerClass; // класс менеджера
  aPupil: BPupilClass; // собственно сам класс ученика
Begin
  // 1. Создаём менеджера учеников
  aManager := BPupilsManagerClass.Build;
  // 2. Регистрируем нового ученика.
  aPupil := aManager.AddObject;
  // 3. Заполняем поля объекта BPupilClass (об этом в следующий раз ^_^)
  aPupil.Initilize('Иван', 'Иванович', 'Иванов');
  // 4. Вызываем Commit
  aManager.Commit;
  // 5. Подчищаем за собой - уничтожаем менеджер
  aManager.Burn;
End;

Всё, ученик создан (если, конечно, заменили дефолтную реализацию валидации горошины Pupic ^_^).
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Personal Pascal Peas

Сообщение Kitayets » 28.06.2012 01:35:50

это всё очень круто, но можно мне немного объяснить - для чего это может понадобится? какой-нибудь пример архитектуры приложения + задачу которую оно должно решать, так чтобы потребовался данный механизм. Можно и ссылку на ресурс/ книгу с описанием и реализацией таких задач.
Kitayets
постоялец
 
Сообщения: 171
Зарегистрирован: 05.05.2010 21:15:24

Re: Personal Pascal Peas

Сообщение Brainenjii » 28.06.2012 08:19:10

В общем случае, это может понадобиться, когда вы хотите абстрагироваться от БД, как обычного носителя данных (до тех пор, пока не потребуются сложные запросы с соединениями и т.п.).
По поводу архитектуры - наибольший плюс должен быть при трёхзвенке. Пример - как оно будет - попытаюсь разобрать на примере вышеуказанного проекта.
Что касается задачи - она одна ^_^ Иметь возможность изменять объект так, чтобы все изменения могли проводиться/откатываться без задействования СУБД. В некотором плане я пытаюсь повторить механизм Commit/Rollback СУБД на уровне объектной модели. Зачем - ответ выше - чтобы абстрагироваться от БД
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Personal Pascal Peas

Сообщение alexs » 28.06.2012 13:57:20

Brainenjii
А почему вы не хотите работать с БД напрямую?
Зачем изобретать свой велосипед, вместо того чтобы использовтаь все 100% возможностей, которые вам даст СУБД?
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4060
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Re: Personal Pascal Peas

Сообщение Brainenjii » 28.06.2012 14:36:45

Хм. Мешать pascal и SQL код мне просто не нравится ^_^ Внутренне ^_^ Работать с датасетами/запросами напрямую - тоже.
Обернуть строку выборки из запроса в объект и затем работать с ним - это же просто удобнее.
Но чтобы обернуть запрос в объект - нужно указывать все поля, типы, списки... Каждое изменение структуры БД - муторное изменение кода во всех местах где оно встречается...
Можно было, конечно, пойти путём замены существующих менеджеров на саму СУБД и все механизмы транзакции оставить ей, а кодогенератор только бы занимался вопросами сохранения/чтения и структуры БД. Это, по сути, и будет то самое OnDemand свойство, о котором упоминал во втором посте. Механизм менеджеров создавался, чтобы обеспечить максимально быстрый доступ к объектам, доступ к которым нужен постоянно.
Как-то так ^_^
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Personal Pascal Peas

Сообщение alexs » 28.06.2012 18:02:16

Brainenjii писал(а): Каждое изменение структуры БД - муторное изменение кода во всех местах где оно встречается...

Brainenjii писал(а):Работать с датасетами/запросами напрямую - тоже.

Brainenjii писал(а):Обернуть строку выборки из запроса в объект и затем работать с ним - это же просто удобнее.

Вот не понял - как это?
Ваши самописные обёртки при изменении структур в БД позволят не менять логику в клиентской части? НЕ ВЕРЮ!
Просто написание программы начните с того, с чего надо - проектирование данны, которая она будет обрабатывать.
А уже потом начинайте кодить.
При грамотно описанной предметной области и хорошо проведённой декомпизиции данных ситуации с кардинальным переписываем кода не будет.
Ну а на уровне кодинга DataSet сам является хорошим представлением данных в объектную модель паскаля.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4060
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Re: Personal Pascal Peas

Сообщение Brainenjii » 28.06.2012 18:41:51

Наши самописные обёртки позволяют "забыть" о том что есть какие-то базы данных, в них какие-то поля и т.д. Править остаётся, действительно, только логику в клиентской части.
Предусмотреть всё на этапе проектирования нельзя. Самописные (и самопереписывающиеся) обертки позволяют значительно упростить внесение корректировок в данные. Честно.
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Personal Pascal Peas

Сообщение alexs » 28.06.2012 19:41:17

Brainenjii
Ваша позиция в корне не верна.
В первую очередь надо проектировать данные. А уж логика их обработки сама обрисуется.
Я вот в начале года столкнулся с таким горе-конструктором.
Вся логика на клиенте.
В СУБД - ОДНА! таблица в которой всё свалено.
На простейший вопрос - поменять флажок по умолчанию для всех пользователей разроботчики ответили - вот есть платформа - пишите код для этого.
Как вы считаете - это верное решение?
Я уж не говорю о прочих прелестях этого "тонкого" клиента (при установке на клиенте магическим образом оказывае 300 метров огрызков от .net всех версий и прочей гадости..)
PS
Почему все боятся работать с СУБД? Зачем нужен промежуточный слой переработки данных? Неужели так трудно изучить 4-ре команды?
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4060
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Re: Personal Pascal Peas

Сообщение Kemper » 28.06.2012 23:42:27

alexs писал(а):В первую очередь надо проектировать данные. А уж логика их обработки сама обрисуется.

Браво!
Kemper
новенький
 
Сообщения: 61
Зарегистрирован: 18.05.2010 00:29:44

Re: Personal Pascal Peas

Сообщение B4rr4cuda » 29.06.2012 00:20:33

Brainenjii, а я поддержу тебя.
Так получилось, что мне пришлось около года сопровождать проект какого-то гаврика, который налепил смесь логики и работы с бд в один большой кусок удобрения.

Так что на прослойки между логикой и БД теперь смотрю с большим одобрением...
Аватара пользователя
B4rr4cuda
энтузиаст
 
Сообщения: 693
Зарегистрирован: 28.12.2007 07:48:35

След.

Вернуться в Разработки на нашем сайте

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2

Рейтинг@Mail.ru