Top Banner
Advanced O/R Mapping with Glorp Alan Knight ([email protected]) Cincom Systems of Canada
35

Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Jul 09, 2020

Download

Documents

dariahiddleston
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Advanced O/R Mapping with Glorp

Alan Knight ([email protected])Cincom Systems of Canada

Page 2: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Metaphor/Motivating Example

Ruby on Rails/ActiveRecordReading Database Schema

» Some interesting mapping issuesCreating Mappings Dynamically

» Conventions/GrammarAPIs

» Querying» Globals, Singletons, Transactions

Schema EvolutionWeb Integration

Page 3: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Ruby on Rails

“Opinionated software”Rails

Go really fast, but only in one directionReaction against J2EE/.NET“Greenfield” projectsRuby-Based

Smalltalk-like, scripting languageSome very Smalltalkish “tricks” in rails

ActiveRecord pattern for persistence

Page 4: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Architecture: Glorp and ActiveRecord

Metadata vs. convention-drivenGlorp: Explicit metadata

TablesClassesDescriptors/Mappings

ActiveRecordStrict naming conventionsAware of language formsHints at the class levelCode Generation (mostly for web)

Page 5: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

BrokersGlorp

Single broker (session)» Responsible for object identity» Manages automatic writes

Multiple clients use multiple sessionsIndependent of other frameworks

ActiveRecordClasses as brokers

» No object identity» Single global session

Explicit writesTightly integrated with web framework

Page 6: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Domain Model

GlorpNo metadata in domain classesPremium on flexibility, ability to optimizeExpect existing classes, schema

ActiveRecordPremium on simplicityMinimal metadata, but on domain classesMay not even be a domain model

» Use ActiveRecord directly» Instance variables as properties

Page 7: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Goal

Can we provide some of the benefits,but without losing our advantages“Hyperactive Records”

Automatic persistenceConvention-drivenBut be less restrictiveUse a bit more information (constraints)Allow a graceful transition

Page 8: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Issue: Reading Schema

Before we can automate, we need toread the database schema.A nicely recursive problem

DatabaseTable•name•constraints•fields DatabaseField

•name•isPrimaryKey•type•nullable

ForeignKeyConstraint•name•sourceFields•targetFields

Page 9: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

INFORMATION_SCHEMA

Page 10: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Mapping DatabaseField

DatabaseField•name•isPrimaryKey•type•nullable

table := self tableNamed: 'columns'.(aDescriptor newMapping: DirectMapping) from: 'name' to: (table fieldNamed: 'column_name').

COLUMNS•TABLE_NAME•COLUMN_NAME•DATA_TYPE•IS_NULLABLE

Page 11: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Mapping #isPrimaryKey

ST: a boolean valueDB: primary key constraints are entitiesColumns used in a constraint are listed inkey_column_usageFor a field, do any primary key constraintsexist that make use of itMapping a two-level join to a boolean

Page 12: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Mapping #isPrimaryKey(aDescriptor newMapping: DirectMapping) from: #isPrimaryKey

to: [:each |each primaryKeyConstraints notEmpty].

Direct mapping, but to an expression“each” is the field we’re referring toprimaryKeyConstraints is anotherrelationshipnotEmpty is a subselect operation

Page 13: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

SubselectsIn queries, several “collection” operationsthat turn into different kinds of subselectsisEmpty/notEmptyselect:anySatisfy:/noneSatisfy:sqlCount (also aggregation)

read: Customer where: [:each | (each orders select: [:order | order amount > 1000]) sqlCount > 5].

Page 14: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Reading Schema Summary

sourceFields and targetFields worseInformation_schema variations, limitsWorks for Oracle, Postgresql, MySQLNo changes at all to the domain model

But easier because read-onlySeveral pseudoVariables

Good motivation for automaticmapping

Page 15: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Back to ActiveRecord

Glorp metadatadefined in DescriptorSystemMethods for tables, classes, mappingE.g. #descriptorForCustomer:Lists allTables, allClasses

Page 16: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

ActiveRecord DescriptorSystem

All subclasses of ActiveRecordRead allTables from the database

For each class name, find table nameFind link tables from constraints or hints

For each inst var/field name, figure outthe mapping

Naming conventionDatabase constraints

Page 17: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Aside: Inflector

Ruby on Rails classKnows basic grammar forms (English)Knows class/inst var/field/table namingand capitalization

Person class -> PEOPLE tableOVERDUE_ORDER_ID -> overdueOrder

