Repository files navigation

purescript-sequelize

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

LICENSE

https://github.com/juspay/purescript-sequelize/blob/master/LICENSE

Usage

Connections

Before we can do anything, we need to have configuration information for our database. That means things like database type (SQLite, PostgreSQL, etc), username/password (if any), port, and so on.

In JS that would be done like so:

constSequelize=require('sequelize');constsequelize=newSequelize({database: "myAwesomeDatabase",dialect: "sqlite",storage: "./awesome.sqlite"});

In PS, the type of sequelize would be Conn. There is one way to get a value of this type:

getConn
::foralle
. OptionsConnOpts->Aff ( sequelize::SEQUELIZE | e ) Conn

And we can use it like so:

myConn::foralle. Aff (sequelize::SEQUELIZE | e) Conn
myConn = getConn opts
 where
opts = database := "myAwesomeDatabase"
<> dialect := SQLite
<> storage := "./awesome.sqlite"

Now that we have a connection to our database, we can start defining our tables via Sequelize's concept of a model.

Models

In PS, we use data types to represent Sequelize models. Let's say we have a database of users:

newtypeUser = User{name::String, age::Int}

This means we want to have a table in the database for all our users, with one row that holds their name.

Sequelize lets you define models using objects where keys are table columns names and values are options on those columns:

constuser=sequelize.define("user",{name: {type: Sequelize.STRING(255),defaultValue: "me"},age: {type: Sequelize.INTEGER(255),defaultValue: 20}},{});

In order to pass an object like this to Sequelize, we'll need to transform any value of type User to a Foreign js object. To that end, we'll derive some instances:

derive instanceeqUser :: EqUserderive instancegenericUser :: GenericUser_instanceshowUser :: ShowUserwhere
show = genericShow
instancedecodeUser :: DecodeUserwhere
decode x = genericDecodeModel x
instanceencodeUser :: EncodeUserwhere
encode x = genericEncodeModel x
instanceencodeModelUser :: EncodeModelUserwhere
encodeModel x = genericEncodeModel x
instancedecodeModelUser :: DecodeModelUserwhere
decodeModel x = genericDecodeModel x

The EncodeModel class is what lets Sequelize understand our PS User type.

But recall that in our JS example, we defined a default value for the name column and told Sequelize its type (STRING(255)). We also passed it a string that tells Sequelize what name to store the table as:

instanceisModelUser :: ModelUserwhere
modelCols _ = userCols
modelName _ = "user"userCols::ModelCols
userCols = ["name" /\ nameOpts, "age" /\ ageOpts]
 where
nameOpts =
columnType := ModelTypes.String {length: Nothing} <>
defaultValue := toForeign "me"
ageOpts =
columnType := ModelTypes.Integer {length: Nothing} <>
defaultValue := toForeign 20

Note the catch-all pattern match in the isModelUser instance: this is because we need a proxy to tell the compiler how to pick an appropriate definition for our columns definition and name. If we didn't have that proxy, there wouldn't be any way to tell that the string "user" and the options for our columns correspond with our User type!

Remember that in JS-land we had const user = sequelize.define(...). In PS, that means user would have type ModelOf User. There is one way of getting a ModelOf a, for any a with an instance of Model:

makeModelOf
::forallae. Modela=>Conn->OptionsModelOpts->Aff ( sequelize::SEQUELIZE | e ) (ModelOfa)

therefore we can get Sequelize's version of our model as in the following:

getModelOfUser::foralle. Aff ( sequelize::SEQUELIZE | e ) (ModelOfUser)
getModelOfUser = do
conn <- myConn
user <- makeModelOf conn mempty -- we don't want to pass any extra options
syncConn conn {force: true} -- drop the current table and recreate it
pure user

Inserting rows to our table

Suppose we have our hands on a concrete User value, for example from a registration form on our app's frontend:

user::User
user = User {name: "Jonas Valanciunas", age: 26}

Sequelize lets you do this in two general ways: by building a value that then gets saved to the database, or creating it all at one time (which is equivalent to building and then saving immediately).

Let's assume we're creating our user in one step. Then we can use:

create
::forallabe
. Submodelab=>ModelOfa->b->Aff ( sequelize::SEQUELIZE | e ) (Instanceb)

The Submodel class is just a relation between two models. For example, we might also want to obtain our user's ID from the database, but there's no way to do that since if we try to use the DecodeModel instance, we can't get any information back besides what our user's name is. Hence, we can use a supermodel that includes the name and the ID.

There is an instance for reflexivity and a function for transitivity: that is, if a has a Model instance then it's already a Submodel of itself, and if a is a submodel of b which is a submodel of c, then a is already a submodel of c. (Transitivity is not provided as an instance because it's very easy to confuse the compiler as to which instance to pick).

Retrieving data

Now we want to fetch data from our table. Note that create gave us access to a value of type Instance User: this is just an opaque type representing Sequelize's notion of an instance, that is, what happens after using queries or something like create. In fact, all our queries in PS give us access to an Instance User, like the following:

findOne
::forallabe. Submodelab=>ModelOfa->Optionsb->Aff ( sequelize::SEQUELIZE | e ) (Maybe (Instanceb))

Since this type is opaque, we need a way to go from an Instance User to a regular User. We can use instanceToModel:

instanceToModel
::foralla. Modela=>Instancea->Fa

After handling any possible errors from trying to deserialize our Instance, we can use our User value.

Using "Where"

There are two different ways to construct a "where" clause in a query. In JS we might do something like the following:

user.findAll({where: {age: 20,}});

In this example, we're matching an exact value: we want only the users whose age is exactly 20.

Or we may do something a bit more complicated:

user.findAll({where: {age: {$gte: 20}}});

In this case, we want only those users whose ages are strictly larger than 19.

WHERE

This is the simplest construction to use. All it does is let you match literal values in the row; it's the equivalent of the first JS example above:

simpleWhere::WHEREUser
simpleWhere = WHERE [Tuple"age" (Int20)]

Where

This is the more expressive construction. To write the equivalent of the second JS example:

moreComplicatedWhere::WhereUser
moreComplicatedWhere = "age" $>= 20

We can construct more complicated clauses by using the boolean $& and $| combinators:

evenMoreComplicatedWhere::WhereUser
evenMoreComplicatedWhere = "age" $>= 20 $& "age" $<= 30

And for more than two clauses conjoined by a boolean combinator, you can directly use the type constructors for Where:

nestedBooleanWhere::WhereUser
nestedBooleanWhere = Or
[ "age" $>= 20 $& "age" $<= 30
, "name" $<- [String"Pau Gasol", String"Marc Gasol"]
]

which will match any users with ages between 20 and 30 or whose names are "Pau Gasol" or "Marc Gasol".

Free monad DSL

You can also use the free monad DSL from Sequelize.Free, which is parameterized by input and output types. It comes with a default interpreter:

runCRUD::_=>ModelOfa->CRUDab ~> Aff (sequelize::SEQUELIZE | e)

as well as all the usual CRUD operations. You could use this for e.g. mocking, in which case you will need to define your own interpreter and switch it out in the appropriate place.

Installing

$ npm install --save config
$ bower install --save purescript-sequelize

About

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

Resources

Stars

16 stars

Watchers

23 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

