diff --git a/repository/Brea-Tests/BreaQueryTest.class.st b/repository/Brea-Tests/BreaQueryTest.class.st new file mode 100644 index 0000000..1917fb2 --- /dev/null +++ b/repository/Brea-Tests/BreaQueryTest.class.st @@ -0,0 +1,21 @@ +" +A BreaQueryTest is a test class for testing the behavior of BreaQuery +" +Class { + #name : #BreaQueryTest, + #superclass : #TestCase, + #category : #'Brea-Tests' +} + +{ #category : #tests } +BreaQueryTest >> testSTONSerialization [ + + | original store deserialized | + original := BreaQuery new + name: 'plus'; + inputs: {'a' -> 3. 'b' -> 4} asDictionary; + codeBlock: [ :x :y | x + y ]. + store := STON toString: original. + deserialized := (STONReader on: store readStream) next. + self assert: original execute equals: deserialized execute +] diff --git a/repository/Brea/Airtable.class.st b/repository/Brea/Airtable.class.st new file mode 100644 index 0000000..c3f8896 --- /dev/null +++ b/repository/Brea/Airtable.class.st @@ -0,0 +1,51 @@ +" +I model an Airtable (https://airtable.com/) database (or Base as they call it). +" +Class { + #name : #Airtable, + #superclass : #Object, + #instVars : [ + 'id', + 'apiKey' + ], + #category : #Brea +} + +{ #category : #accessing } +Airtable >> apiKey [ + ^ apiKey +] + +{ #category : #accessing } +Airtable >> apiKey: aString [ + apiKey := aString +] + +{ #category : #accessing } +Airtable >> id [ + ^ id +] + +{ #category : #accessing } +Airtable >> id: aString [ + id := aString +] + +{ #category : #'as yet unclassified' } +Airtable >> rawRecords [ + + (self id isNil or: [ self apiKey isNil ]) ifTrue: [ ^ self ]. + ^ ZnClient new + url: (self id); + headerAt: 'Authorization' put: 'Bearer ', (self apiKey); + get. + +] + +{ #category : #'as yet unclassified' } +Airtable >> records [ + + ^ ((NeoJSONReader fromString: (self rawRecords)) at: 'records') + select: [ :each | (each at: 'fields') isNotEmpty ] + +] diff --git a/repository/Brea/BlockClosure.extension.st b/repository/Brea/BlockClosure.extension.st new file mode 100644 index 0000000..ce06ce6 --- /dev/null +++ b/repository/Brea/BlockClosure.extension.st @@ -0,0 +1,20 @@ +Extension { #name : #BlockClosure } + +{ #category : #'*Brea' } +BlockClosure class >> fromSton: stonReader [ + ^ self compilerClass new + source: stonReader parseListSingleton; + evaluate +] + +{ #category : #'*Brea' } +BlockClosure >> stonContainSubObjects [ + ^ false +] + +{ #category : #'*Brea' } +BlockClosure >> stonOn: stonWriter [ + self isClean + ifTrue: [ stonWriter writeObject: self listSingleton: self printString ] + ifFalse: [ stonWriter error: 'Only clean block can be serialized' ] +] diff --git a/repository/Brea/BreaQuery.class.st b/repository/Brea/BreaQuery.class.st new file mode 100644 index 0000000..789f0d5 --- /dev/null +++ b/repository/Brea/BreaQuery.class.st @@ -0,0 +1,95 @@ +" +I represent a operation that can be done on data inputs to produce and output by executing +a code block. + +I can be used by BreaThemes to produce outpus reflected in a particular set of theme pages. + + +- (for bonus points) how to create instances. + + One simple example is simply gorgeous. + +Internal Representation and Key Implementation Points. + + Instance Variables + codeBlock: + inputs: + name: + + + Implementation Points +" +Class { + #name : #BreaQuery, + #superclass : #Object, + #instVars : [ + 'name', + 'inputs', + 'codeBlock', + 'cleanedInputs' + ], + #category : #Brea +} + +{ #category : #converting } +BreaQuery >> asSton [ + ^ STON toStringPretty: self +] + +{ #category : #converting } +BreaQuery >> cleanInputs [ + self cleanedInputs ifNil: [ ^ self ]. + self cleanedInputs ifTrue: [ + self inputs keysAndValuesDo: [ :k :v | | currentValue | + currentValue := self inputs at: k. + self inputs at: k put: currentValue class new + ] + ]. +] + +{ #category : #accessing } +BreaQuery >> cleanedInputs [ + ^ cleanedInputs +] + +{ #category : #accessing } +BreaQuery >> cleanedInputs: aBoolean [ + "I tell if the inputs should be cleaned when the query is serialized as STON, for + example when they contain sensible information, like API keys or passwords" + cleanedInputs := aBoolean +] + +{ #category : #accessing } +BreaQuery >> codeBlock [ + ^ codeBlock +] + +{ #category : #accessing } +BreaQuery >> codeBlock: anObject [ + codeBlock := anObject +] + +{ #category : #execution } +BreaQuery >> execute [ + ^ self codeBlock valueWithArguments: self inputs values. +] + +{ #category : #accessing } +BreaQuery >> inputs [ + ^ inputs +] + +{ #category : #accessing } +BreaQuery >> inputs: anOrderedDictionary [ + inputs := anOrderedDictionary +] + +{ #category : #accessing } +BreaQuery >> name [ + ^ name +] + +{ #category : #accessing } +BreaQuery >> name: anObject [ + name := anObject +] diff --git a/repository/Brea/BreaTheme.class.st b/repository/Brea/BreaTheme.class.st index 8dc2f20..bc020b0 100644 --- a/repository/Brea/BreaTheme.class.st +++ b/repository/Brea/BreaTheme.class.st @@ -27,11 +27,12 @@ Class { #superclass : #Object, #instVars : [ 'name', + 'folder', 'provider', 'url', 'preview', 'license', - 'folder', + 'queries', 'customizations' ], #category : #Brea @@ -101,6 +102,16 @@ BreaTheme class >> downloadLinks [ ^ result ] +{ #category : #operation } +BreaTheme >> addQuery: aBreaQuery [ + self queries add: aBreaQuery cleanInputs +] + +{ #category : #operation } +BreaTheme >> asSton [ + ^ STON toStringPretty: self +] + { #category : #utilities } BreaTheme >> dashedName [ ^ self name asDashedLowercase @@ -148,7 +159,7 @@ BreaTheme >> license: anObject [ license := anObject ] -{ #category : #'as yet unclassified' } +{ #category : #operation } BreaTheme >> loadConfiguration [ | config | config := self folder / 'brea.yaml'. @@ -193,6 +204,16 @@ BreaTheme >> provider: anObject [ provider := anObject ] +{ #category : #accessing } +BreaTheme >> queries [ + ^ queries ifNil: [ queries := OrderedCollection new ] +] + +{ #category : #accessing } +BreaTheme >> queries: cleanedBreaQueriesCollection [ + queries := cleanedBreaQueriesCollection +] + { #category : #accessing } BreaTheme >> url [ ^ url ifNil: [ url := self class downloadLinks at: self name. ]