Big ball of regular expressions

Page 18: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Aside: Hints

Ruby on Rails uses class data to tell ithow to create relationships that areambiguoushasMany, hasAndBelongsToManytableNames (added)

Page 19: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Aside: Class Generation

Generate a packageClass for each database table

FilteredEmpty descriptor system with rootclass

Page 20: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Incremental Setup

We want to do as little work asnecessaryHow to “tweak” an automaticallygenerated mapping#mappingNamed:do:

self mappingNamed: #bankCode do:[:mapping | mapping type: Integer].

Page 21: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Rails Migrations

Define tables in Ruby codeMultiple versions, ordered by namingconventionFirst version fullSubsequent versions define how toupgrade and downgrade

In the database, store a versionnumber for the schemaRun the instructions in sequence

Page 22: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Smalltalk Migrations

We have full metadata definition oftablesKeep multiple classes

Subclasses?Modify the schema to conform to thenewestPrototype level

No upgrading instructions, can lose dataJumps directly from one to the other

Page 23: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Web Integration

Equivalent to automatic web formsMagritteGlorp (Ramon Leon)

Extend Magritte with additionalinformation about relationship typesGenerate Glorp descriptors based onMagritte metadata

Page 24: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Web Integration

GlorpActiveRecordMagritteSupportMagritte metadata based on Glorp

Assume Magritte editor based on datatype

Glorp metadata based on database

Page 25: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

References

GLORPhttp://www.glorp.orghttp://glorp.sourceforge.net

Ruby on Railshttp://www.rubyonrails.org/Lots of other links

Page 26: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

The End

Page 27: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Subselects

In SQL terms, a nested queryMany different uses

tend to make the brain hurtGlorp provides various shortcuts forspecific Smalltalk semantics, plus ageneral mechanism

sometimes also make the brain hurtstill settling on semantics, naming

Page 28: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Subselect Example

e.g.… where: [:each | each membersanySatisfy: [:eachMember | eachMembername like: 'Alan%']].

SELECT <project fields>

FROM PROJECT t1

WHERE EXISTS (

SELECT <whatever> FROM MEMBER s1t1 WHERE

s1t1.proj_id = t1.id)

Page 29: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

AggregatingTwo forms of aggregatingAt the query level

aQuery retrieve: [:each | each value sum]Puts an aggregate into the fields of the SQLSELECT ... SUM(t1.value)

Within a where clausewhere: [:each | (each value sqlSum) > 10]Creates a subselect of that aggregateSELECT ... WHERE (SELECTSUM(s1t1.value) FROM ... WHERE ...)> 10

min, max, average, count, etc.

Page 30: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Still More Aggregating

Also within a where clause expression count: [:x | x attribute]

or more generally expression

count: [:x | x attribute]

where: [:x | x something = 5].

More awkward than expression sqlCount

Not really more powerful

Page 31: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

General Aggregations

General facilityread: GlorpCustomer

where: [:each | each

(each aggregate: each accounts

as: #countStar

where: [:acct | acct price > 1000]])

= 1].

Really awkwardMore general

Only requires the underlying function toexist

Page 32: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Select:

count:where: suggests a moreSmalltalk-like form

where: [:each |

(each users select: [:eachUser |

eachUser name like: 'A%])

sqlCount > 3].

Or we could apply other operationse.g. anySatisfy: to the filteredcollection.

Page 33: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Fully General Subselects

A subselect is represented by a query.aCustomer accounts

anySatisfyExists: [:eachAccount |

eachAccount in:

(Query

read: GlorpBankAccount

where: [:acct |

acct balance < 100])]].

Very general, but awkwardOften putting queries into block temps,setting retrieve: clauses, etc.

Page 34: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

Correlated Subselects

Are the internal selects effectively constants,or do they refer back to things in outerqueriesSlower in database, but more powerful

read: StorePackage where: [:each |

| q |

q := Query read: StorePackage

where: [:eachPkg |

eachPkg name = each name].

q retrieve: [:x | x primaryKey max].

each username = 'aknight' & (each primaryKey= q)].

Page 35: Advanced O/R Mapping with GlorpRails Migrations Define tables in Ruby code Multiple versions, ordered by naming convention First version full Subsequent versions define how to upgrade

OK, No More Subselects

Yes, these are complicatedSometimes you need themThe tests are a good resource for codefragments to copy fromOr just experiment until you get SQL(and results) you want