purescript-sequelize

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

LICENSE

https://github.com/juspay/purescript-sequelize/blob/master/LICENSE

Usage

Connections

Before we can do anything, we need to have configuration information for our database. That means things like database type (SQLite, PostgreSQL, etc), username/password (if any), port, and so on.

In JS that would be done like so:

constSequelize=require('sequelize');constsequelize=newSequelize({database: "myAwesomeDatabase",dialect: "sqlite",storage: "./awesome.sqlite"});

In PS, the type of sequelize would be Conn. There is one way to get a value of this type:

getConn
::foralle
. OptionsConnOpts->Aff ( sequelize::SEQUELIZE | e ) Conn

And we can use it like so:

myConn::foralle. Aff (sequelize::SEQUELIZE | e) Conn
myConn = getConn opts
 where
opts = database := "myAwesomeDatabase"
<> dialect := SQLite
<> storage := "./awesome.sqlite"

Now that we have a connection to our database, we can start defining our tables via Sequelize's concept of a model.

Models

In PS, we use data types to represent Sequelize models. Let's say we have a database of users:

newtypeUser = User{name::String, age::Int}

This means we want to have a table in the database for all our users, with one row that holds their name.

Sequelize lets you define models using objects where keys are table columns names and values are options on those columns:

constuser=sequelize.define("user",{name: {type: Sequelize.STRING(255),defaultValue: "me"},age: {type: Sequelize.INTEGER(255),defaultValue: 20}},{});

In order to pass an object like this to Sequelize, we'll need to transform any value of type User to a Foreign js object. To that end, we'll derive some instances:

derive instanceeqUser :: EqUserderive instancegenericUser :: GenericUser_instanceshowUser :: ShowUserwhere
show = genericShow
instancedecodeUser :: DecodeUserwhere
decode x = genericDecodeModel x
instanceencodeUser :: EncodeUserwhere
encode x = genericEncodeModel x
instanceencodeModelUser :: EncodeModelUserwhere
encodeModel x = genericEncodeModel x
instancedecodeModelUser :: DecodeModelUserwhere
decodeModel x = genericDecodeModel x

The EncodeModel class is what lets Sequelize understand our PS User type.

But recall that in our JS example, we defined a default value for the name column and told Sequelize its type (STRING(255)). We also passed it a string that tells Sequelize what name to store the table as:

instanceisModelUser :: ModelUserwhere
modelCols _ = userCols
modelName _ = "user"userCols::ModelCols
userCols = ["name" /\ nameOpts, "age" /\ ageOpts]
 where
nameOpts =
columnType := ModelTypes.String {length: Nothing} <>
defaultValue := toForeign "me"
ageOpts =
columnType := ModelTypes.Integer {length: Nothing} <>
defaultValue := toForeign 20

Note the catch-all pattern match in the isModelUser instance: this is because we need a proxy to tell the compiler how to pick an appropriate definition for our columns definition and name. If we didn't have that proxy, there wouldn't be any way to tell that the string "user" and the options for our columns correspond with our User type!

Remember that in JS-land we had const user = sequelize.define(...). In PS, that means user would have type ModelOf User. There is one way of getting a ModelOf a, for any a with an instance of Model:

makeModelOf
::forallae. Modela=>Conn->OptionsModelOpts->Aff ( sequelize::SEQUELIZE | e ) (ModelOfa)

therefore we can get Sequelize's version of our model as in the following:

getModelOfUser::foralle. Aff ( sequelize::SEQUELIZE | e ) (ModelOfUser)
getModelOfUser = do
conn <- myConn
user <- makeModelOf conn mempty -- we don't want to pass any extra options
syncConn conn {force: true} -- drop the current table and recreate it
pure user

Inserting rows to our table

Suppose we have our hands on a concrete User value, for example from a registration form on our app's frontend:

user::User
user = User {name: "Jonas Valanciunas", age: 26}

Sequelize lets you do this in two general ways: by building a value that then gets saved to the database, or creating it all at one time (which is equivalent to building and then saving immediately).

Let's assume we're creating our user in one step. Then we can use:

create
::forallabe
. Submodelab=>ModelOfa->b->Aff ( sequelize::SEQUELIZE | e ) (Instanceb)

The Submodel class is just a relation between two models. For example, we might also want to obtain our user's ID from the database, but there's no way to do that since if we try to use the DecodeModel instance, we can't get any information back besides what our user's name is. Hence, we can use a supermodel that includes the name and the ID.

There is an instance for reflexivity and a function for transitivity: that is, if a has a Model instance then it's already a Submodel of itself, and if a is a submodel of b which is a submodel of c, then a is already a submodel of c. (Transitivity is not provided as an instance because it's very easy to confuse the compiler as to which instance to pick).

Retrieving data

Now we want to fetch data from our table. Note that create gave us access to a value of type Instance User: this is just an opaque type representing Sequelize's notion of an instance, that is, what happens after using queries or something like create. In fact, all our queries in PS give us access to an Instance User, like the following:

findOne
::forallabe. Submodelab=>ModelOfa->Optionsb->Aff ( sequelize::SEQUELIZE | e ) (Maybe (Instanceb))

Since this type is opaque, we need a way to go from an Instance User to a regular User. We can use instanceToModel:

instanceToModel
::foralla. Modela=>Instancea->Fa

After handling any possible errors from trying to deserialize our Instance, we can use our User value.

Using "Where"

There are two different ways to construct a "where" clause in a query. In JS we might do something like the following:

user.findAll({where: {age: 20,}});

In this example, we're matching an exact value: we want only the users whose age is exactly 20.

Or we may do something a bit more complicated:

user.findAll({where: {age: {$gte: 20}}});

In this case, we want only those users whose ages are strictly larger than 19.

WHERE

This is the simplest construction to use. All it does is let you match literal values in the row; it's the equivalent of the first JS example above:

simpleWhere::WHEREUser
simpleWhere = WHERE [Tuple"age" (Int20)]

Where

This is the more expressive construction. To write the equivalent of the second JS example:

moreComplicatedWhere::WhereUser
moreComplicatedWhere = "age" $>= 20

We can construct more complicated clauses by using the boolean $& and $| combinators:

evenMoreComplicatedWhere::WhereUser
evenMoreComplicatedWhere = "age" $>= 20 $& "age" $<= 30

And for more than two clauses conjoined by a boolean combinator, you can directly use the type constructors for Where:

nestedBooleanWhere::WhereUser
nestedBooleanWhere = Or
[ "age" $>= 20 $& "age" $<= 30
, "name" $<- [String"Pau Gasol", String"Marc Gasol"]
]

which will match any users with ages between 20 and 30 or whose names are "Pau Gasol" or "Marc Gasol".

Free monad DSL

You can also use the free monad DSL from Sequelize.Free, which is parameterized by input and output types. It comes with a default interpreter:

runCRUD::_=>ModelOfa->CRUDab ~> Aff (sequelize::SEQUELIZE | e)

as well as all the usual CRUD operations. You could use this for e.g. mocking, in which case you will need to define your own interpreter and switch it out in the appropriate place.

Installing

$ npm install --save config
$ bower install --save purescript-sequelize

About

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

Resources

Stars

16 stars

Watchers

23 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

purescript-sequelize

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

