-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
P3Constraint hierarchy moved to P3 repository
P3ClientTest>>#testConstraints added
- Loading branch information
svenvc
committed
Jan 2, 2024
1 parent
8f9ee23
commit aba118a
Showing
6 changed files
with
425 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
" | ||
I am P3CheckConstraint. | ||
I am a P3Constraint. | ||
I implement SQL CHECK. | ||
I know my check clause. | ||
" | ||
Class { | ||
#name : #P3CheckConstraint, | ||
#superclass : #P3Constraint, | ||
#instVars : [ | ||
'checkClause' | ||
], | ||
#category : #'P3-Support' | ||
} | ||
|
||
{ #category : #accessing } | ||
P3CheckConstraint class >> handlesType: type [ | ||
^ type = 'CHECK' | ||
] | ||
|
||
{ #category : #accessing } | ||
P3CheckConstraint >> checkClause [ | ||
^ checkClause | ||
] | ||
|
||
{ #category : #accessing } | ||
P3CheckConstraint >> checkClause: anObject [ | ||
checkClause := anObject | ||
] | ||
|
||
{ #category : #accessing } | ||
P3CheckConstraint >> constraintType [ | ||
^ 'CHECK' | ||
] | ||
|
||
{ #category : #accessing } | ||
P3CheckConstraint >> loadDetailsUsing: client [ | ||
| statement result | | ||
super loadDetailsUsing: client. | ||
statement := client format: 'SELECT check_clause FROM information_schema.check_constraints WHERE constraint_schema = $1 AND constraint_name = $2'. | ||
result := statement query: { self constraintSchema . self constraintName }. | ||
self checkClause: result firstFieldOfFirstRecord | ||
] | ||
|
||
{ #category : #accessing } | ||
P3CheckConstraint >> sqlDescription [ | ||
^ String streamContents: [ :out | | ||
out nextPutAll: 'CHECK'. | ||
self checkClause ifNotNil: [ :clause | | ||
out space; nextPutAll: clause ] ] | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
" | ||
I am P3Constraint. | ||
I am an abstract class. | ||
I represent an SQL constraint. | ||
I have | ||
- a name | ||
- a schem:table that I am defined on | ||
- a list of columns on which I am applicable | ||
I can reproduce my SQL definition. | ||
Use me to get all constraints for a given table. | ||
My concrete subclasses implement actual constraint types. | ||
" | ||
Class { | ||
#name : #P3Constraint, | ||
#superclass : #Object, | ||
#instVars : [ | ||
'constraintSchema', | ||
'constraintName', | ||
'tableSchema', | ||
'tableName', | ||
'isDeferrable', | ||
'initiallyDeferred', | ||
'enforced', | ||
'constraintColumns' | ||
], | ||
#category : #'P3-Support' | ||
} | ||
|
||
{ #category : #accessing } | ||
P3Constraint class >> allForTable: tableName in: schemaName using: client [ | ||
| statement result specificClass constraint | | ||
statement := client format: 'SELECT constraint_schema, constraint_name, constraint_type, is_deferrable, initially_deferred, enforced FROM information_schema.table_constraints WHERE table_schema = $1 AND table_name= $2'. | ||
result := statement query: { schemaName . tableName }. | ||
^ result data collect: [ :row | | ||
specificClass := self subclasses | ||
detect: [ :each | each handlesType: row third ] | ||
ifNone: [ self error: 'unknown contraint type' ]. | ||
constraint := specificClass new. | ||
constraint | ||
tableSchema: schemaName; | ||
tableName: tableName; | ||
constraintSchema: row first; | ||
constraintName: row second; | ||
isDeferrable: row fourth = 'YES'; | ||
initiallyDeferred: row fifth = 'YES'; | ||
enforced: row = 'YES'. | ||
constraint loadDetailsUsing: client. | ||
constraint ] | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint class >> handlesType: type [ | ||
self subclassResponsibility | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint class >> referencingConstraintNamesForTable: tableName in: schemaName using: client [ | ||
"Return (table_name, constraint_name) pairs where the given schemaName:tableName is referenced. | ||
Do not return the actual constraint object as this might be costly to compute." | ||
|
||
| statement result | | ||
statement := client format: 'SELECT tc.table_name, ctu.constraint_name | ||
FROM information_schema.constraint_table_usage AS ctu, information_schema.table_constraints AS tc | ||
WHERE ctu.table_schema = $1 AND ctu.table_name = $2 AND ctu.constraint_name = tc.constraint_name AND tc.constraint_type = ''FOREIGN KEY'''. | ||
result := statement query: { schemaName . tableName }. | ||
^ result data | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> constraintColumns [ | ||
^ constraintColumns | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> constraintColumns: anObject [ | ||
constraintColumns := anObject | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> constraintName [ | ||
^ constraintName | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> constraintName: anObject [ | ||
constraintName := anObject | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> constraintSchema [ | ||
^ constraintSchema | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> constraintSchema: anObject [ | ||
constraintSchema := anObject | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> constraintType [ | ||
self subclassResponsibility | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> enforced [ | ||
^ enforced | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> enforced: anObject [ | ||
enforced := anObject | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> initiallyDeferred [ | ||
^ initiallyDeferred | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> initiallyDeferred: anObject [ | ||
initiallyDeferred := anObject | ||
] | ||
|
||
{ #category : #testing } | ||
P3Constraint >> isCheck [ | ||
^ self constraintType = 'CHECK' | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> isDeferrable [ | ||
^ isDeferrable | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> isDeferrable: anObject [ | ||
isDeferrable := anObject | ||
] | ||
|
||
{ #category : #testing } | ||
P3Constraint >> isForeignKey [ | ||
^ self constraintType = 'FOREIGN KEY' | ||
] | ||
|
||
{ #category : #testing } | ||
P3Constraint >> isPrimaryKey [ | ||
^ self constraintType = 'PRIMARY KEY' | ||
] | ||
|
||
{ #category : #testing } | ||
P3Constraint >> isUnique [ | ||
^ self constraintType = 'UNIQUE' | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> loadDetailsUsing: client [ | ||
| statement result | | ||
statement := client format: 'SELECT column_name FROM information_schema.key_column_usage WHERE constraint_schema = $1 AND constraint_name = $2'. | ||
result := statement query: { self constraintSchema . self constraintName }. | ||
self constraintColumns: result firstColumnData | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> printOn: stream [ | ||
super printOn: stream. | ||
stream nextPut: $(. | ||
self constraintName ifNotNil: [ :name | | ||
stream nextPutAll: name ]. | ||
self sqlDescription ifNotNil: [ :description | | ||
self constraintName ifNotNil: [ stream space ]. | ||
stream nextPutAll: description ]. | ||
stream nextPut: $) | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> sqlDescription [ | ||
self subclassResponsibility | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> tableName [ | ||
^ tableName | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> tableName: anObject [ | ||
tableName := anObject | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> tableSchema [ | ||
^ tableSchema | ||
] | ||
|
||
{ #category : #accessing } | ||
P3Constraint >> tableSchema: anObject [ | ||
tableSchema := anObject | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
" | ||
I am P3ForeignKeyConstraint. | ||
I am a P3Constraint. | ||
I implement SQL FOREIGN KEY. | ||
I know to table and columns that I reference. | ||
" | ||
Class { | ||
#name : #P3ForeignKeyConstraint, | ||
#superclass : #P3Constraint, | ||
#instVars : [ | ||
'foreignKeyTable', | ||
'foreignKeyColumns' | ||
], | ||
#category : #'P3-Support' | ||
} | ||
|
||
{ #category : #accessing } | ||
P3ForeignKeyConstraint class >> handlesType: type [ | ||
^ type = 'FOREIGN KEY' | ||
] | ||
|
||
{ #category : #accessing } | ||
P3ForeignKeyConstraint >> constraintType [ | ||
^ 'FOREIGN KEY' | ||
] | ||
|
||
{ #category : #accessing } | ||
P3ForeignKeyConstraint >> foreignKeyColumns [ | ||
^ foreignKeyColumns | ||
] | ||
|
||
{ #category : #accessing } | ||
P3ForeignKeyConstraint >> foreignKeyColumns: anObject [ | ||
foreignKeyColumns := anObject | ||
] | ||
|
||
{ #category : #accessing } | ||
P3ForeignKeyConstraint >> foreignKeyTable [ | ||
^ foreignKeyTable | ||
] | ||
|
||
{ #category : #accessing } | ||
P3ForeignKeyConstraint >> foreignKeyTable: anObject [ | ||
foreignKeyTable := anObject | ||
] | ||
|
||
{ #category : #accessing } | ||
P3ForeignKeyConstraint >> loadDetailsUsing: client [ | ||
| statement result | | ||
super loadDetailsUsing: client. | ||
statement := client format: 'SELECT column_name FROM information_schema.constraint_column_usage WHERE constraint_schema = $1 AND constraint_name = $2'. | ||
result := statement query: { self constraintSchema . self constraintName }. | ||
self foreignKeyColumns: result firstColumnData. | ||
statement := client format: 'SELECT table_name FROM information_schema.constraint_table_usage WHERE constraint_schema = $1 AND constraint_name = $2'. | ||
result := statement query: { self constraintSchema . self constraintName }. | ||
self foreignKeyTable: result firstFieldOfFirstRecord | ||
] | ||
|
||
{ #category : #accessing } | ||
P3ForeignKeyConstraint >> sqlDescription [ | ||
^ String streamContents: [ :out | | ||
out nextPutAll: 'FOREIGN KEY'. | ||
(self constraintColumns isEmptyOrNil | ||
or: [ self foreignKeyColumns isEmptyOrNil | ||
or: [ self foreignKeyTable isNil ] ]) | ||
ifFalse: [ | ||
out nextPutAll: ' ('; | ||
nextPutAll: ($, join: self constraintColumns); | ||
nextPutAll: ') REFERENCES '; | ||
nextPutAll: self foreignKeyTable; | ||
nextPut: $(; | ||
nextPutAll: ($, join: self foreignKeyColumns); | ||
nextPut: $) ] ] | ||
] |
Oops, something went wrong.