LICENSE

https://github.com/juspay/purescript-sequelize/blob/master/LICENSE

Usage

Connections

Before we can do anything, we need to have configuration information for our database. That means things like database type (SQLite, PostgreSQL, etc), username/password (if any), port, and so on.

In JS that would be done like so:

constSequelize=require('sequelize');constsequelize=newSequelize({database: "myAwesomeDatabase",dialect: "sqlite",storage: "./awesome.sqlite"});

In PS, the type of sequelize would be Conn. There is one way to get a value of this type:

getConn
::foralle
. OptionsConnOpts->Aff ( sequelize::SEQUELIZE | e ) Conn

And we can use it like so:

myConn::foralle. Aff (sequelize::SEQUELIZE | e) Conn
myConn = getConn opts
 where
opts = database := "myAwesomeDatabase"
<> dialect := SQLite
<> storage := "./awesome.sqlite"

Now that we have a connection to our database, we can start defining our tables via Sequelize's concept of a model.

Models

In PS, we use data types to represent Sequelize models. Let's say we have a database of users:

newtypeUser = User{name::String, age::Int}

This means we want to have a table in the database for all our users, with one row that holds their name.

Sequelize lets you define models using objects where keys are table columns names and values are options on those columns:

constuser=sequelize.define("user",{name: {type: Sequelize.STRING(255),defaultValue: "me"},age: {type: Sequelize.INTEGER(255),defaultValue: 20}},{});

In order to pass an object like this to Sequelize, we'll need to transform any value of type User to a Foreign js object. To that end, we'll derive some instances:

derive instanceeqUser :: EqUserderive instancegenericUser :: GenericUser_instanceshowUser :: ShowUserwhere
show = genericShow
instancedecodeUser :: DecodeUserwhere
decode x = genericDecodeModel x
instanceencodeUser :: EncodeUserwhere
encode x = genericEncodeModel x
instanceencodeModelUser :: EncodeModelUserwhere
encodeModel x = genericEncodeModel x
instancedecodeModelUser :: DecodeModelUserwhere
decodeModel x = genericDecodeModel x

The EncodeModel class is what lets Sequelize understand our PS User type.

But recall that in our JS example, we defined a default value for the name column and told Sequelize its type (STRING(255)). We also passed it a string that tells Sequelize what name to store the table as:

instanceisModelUser :: ModelUserwhere
modelCols _ = userCols
modelName _ = "user"userCols::ModelCols
userCols = ["name" /\ nameOpts, "age" /\ ageOpts]
 where
nameOpts =
columnType := ModelTypes.String {length: Nothing} <>
defaultValue := toForeign "me"
ageOpts =
columnType := ModelTypes.Integer {length: Nothing} <>
defaultValue := toForeign 20

Note the catch-all pattern match in the isModelUser instance: this is because we need a proxy to tell the compiler how to pick an appropriate definition for our columns definition and name. If we didn't have that proxy, there wouldn't be any way to tell that the string "user" and the options for our columns correspond with our User type!

Remember that in JS-land we had const user = sequelize.define(...). In PS, that means user would have type ModelOf User. There is one way of getting a ModelOf a, for any a with an instance of Model:

makeModelOf
::forallae. Modela=>Conn->OptionsModelOpts->Aff ( sequelize::SEQUELIZE | e ) (ModelOfa)

therefore we can get Sequelize's version of our model as in the following:

getModelOfUser::foralle. Aff ( sequelize::SEQUELIZE | e ) (ModelOfUser)
getModelOfUser = do
conn <- myConn
user <- makeModelOf conn mempty -- we don't want to pass any extra options
syncConn conn {force: true} -- drop the current table and recreate it
pure user

Inserting rows to our table

Suppose we have our hands on a concrete User value, for example from a registration form on our app's frontend:

user::User
user = User {name: "Jonas Valanciunas", age: 26}

Sequelize lets you do this in two general ways: by building a value that then gets saved to the database, or creating it all at one time (which is equivalent to building and then saving immediately).

Let's assume we're creating our user in one step. Then we can use:

create
::forallabe
. Submodelab=>ModelOfa->b->Aff ( sequelize::SEQUELIZE | e ) (Instanceb)

The Submodel class is just a relation between two models. For example, we might also want to obtain our user's ID from the database, but there's no way to do that since if we try to use the DecodeModel instance, we can't get any information back besides what our user's name is. Hence, we can use a supermodel that includes the name and the ID.

There is an instance for reflexivity and a function for transitivity: that is, if a has a Model instance then it's already a Submodel of itself, and if a is a submodel of b which is a submodel of c, then a is already a submodel of c. (Transitivity is not provided as an instance because it's very easy to confuse the compiler as to which instance to pick).

Retrieving data

Now we want to fetch data from our table. Note that create gave us access to a value of type Instance User: this is just an opaque type representing Sequelize's notion of an instance, that is, what happens after using queries or something like create. In fact, all our queries in PS give us access to an Instance User, like the following:

findOne
::forallabe. Submodelab=>ModelOfa->Optionsb->Aff ( sequelize::SEQUELIZE | e ) (Maybe (Instanceb))

Since this type is opaque, we need a way to go from an Instance User to a regular User. We can use instanceToModel:

instanceToModel
::foralla. Modela=>Instancea->Fa

After handling any possible errors from trying to deserialize our Instance, we can use our User value.

Using "Where"

There are two different ways to construct a "where" clause in a query. In JS we might do something like the following:

user.findAll({where: {age: 20,}});

In this example, we're matching an exact value: we want only the users whose age is exactly 20.

Or we may do something a bit more complicated:

user.findAll({where: {age: {$gte: 20}}});

In this case, we want only those users whose ages are strictly larger than 19.

WHERE

This is the simplest construction to use. All it does is let you match literal values in the row; it's the equivalent of the first JS example above:

simpleWhere::WHEREUser
simpleWhere = WHERE [Tuple"age" (Int20)]

Where

This is the more expressive construction. To write the equivalent of the second JS example:

moreComplicatedWhere::WhereUser
moreComplicatedWhere = "age" $>= 20

We can construct more complicated clauses by using the boolean $& and $| combinators:

evenMoreComplicatedWhere::WhereUser
evenMoreComplicatedWhere = "age" $>= 20 $& "age" $<= 30

And for more than two clauses conjoined by a boolean combinator, you can directly use the type constructors for Where:

nestedBooleanWhere::WhereUser
nestedBooleanWhere = Or
[ "age" $>= 20 $& "age" $<= 30
, "name" $<- [String"Pau Gasol", String"Marc Gasol"]
]

which will match any users with ages between 20 and 30 or whose names are "Pau Gasol" or "Marc Gasol".

Free monad DSL

You can also use the free monad DSL from Sequelize.Free, which is parameterized by input and output types. It comes with a default interpreter:

runCRUD::_=>ModelOfa->CRUDab ~> Aff (sequelize::SEQUELIZE | e)

as well as all the usual CRUD operations. You could use this for e.g. mocking, in which case you will need to define your own interpreter and switch it out in the appropriate place.

Installing

$ npm install --save config
$ bower install --save purescript-sequelize

About

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

Resources

Stars

16 stars

Watchers

23 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

purescript-sequelize

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

LICENSE

https://github.com/juspay/purescript-sequelize/blob/master/LICENSE

Usage

Connections

Before we can do anything, we need to have configuration information for our database. That means things like database type (SQLite, PostgreSQL, etc), username/password (if any), port, and so on.

In JS that would be done like so:

constSequelize=require('sequelize');constsequelize=newSequelize({database: "myAwesomeDatabase",dialect: "sqlite",storage: "./awesome.sqlite"});

In PS, the type of sequelize would be Conn. There is one way to get a value of this type:

getConn
::foralle
. OptionsConnOpts->Aff ( sequelize::SEQUELIZE | e ) Conn

And we can use it like so:

myConn::foralle. Aff (sequelize::SEQUELIZE | e) Conn
myConn = getConn opts
 where
opts = database := "myAwesomeDatabase"
<> dialect := SQLite
<> storage := "./awesome.sqlite"

Now that we have a connection to our database, we can start defining our tables via Sequelize's concept of a model.

Models

In PS, we use data types to represent Sequelize models. Let's say we have a database of users:

newtypeUser = User{name::String, age::Int}

This means we want to have a table in the database for all our users, with one row that holds their name.

Sequelize lets you define models using objects where keys are table columns names and values are options on those columns:

constuser=sequelize.define("user",{name: {type: Sequelize.STRING(255),defaultValue: "me"},age: {type: Sequelize.INTEGER(255),defaultValue: 20}},{});

In order to pass an object like this to Sequelize, we'll need to transform any value of type User to a Foreign js object. To that end, we'll derive some instances:

derive instanceeqUser :: EqUserderive instancegenericUser :: GenericUser_instanceshowUser :: ShowUserwhere
show = genericShow
instancedecodeUser :: DecodeUserwhere
decode x = genericDecodeModel x
instanceencodeUser :: EncodeUserwhere
encode x = genericEncodeModel x
instanceencodeModelUser :: EncodeModelUserwhere
encodeModel x = genericEncodeModel x
instancedecodeModelUser :: DecodeModelUserwhere
decodeModel x = genericDecodeModel x

The EncodeModel class is what lets Sequelize understand our PS User type.

But recall that in our JS example, we defined a default value for the name column and told Sequelize its type (STRING(255)). We also passed it a string that tells Sequelize what name to store the table as:

instanceisModelUser :: ModelUserwhere
modelCols _ = userCols
modelName _ = "user"userCols::ModelCols
userCols = ["name" /\ nameOpts, "age" /\ ageOpts]
 where
nameOpts =
columnType := ModelTypes.String {length: Nothing} <>
defaultValue := toForeign "me"
ageOpts =
columnType := ModelTypes.Integer {length: Nothing} <>
defaultValue := toForeign 20

Note the catch-all pattern match in the isModelUser instance: this is because we need a proxy to tell the compiler how to pick an appropriate definition for our columns definition and name. If we didn't have that proxy, there wouldn't be any way to tell that the string "user" and the options for our columns correspond with our User type!

Remember that in JS-land we had const user = sequelize.define(...). In PS, that means user would have type ModelOf User. There is one way of getting a ModelOf a, for any a with an instance of Model:

makeModelOf
::forallae. Modela=>Conn->OptionsModelOpts->Aff ( sequelize::SEQUELIZE | e ) (ModelOfa)

therefore we can get Sequelize's version of our model as in the following:

getModelOfUser::foralle. Aff ( sequelize::SEQUELIZE | e ) (ModelOfUser)
getModelOfUser = do
conn <- myConn
user <- makeModelOf conn mempty -- we don't want to pass any extra options
syncConn conn {force: true} -- drop the current table and recreate it
pure user

Inserting rows to our table

Suppose we have our hands on a concrete User value, for example from a registration form on our app's frontend:

user::User
user = User {name: "Jonas Valanciunas", age: 26}

Sequelize lets you do this in two general ways: by building a value that then gets saved to the database, or creating it all at one time (which is equivalent to building and then saving immediately).

Let's assume we're creating our user in one step. Then we can use:

create
::forallabe
. Submodelab=>ModelOfa->b->Aff ( sequelize::SEQUELIZE | e ) (Instanceb)

The Submodel class is just a relation between two models. For example, we might also want to obtain our user's ID from the database, but there's no way to do that since if we try to use the DecodeModel instance, we can't get any information back besides what our user's name is. Hence, we can use a supermodel that includes the name and the ID.

There is an instance for reflexivity and a function for transitivity: that is, if a has a Model instance then it's already a Submodel of itself, and if a is a submodel of b which is a submodel of c, then a is already a submodel of c. (Transitivity is not provided as an instance because it's very easy to confuse the compiler as to which instance to pick).

Retrieving data

Now we want to fetch data from our table. Note that create gave us access to a value of type Instance User: this is just an opaque type representing Sequelize's notion of an instance, that is, what happens after using queries or something like create. In fact, all our queries in PS give us access to an Instance User, like the following:

findOne
::forallabe. Submodelab=>ModelOfa->Optionsb->Aff ( sequelize::SEQUELIZE | e ) (Maybe (Instanceb))

Since this type is opaque, we need a way to go from an Instance User to a regular User. We can use instanceToModel:

instanceToModel
::foralla. Modela=>Instancea->Fa

After handling any possible errors from trying to deserialize our Instance, we can use our User value.

Using "Where"

There are two different ways to construct a "where" clause in a query. In JS we might do something like the following:

user.findAll({where: {age: 20,}});

In this example, we're matching an exact value: we want only the users whose age is exactly 20.

Or we may do something a bit more complicated:

user.findAll({where: {age: {$gte: 20}}});

In this case, we want only those users whose ages are strictly larger than 19.

WHERE

This is the simplest construction to use. All it does is let you match literal values in the row; it's the equivalent of the first JS example above:

simpleWhere::WHEREUser
simpleWhere = WHERE [Tuple"age" (Int20)]

Where

This is the more expressive construction. To write the equivalent of the second JS example:

moreComplicatedWhere::WhereUser
moreComplicatedWhere = "age" $>= 20

We can construct more complicated clauses by using the boolean $& and $| combinators:

evenMoreComplicatedWhere::WhereUser
evenMoreComplicatedWhere = "age" $>= 20 $& "age" $<= 30

And for more than two clauses conjoined by a boolean combinator, you can directly use the type constructors for Where:

nestedBooleanWhere::WhereUser
nestedBooleanWhere = Or
[ "age" $>= 20 $& "age" $<= 30
, "name" $<- [String"Pau Gasol", String"Marc Gasol"]
]

which will match any users with ages between 20 and 30 or whose names are "Pau Gasol" or "Marc Gasol".

Free monad DSL

You can also use the free monad DSL from Sequelize.Free, which is parameterized by input and output types. It comes with a default interpreter:

runCRUD::_=>ModelOfa->CRUDab ~> Aff (sequelize::SEQUELIZE | e)

as well as all the usual CRUD operations. You could use this for e.g. mocking, in which case you will need to define your own interpreter and switch it out in the appropriate place.

Installing

$ npm install --save config
$ bower install --save purescript-sequelize

About

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

Resources

Stars

16 stars

Watchers

23 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

purescript-sequelize

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

LICENSE

https://github.com/juspay/purescript-sequelize/blob/master/LICENSE

Usage

Connections

Before we can do anything, we need to have configuration information for our database. That means things like database type (SQLite, PostgreSQL, etc), username/password (if any), port, and so on.

In JS that would be done like so:

constSequelize=require('sequelize');constsequelize=newSequelize({database: "myAwesomeDatabase",dialect: "sqlite",storage: "./awesome.sqlite"});

In PS, the type of sequelize would be Conn. There is one way to get a value of this type:

getConn
::foralle
. OptionsConnOpts->Aff ( sequelize::SEQUELIZE | e ) Conn

And we can use it like so:

myConn::foralle. Aff (sequelize::SEQUELIZE | e) Conn
myConn = getConn opts
 where
opts = database := "myAwesomeDatabase"
<> dialect := SQLite
<> storage := "./awesome.sqlite"

Now that we have a connection to our database, we can start defining our tables via Sequelize's concept of a model.

Models

In PS, we use data types to represent Sequelize models. Let's say we have a database of users:

newtypeUser = User{name::String, age::Int}

This means we want to have a table in the database for all our users, with one row that holds their name.

Sequelize lets you define models using objects where keys are table columns names and values are options on those columns:

constuser=sequelize.define("user",{name: {type: Sequelize.STRING(255),defaultValue: "me"},age: {type: Sequelize.INTEGER(255),defaultValue: 20}},{});

In order to pass an object like this to Sequelize, we'll need to transform any value of type User to a Foreign js object. To that end, we'll derive some instances:

derive instanceeqUser :: EqUserderive instancegenericUser :: GenericUser_instanceshowUser :: ShowUserwhere
show = genericShow
instancedecodeUser :: DecodeUserwhere
decode x = genericDecodeModel x
instanceencodeUser :: EncodeUserwhere
encode x = genericEncodeModel x
instanceencodeModelUser :: EncodeModelUserwhere
encodeModel x = genericEncodeModel x
instancedecodeModelUser :: DecodeModelUserwhere
decodeModel x = genericDecodeModel x

The EncodeModel class is what lets Sequelize understand our PS User type.

But recall that in our JS example, we defined a default value for the name column and told Sequelize its type (STRING(255)). We also passed it a string that tells Sequelize what name to store the table as:

instanceisModelUser :: ModelUserwhere
modelCols _ = userCols
modelName _ = "user"userCols::ModelCols
userCols = ["name" /\ nameOpts, "age" /\ ageOpts]
 where
nameOpts =
columnType := ModelTypes.String {length: Nothing} <>
defaultValue := toForeign "me"
ageOpts =
columnType := ModelTypes.Integer {length: Nothing} <>
defaultValue := toForeign 20

Note the catch-all pattern match in the isModelUser instance: this is because we need a proxy to tell the compiler how to pick an appropriate definition for our columns definition and name. If we didn't have that proxy, there wouldn't be any way to tell that the string "user" and the options for our columns correspond with our User type!

Remember that in JS-land we had const user = sequelize.define(...). In PS, that means user would have type ModelOf User. There is one way of getting a ModelOf a, for any a with an instance of Model:

makeModelOf
::forallae. Modela=>Conn->OptionsModelOpts->Aff ( sequelize::SEQUELIZE | e ) (ModelOfa)

therefore we can get Sequelize's version of our model as in the following:

getModelOfUser::foralle. Aff ( sequelize::SEQUELIZE | e ) (ModelOfUser)
getModelOfUser = do
conn <- myConn
user <- makeModelOf conn mempty -- we don't want to pass any extra options
syncConn conn {force: true} -- drop the current table and recreate it
pure user

Inserting rows to our table

Suppose we have our hands on a concrete User value, for example from a registration form on our app's frontend:

user::User
user = User {name: "Jonas Valanciunas", age: 26}

Sequelize lets you do this in two general ways: by building a value that then gets saved to the database, or creating it all at one time (which is equivalent to building and then saving immediately).

Let's assume we're creating our user in one step. Then we can use:

create
::forallabe
. Submodelab=>ModelOfa->b->Aff ( sequelize::SEQUELIZE | e ) (Instanceb)

The Submodel class is just a relation between two models. For example, we might also want to obtain our user's ID from the database, but there's no way to do that since if we try to use the DecodeModel instance, we can't get any information back besides what our user's name is. Hence, we can use a supermodel that includes the name and the ID.

There is an instance for reflexivity and a function for transitivity: that is, if a has a Model instance then it's already a Submodel of itself, and if a is a submodel of b which is a submodel of c, then a is already a submodel of c. (Transitivity is not provided as an instance because it's very easy to confuse the compiler as to which instance to pick).

Retrieving data

Now we want to fetch data from our table. Note that create gave us access to a value of type Instance User: this is just an opaque type representing Sequelize's notion of an instance, that is, what happens after using queries or something like create. In fact, all our queries in PS give us access to an Instance User, like the following:

findOne
::forallabe. Submodelab=>ModelOfa->Optionsb->Aff ( sequelize::SEQUELIZE | e ) (Maybe (Instanceb))

Since this type is opaque, we need a way to go from an Instance User to a regular User. We can use instanceToModel:

instanceToModel
::foralla. Modela=>Instancea->Fa

After handling any possible errors from trying to deserialize our Instance, we can use our User value.

Using "Where"

There are two different ways to construct a "where" clause in a query. In JS we might do something like the following:

user.findAll({where: {age: 20,}});

In this example, we're matching an exact value: we want only the users whose age is exactly 20.

Or we may do something a bit more complicated:

user.findAll({where: {age: {$gte: 20}}});

In this case, we want only those users whose ages are strictly larger than 19.

WHERE

This is the simplest construction to use. All it does is let you match literal values in the row; it's the equivalent of the first JS example above:

simpleWhere::WHEREUser
simpleWhere = WHERE [Tuple"age" (Int20)]

Where

This is the more expressive construction. To write the equivalent of the second JS example:

moreComplicatedWhere::WhereUser
moreComplicatedWhere = "age" $>= 20

We can construct more complicated clauses by using the boolean $& and $| combinators:

evenMoreComplicatedWhere::WhereUser
evenMoreComplicatedWhere = "age" $>= 20 $& "age" $<= 30

And for more than two clauses conjoined by a boolean combinator, you can directly use the type constructors for Where:

nestedBooleanWhere::WhereUser
nestedBooleanWhere = Or
[ "age" $>= 20 $& "age" $<= 30
, "name" $<- [String"Pau Gasol", String"Marc Gasol"]
]

which will match any users with ages between 20 and 30 or whose names are "Pau Gasol" or "Marc Gasol".

Free monad DSL

You can also use the free monad DSL from Sequelize.Free, which is parameterized by input and output types. It comes with a default interpreter:

runCRUD::_=>ModelOfa->CRUDab ~> Aff (sequelize::SEQUELIZE | e)

as well as all the usual CRUD operations. You could use this for e.g. mocking, in which case you will need to define your own interpreter and switch it out in the appropriate place.

Installing

$ npm install --save config
$ bower install --save purescript-sequelize

About

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

Resources

Stars

16 stars

Watchers

23 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

purescript-sequelize

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

LICENSE

https://github.com/juspay/purescript-sequelize/blob/master/LICENSE

Usage

Connections

Before we can do anything, we need to have configuration information for our database. That means things like database type (SQLite, PostgreSQL, etc), username/password (if any), port, and so on.

In JS that would be done like so:

constSequelize=require('sequelize');constsequelize=newSequelize({database: "myAwesomeDatabase",dialect: "sqlite",storage: "./awesome.sqlite"});

In PS, the type of sequelize would be Conn. There is one way to get a value of this type:

getConn
::foralle
. OptionsConnOpts->Aff ( sequelize::SEQUELIZE | e ) Conn

And we can use it like so:

myConn::foralle. Aff (sequelize::SEQUELIZE | e) Conn
myConn = getConn opts
 where
opts = database := "myAwesomeDatabase"
<> dialect := SQLite
<> storage := "./awesome.sqlite"

Now that we have a connection to our database, we can start defining our tables via Sequelize's concept of a model.

Models

In PS, we use data types to represent Sequelize models. Let's say we have a database of users:

newtypeUser = User{name::String, age::Int}

This means we want to have a table in the database for all our users, with one row that holds their name.

Sequelize lets you define models using objects where keys are table columns names and values are options on those columns:

constuser=sequelize.define("user",{name: {type: Sequelize.STRING(255),defaultValue: "me"},age: {type: Sequelize.INTEGER(255),defaultValue: 20}},{});

In order to pass an object like this to Sequelize, we'll need to transform any value of type User to a Foreign js object. To that end, we'll derive some instances:

derive instanceeqUser :: EqUserderive instancegenericUser :: GenericUser_instanceshowUser :: ShowUserwhere
show = genericShow
instancedecodeUser :: DecodeUserwhere
decode x = genericDecodeModel x
instanceencodeUser :: EncodeUserwhere
encode x = genericEncodeModel x
instanceencodeModelUser :: EncodeModelUserwhere
encodeModel x = genericEncodeModel x
instancedecodeModelUser :: DecodeModelUserwhere
decodeModel x = genericDecodeModel x

The EncodeModel class is what lets Sequelize understand our PS User type.

But recall that in our JS example, we defined a default value for the name column and told Sequelize its type (STRING(255)). We also passed it a string that tells Sequelize what name to store the table as:

instanceisModelUser :: ModelUserwhere
modelCols _ = userCols
modelName _ = "user"userCols::ModelCols
userCols = ["name" /\ nameOpts, "age" /\ ageOpts]
 where
nameOpts =
columnType := ModelTypes.String {length: Nothing} <>
defaultValue := toForeign "me"
ageOpts =
columnType := ModelTypes.Integer {length: Nothing} <>
defaultValue := toForeign 20

Note the catch-all pattern match in the isModelUser instance: this is because we need a proxy to tell the compiler how to pick an appropriate definition for our columns definition and name. If we didn't have that proxy, there wouldn't be any way to tell that the string "user" and the options for our columns correspond with our User type!

Remember that in JS-land we had const user = sequelize.define(...). In PS, that means user would have type ModelOf User. There is one way of getting a ModelOf a, for any a with an instance of Model:

makeModelOf
::forallae. Modela=>Conn->OptionsModelOpts->Aff ( sequelize::SEQUELIZE | e ) (ModelOfa)

therefore we can get Sequelize's version of our model as in the following:

getModelOfUser::foralle. Aff ( sequelize::SEQUELIZE | e ) (ModelOfUser)
getModelOfUser = do
conn <- myConn
user <- makeModelOf conn mempty -- we don't want to pass any extra options
syncConn conn {force: true} -- drop the current table and recreate it
pure user

Inserting rows to our table

Suppose we have our hands on a concrete User value, for example from a registration form on our app's frontend:

user::User
user = User {name: "Jonas Valanciunas", age: 26}

Sequelize lets you do this in two general ways: by building a value that then gets saved to the database, or creating it all at one time (which is equivalent to building and then saving immediately).

Let's assume we're creating our user in one step. Then we can use:

create
::forallabe
. Submodelab=>ModelOfa->b->Aff ( sequelize::SEQUELIZE | e ) (Instanceb)

The Submodel class is just a relation between two models. For example, we might also want to obtain our user's ID from the database, but there's no way to do that since if we try to use the DecodeModel instance, we can't get any information back besides what our user's name is. Hence, we can use a supermodel that includes the name and the ID.

There is an instance for reflexivity and a function for transitivity: that is, if a has a Model instance then it's already a Submodel of itself, and if a is a submodel of b which is a submodel of c, then a is already a submodel of c. (Transitivity is not provided as an instance because it's very easy to confuse the compiler as to which instance to pick).

Retrieving data

Now we want to fetch data from our table. Note that create gave us access to a value of type Instance User: this is just an opaque type representing Sequelize's notion of an instance, that is, what happens after using queries or something like create. In fact, all our queries in PS give us access to an Instance User, like the following:

findOne
::forallabe. Submodelab=>ModelOfa->Optionsb->Aff ( sequelize::SEQUELIZE | e ) (Maybe (Instanceb))

Since this type is opaque, we need a way to go from an Instance User to a regular User. We can use instanceToModel:

instanceToModel
::foralla. Modela=>Instancea->Fa

After handling any possible errors from trying to deserialize our Instance, we can use our User value.

Using "Where"

There are two different ways to construct a "where" clause in a query. In JS we might do something like the following:

user.findAll({where: {age: 20,}});

In this example, we're matching an exact value: we want only the users whose age is exactly 20.

Or we may do something a bit more complicated:

user.findAll({where: {age: {$gte: 20}}});

In this case, we want only those users whose ages are strictly larger than 19.

WHERE

This is the simplest construction to use. All it does is let you match literal values in the row; it's the equivalent of the first JS example above:

simpleWhere::WHEREUser
simpleWhere = WHERE [Tuple"age" (Int20)]

Where

This is the more expressive construction. To write the equivalent of the second JS example:

moreComplicatedWhere::WhereUser
moreComplicatedWhere = "age" $>= 20

We can construct more complicated clauses by using the boolean $& and $| combinators:

evenMoreComplicatedWhere::WhereUser
evenMoreComplicatedWhere = "age" $>= 20 $& "age" $<= 30

And for more than two clauses conjoined by a boolean combinator, you can directly use the type constructors for Where:

nestedBooleanWhere::WhereUser
nestedBooleanWhere = Or
[ "age" $>= 20 $& "age" $<= 30
, "name" $<- [String"Pau Gasol", String"Marc Gasol"]
]

which will match any users with ages between 20 and 30 or whose names are "Pau Gasol" or "Marc Gasol".

Free monad DSL

You can also use the free monad DSL from Sequelize.Free, which is parameterized by input and output types. It comes with a default interpreter:

runCRUD::_=>ModelOfa->CRUDab ~> Aff (sequelize::SEQUELIZE | e)

as well as all the usual CRUD operations. You could use this for e.g. mocking, in which case you will need to define your own interpreter and switch it out in the appropriate place.

Installing

$ npm install --save config
$ bower install --save purescript-sequelize

About

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

Resources

Stars

16 stars

Watchers

23 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

purescript-sequelize

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

LICENSE

https://github.com/juspay/purescript-sequelize/blob/master/LICENSE

Usage

Connections

Before we can do anything, we need to have configuration information for our database. That means things like database type (SQLite, PostgreSQL, etc), username/password (if any), port, and so on.

In JS that would be done like so:

constSequelize=require('sequelize');constsequelize=newSequelize({database: "myAwesomeDatabase",dialect: "sqlite",storage: "./awesome.sqlite"});

In PS, the type of sequelize would be Conn. There is one way to get a value of this type:

getConn
::foralle
. OptionsConnOpts->Aff ( sequelize::SEQUELIZE | e ) Conn

And we can use it like so:

myConn::foralle. Aff (sequelize::SEQUELIZE | e) Conn
myConn = getConn opts
 where
opts = database := "myAwesomeDatabase"
<> dialect := SQLite
<> storage := "./awesome.sqlite"

Now that we have a connection to our database, we can start defining our tables via Sequelize's concept of a model.

Models

In PS, we use data types to represent Sequelize models. Let's say we have a database of users:

newtypeUser = User{name::String, age::Int}

This means we want to have a table in the database for all our users, with one row that holds their name.

Sequelize lets you define models using objects where keys are table columns names and values are options on those columns:

constuser=sequelize.define("user",{name: {type: Sequelize.STRING(255),defaultValue: "me"},age: {type: Sequelize.INTEGER(255),defaultValue: 20}},{});

In order to pass an object like this to Sequelize, we'll need to transform any value of type User to a Foreign js object. To that end, we'll derive some instances:

derive instanceeqUser :: EqUserderive instancegenericUser :: GenericUser_instanceshowUser :: ShowUserwhere
show = genericShow
instancedecodeUser :: DecodeUserwhere
decode x = genericDecodeModel x
instanceencodeUser :: EncodeUserwhere
encode x = genericEncodeModel x
instanceencodeModelUser :: EncodeModelUserwhere
encodeModel x = genericEncodeModel x
instancedecodeModelUser :: DecodeModelUserwhere
decodeModel x = genericDecodeModel x

The EncodeModel class is what lets Sequelize understand our PS User type.

But recall that in our JS example, we defined a default value for the name column and told Sequelize its type (STRING(255)). We also passed it a string that tells Sequelize what name to store the table as:

instanceisModelUser :: ModelUserwhere
modelCols _ = userCols
modelName _ = "user"userCols::ModelCols
userCols = ["name" /\ nameOpts, "age" /\ ageOpts]
 where
nameOpts =
columnType := ModelTypes.String {length: Nothing} <>
defaultValue := toForeign "me"
ageOpts =
columnType := ModelTypes.Integer {length: Nothing} <>
defaultValue := toForeign 20

Note the catch-all pattern match in the isModelUser instance: this is because we need a proxy to tell the compiler how to pick an appropriate definition for our columns definition and name. If we didn't have that proxy, there wouldn't be any way to tell that the string "user" and the options for our columns correspond with our User type!

Remember that in JS-land we had const user = sequelize.define(...). In PS, that means user would have type ModelOf User. There is one way of getting a ModelOf a, for any a with an instance of Model:

makeModelOf
::forallae. Modela=>Conn->OptionsModelOpts->Aff ( sequelize::SEQUELIZE | e ) (ModelOfa)

therefore we can get Sequelize's version of our model as in the following:

getModelOfUser::foralle. Aff ( sequelize::SEQUELIZE | e ) (ModelOfUser)
getModelOfUser = do
conn <- myConn
user <- makeModelOf conn mempty -- we don't want to pass any extra options
syncConn conn {force: true} -- drop the current table and recreate it
pure user

Inserting rows to our table

Suppose we have our hands on a concrete User value, for example from a registration form on our app's frontend:

user::User
user = User {name: "Jonas Valanciunas", age: 26}

Sequelize lets you do this in two general ways: by building a value that then gets saved to the database, or creating it all at one time (which is equivalent to building and then saving immediately).

Let's assume we're creating our user in one step. Then we can use:

create
::forallabe
. Submodelab=>ModelOfa->b->Aff ( sequelize::SEQUELIZE | e ) (Instanceb)

The Submodel class is just a relation between two models. For example, we might also want to obtain our user's ID from the database, but there's no way to do that since if we try to use the DecodeModel instance, we can't get any information back besides what our user's name is. Hence, we can use a supermodel that includes the name and the ID.

There is an instance for reflexivity and a function for transitivity: that is, if a has a Model instance then it's already a Submodel of itself, and if a is a submodel of b which is a submodel of c, then a is already a submodel of c. (Transitivity is not provided as an instance because it's very easy to confuse the compiler as to which instance to pick).

Retrieving data

Now we want to fetch data from our table. Note that create gave us access to a value of type Instance User: this is just an opaque type representing Sequelize's notion of an instance, that is, what happens after using queries or something like create. In fact, all our queries in PS give us access to an Instance User, like the following:

findOne
::forallabe. Submodelab=>ModelOfa->Optionsb->Aff ( sequelize::SEQUELIZE | e ) (Maybe (Instanceb))

Since this type is opaque, we need a way to go from an Instance User to a regular User. We can use instanceToModel:

instanceToModel
::foralla. Modela=>Instancea->Fa

After handling any possible errors from trying to deserialize our Instance, we can use our User value.

Using "Where"

There are two different ways to construct a "where" clause in a query. In JS we might do something like the following:

user.findAll({where: {age: 20,}});

In this example, we're matching an exact value: we want only the users whose age is exactly 20.

Or we may do something a bit more complicated:

user.findAll({where: {age: {$gte: 20}}});

In this case, we want only those users whose ages are strictly larger than 19.

WHERE

This is the simplest construction to use. All it does is let you match literal values in the row; it's the equivalent of the first JS example above:

simpleWhere::WHEREUser
simpleWhere = WHERE [Tuple"age" (Int20)]

Where

This is the more expressive construction. To write the equivalent of the second JS example:

moreComplicatedWhere::WhereUser
moreComplicatedWhere = "age" $>= 20

We can construct more complicated clauses by using the boolean $& and $| combinators:

evenMoreComplicatedWhere::WhereUser
evenMoreComplicatedWhere = "age" $>= 20 $& "age" $<= 30

And for more than two clauses conjoined by a boolean combinator, you can directly use the type constructors for Where:

nestedBooleanWhere::WhereUser
nestedBooleanWhere = Or
[ "age" $>= 20 $& "age" $<= 30
, "name" $<- [String"Pau Gasol", String"Marc Gasol"]
]

which will match any users with ages between 20 and 30 or whose names are "Pau Gasol" or "Marc Gasol".

Free monad DSL

You can also use the free monad DSL from Sequelize.Free, which is parameterized by input and output types. It comes with a default interpreter:

runCRUD::_=>ModelOfa->CRUDab ~> Aff (sequelize::SEQUELIZE | e)

as well as all the usual CRUD operations. You could use this for e.g. mocking, in which case you will need to define your own interpreter and switch it out in the appropriate place.

Installing

$ npm install --save config
$ bower install --save purescript-sequelize

About

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

Resources

Stars

16 stars

Watchers

23 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

purescript-sequelize

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

LICENSE

https://github.com/juspay/purescript-sequelize/blob/master/LICENSE

Usage

Connections

Before we can do anything, we need to have configuration information for our database. That means things like database type (SQLite, PostgreSQL, etc), username/password (if any), port, and so on.

In JS that would be done like so:

constSequelize=require('sequelize');constsequelize=newSequelize({database: "myAwesomeDatabase",dialect: "sqlite",storage: "./awesome.sqlite"});

In PS, the type of sequelize would be Conn. There is one way to get a value of this type:

getConn
::foralle
. OptionsConnOpts->Aff ( sequelize::SEQUELIZE | e ) Conn

And we can use it like so:

myConn::foralle. Aff (sequelize::SEQUELIZE | e) Conn
myConn = getConn opts
 where
opts = database := "myAwesomeDatabase"
<> dialect := SQLite
<> storage := "./awesome.sqlite"

Now that we have a connection to our database, we can start defining our tables via Sequelize's concept of a model.

Models

In PS, we use data types to represent Sequelize models. Let's say we have a database of users:

newtypeUser = User{name::String, age::Int}

This means we want to have a table in the database for all our users, with one row that holds their name.

Sequelize lets you define models using objects where keys are table columns names and values are options on those columns:

constuser=sequelize.define("user",{name: {type: Sequelize.STRING(255),defaultValue: "me"},age: {type: Sequelize.INTEGER(255),defaultValue: 20}},{});

In order to pass an object like this to Sequelize, we'll need to transform any value of type User to a Foreign js object. To that end, we'll derive some instances:

derive instanceeqUser :: EqUserderive instancegenericUser :: GenericUser_instanceshowUser :: ShowUserwhere
show = genericShow
instancedecodeUser :: DecodeUserwhere
decode x = genericDecodeModel x
instanceencodeUser :: EncodeUserwhere
encode x = genericEncodeModel x
instanceencodeModelUser :: EncodeModelUserwhere
encodeModel x = genericEncodeModel x
instancedecodeModelUser :: DecodeModelUserwhere
decodeModel x = genericDecodeModel x

The EncodeModel class is what lets Sequelize understand our PS User type.

But recall that in our JS example, we defined a default value for the name column and told Sequelize its type (STRING(255)). We also passed it a string that tells Sequelize what name to store the table as:

instanceisModelUser :: ModelUserwhere
modelCols _ = userCols
modelName _ = "user"userCols::ModelCols
userCols = ["name" /\ nameOpts, "age" /\ ageOpts]
 where
nameOpts =
columnType := ModelTypes.String {length: Nothing} <>
defaultValue := toForeign "me"
ageOpts =
columnType := ModelTypes.Integer {length: Nothing} <>
defaultValue := toForeign 20

Note the catch-all pattern match in the isModelUser instance: this is because we need a proxy to tell the compiler how to pick an appropriate definition for our columns definition and name. If we didn't have that proxy, there wouldn't be any way to tell that the string "user" and the options for our columns correspond with our User type!

Remember that in JS-land we had const user = sequelize.define(...). In PS, that means user would have type ModelOf User. There is one way of getting a ModelOf a, for any a with an instance of Model:

makeModelOf
::forallae. Modela=>Conn->OptionsModelOpts->Aff ( sequelize::SEQUELIZE | e ) (ModelOfa)

therefore we can get Sequelize's version of our model as in the following:

getModelOfUser::foralle. Aff ( sequelize::SEQUELIZE | e ) (ModelOfUser)
getModelOfUser = do
conn <- myConn
user <- makeModelOf conn mempty -- we don't want to pass any extra options
syncConn conn {force: true} -- drop the current table and recreate it
pure user

Inserting rows to our table

Suppose we have our hands on a concrete User value, for example from a registration form on our app's frontend:

user::User
user = User {name: "Jonas Valanciunas", age: 26}

Sequelize lets you do this in two general ways: by building a value that then gets saved to the database, or creating it all at one time (which is equivalent to building and then saving immediately).

Let's assume we're creating our user in one step. Then we can use:

create
::forallabe
. Submodelab=>ModelOfa->b->Aff ( sequelize::SEQUELIZE | e ) (Instanceb)

The Submodel class is just a relation between two models. For example, we might also want to obtain our user's ID from the database, but there's no way to do that since if we try to use the DecodeModel instance, we can't get any information back besides what our user's name is. Hence, we can use a supermodel that includes the name and the ID.

There is an instance for reflexivity and a function for transitivity: that is, if a has a Model instance then it's already a Submodel of itself, and if a is a submodel of b which is a submodel of c, then a is already a submodel of c. (Transitivity is not provided as an instance because it's very easy to confuse the compiler as to which instance to pick).

Retrieving data

Now we want to fetch data from our table. Note that create gave us access to a value of type Instance User: this is just an opaque type representing Sequelize's notion of an instance, that is, what happens after using queries or something like create. In fact, all our queries in PS give us access to an Instance User, like the following:

findOne
::forallabe. Submodelab=>ModelOfa->Optionsb->Aff ( sequelize::SEQUELIZE | e ) (Maybe (Instanceb))

Since this type is opaque, we need a way to go from an Instance User to a regular User. We can use instanceToModel:

instanceToModel
::foralla. Modela=>Instancea->Fa

After handling any possible errors from trying to deserialize our Instance, we can use our User value.

Using "Where"

There are two different ways to construct a "where" clause in a query. In JS we might do something like the following:

user.findAll({where: {age: 20,}});

In this example, we're matching an exact value: we want only the users whose age is exactly 20.

Or we may do something a bit more complicated:

user.findAll({where: {age: {$gte: 20}}});

In this case, we want only those users whose ages are strictly larger than 19.

WHERE

This is the simplest construction to use. All it does is let you match literal values in the row; it's the equivalent of the first JS example above:

simpleWhere::WHEREUser
simpleWhere = WHERE [Tuple"age" (Int20)]

Where

This is the more expressive construction. To write the equivalent of the second JS example:

moreComplicatedWhere::WhereUser
moreComplicatedWhere = "age" $>= 20

We can construct more complicated clauses by using the boolean $& and $| combinators:

evenMoreComplicatedWhere::WhereUser
evenMoreComplicatedWhere = "age" $>= 20 $& "age" $<= 30

And for more than two clauses conjoined by a boolean combinator, you can directly use the type constructors for Where:

nestedBooleanWhere::WhereUser
nestedBooleanWhere = Or
[ "age" $>= 20 $& "age" $<= 30
, "name" $<- [String"Pau Gasol", String"Marc Gasol"]
]

which will match any users with ages between 20 and 30 or whose names are "Pau Gasol" or "Marc Gasol".

Free monad DSL

You can also use the free monad DSL from Sequelize.Free, which is parameterized by input and output types. It comes with a default interpreter:

runCRUD::_=>ModelOfa->CRUDab ~> Aff (sequelize::SEQUELIZE | e)

as well as all the usual CRUD operations. You could use this for e.g. mocking, in which case you will need to define your own interpreter and switch it out in the appropriate place.

Installing

$ npm install --save config
$ bower install --save purescript-sequelize

About

Purescript wrapper for Sequelize - http://docs.sequelizejs.com/

Resources

Stars

16 stars

Watchers

23 watching

Forks

Releases

Packages

Used by

Contributors

Languages