ruby-montage 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.ruby-version +1 -0
  4. data/CODE_OF_CONDUCT.md +13 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +132 -0
  8. data/Rakefile +12 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +7 -0
  11. data/circle.yml +13 -0
  12. data/lib/montage.rb +6 -0
  13. data/lib/montage/client.rb +109 -0
  14. data/lib/montage/client/documents.rb +79 -0
  15. data/lib/montage/client/files.rb +39 -0
  16. data/lib/montage/client/schemas.rb +19 -0
  17. data/lib/montage/collection.rb +43 -0
  18. data/lib/montage/collections.rb +21 -0
  19. data/lib/montage/collections/documents.rb +13 -0
  20. data/lib/montage/collections/errors.rb +13 -0
  21. data/lib/montage/collections/files.rb +13 -0
  22. data/lib/montage/collections/schemas.rb +13 -0
  23. data/lib/montage/errors.rb +5 -0
  24. data/lib/montage/operators.rb +34 -0
  25. data/lib/montage/operators/equal.rb +17 -0
  26. data/lib/montage/operators/gt.rb +17 -0
  27. data/lib/montage/operators/gte.rb +17 -0
  28. data/lib/montage/operators/ilike.rb +17 -0
  29. data/lib/montage/operators/in.rb +17 -0
  30. data/lib/montage/operators/like.rb +17 -0
  31. data/lib/montage/operators/lt.rb +17 -0
  32. data/lib/montage/operators/lte.rb +17 -0
  33. data/lib/montage/operators/nil.rb +17 -0
  34. data/lib/montage/operators/not.rb +17 -0
  35. data/lib/montage/operators/not_in.rb +17 -0
  36. data/lib/montage/query.rb +107 -0
  37. data/lib/montage/query_parser.rb +112 -0
  38. data/lib/montage/resource.rb +47 -0
  39. data/lib/montage/resources.rb +25 -0
  40. data/lib/montage/resources/document.rb +9 -0
  41. data/lib/montage/resources/error.rb +9 -0
  42. data/lib/montage/resources/file.rb +9 -0
  43. data/lib/montage/resources/schema.rb +9 -0
  44. data/lib/montage/resources/token.rb +13 -0
  45. data/lib/montage/response.rb +49 -0
  46. data/lib/montage/support.rb +25 -0
  47. data/lib/montage/version.rb +3 -0
  48. data/ruby-montage.gemspec +36 -0
  49. metadata +251 -0
@@ -0,0 +1,39 @@
1
+ module Montage
2
+ class Client
3
+ module Files
4
+ # Public: Get a list of files.
5
+ #
6
+ # Returns a Montage::Response
7
+ # def files
8
+ # get("files/", "file")
9
+ # end
10
+
11
+ # Public: Get a single file
12
+ #
13
+ # file_id - Required. The uuid of the file.
14
+ #
15
+ # Returns a Montage::Response
16
+ # def file(file_id)
17
+ # get("files/#{file_id}/", "file")
18
+ # end
19
+
20
+ # Public: Upload a new file
21
+ #
22
+ # file - Required. The file to upload.
23
+ #
24
+ # Returns a Montage::Response
25
+ # def new_file(file)
26
+ # post("files/", "file", file)
27
+ # end
28
+
29
+ # Public: Delete a file
30
+ #
31
+ # file_id - Required. The uuid of the file.
32
+ #
33
+ # Returns a Montage::Response
34
+ # def destroy_file(file_id)
35
+ # delete("files/#{file_id}/", "file")
36
+ # end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,19 @@
1
+ module Montage
2
+ class Client
3
+ module Schemas
4
+ # Public: Get a list of schemas
5
+ #
6
+ # Returns a Montage::Response
7
+ def schemas
8
+ get("schemas/", "schema")
9
+ end
10
+
11
+ # Public: Get a single schema
12
+ #
13
+ # Returns a Montage::Response
14
+ def schema(name)
15
+ get("schemas/#{name}/", "schema")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,43 @@
1
+ module Montage
2
+ class Collection
3
+ include Enumerable
4
+
5
+ attr_reader :raw_items, :items
6
+
7
+ def initialize(raw_items)
8
+ @raw_items = raw_items.dup.freeze
9
+ @items = parse_items
10
+ end
11
+
12
+ def self.collection_name
13
+ "resources"
14
+ end
15
+
16
+ def self.resource_name
17
+ "resource"
18
+ end
19
+
20
+ def item_class
21
+ @item_class ||= Montage::Resources.find_class(self.class.resource_name)
22
+ end
23
+
24
+ def parse_items
25
+ raw_items.map do |raw_item|
26
+ if raw_item["_meta"]
27
+ raw_item["created_at"] = raw_item["_meta"]["created"]
28
+ raw_item["updated_at"] = raw_item["_meta"]["modified"]
29
+ end
30
+
31
+ item_class.new(raw_item)
32
+ end
33
+ end
34
+
35
+ def singular?
36
+ items.length < 2
37
+ end
38
+
39
+ def each(&block)
40
+ items.each { |item| yield(item) }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ require 'montage/collections/errors'
2
+ require 'montage/collections/files'
3
+ require 'montage/collections/schemas'
4
+ require 'montage/collections/documents'
5
+
6
+ module Montage
7
+ module Collections
8
+ def self.classes
9
+ [
10
+ Montage::Errors,
11
+ Montage::Files,
12
+ Montage::Schemas,
13
+ Montage::Documents
14
+ ]
15
+ end
16
+
17
+ def self.find_class(name)
18
+ self.classes.find(Proc.new { Montage::Collection }) { |c| c.collection_name == name }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ require 'montage/collection'
2
+
3
+ module Montage
4
+ class Documents < Collection
5
+ def self.collection_name
6
+ "documents"
7
+ end
8
+
9
+ def self.resource_name
10
+ "document"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'montage/collection'
2
+
3
+ module Montage
4
+ class Errors < Collection
5
+ def self.collection_name
6
+ "errors"
7
+ end
8
+
9
+ def self.resource_name
10
+ "error"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'montage/collection'
2
+
3
+ module Montage
4
+ class Files < Collection
5
+ def self.collection_name
6
+ "files"
7
+ end
8
+
9
+ def self.resource_name
10
+ "file"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'montage/collection'
2
+
3
+ module Montage
4
+ class Schemas < Collection
5
+ def self.collection_name
6
+ "schemas"
7
+ end
8
+
9
+ def self.resource_name
10
+ "schema"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module Montage
2
+ class MissingAttributeError < StandardError; end
3
+
4
+ class QueryError < StandardError; end
5
+ end
@@ -0,0 +1,34 @@
1
+ require 'montage/operators/equal'
2
+ require 'montage/operators/not'
3
+ require 'montage/operators/not_in'
4
+ require 'montage/operators/lte'
5
+ require 'montage/operators/gte'
6
+ require 'montage/operators/lt'
7
+ require 'montage/operators/gt'
8
+ require 'montage/operators/ilike'
9
+ require 'montage/operators/like'
10
+ require 'montage/operators/in'
11
+ require 'montage/operators/nil'
12
+
13
+ module Montage
14
+ module Operators
15
+ def self.classes
16
+ [
17
+ Montage::Operators::Equal,
18
+ Montage::Operators::Not,
19
+ Montage::Operators::Lte,
20
+ Montage::Operators::Gte,
21
+ Montage::Operators::Lt,
22
+ Montage::Operators::Gt,
23
+ Montage::Operators::NotIn,
24
+ Montage::Operators::In,
25
+ Montage::Operators::Ilike,
26
+ Montage::Operators::Like,
27
+ ]
28
+ end
29
+
30
+ def self.find_operator(query_string)
31
+ self.classes.find(Proc.new { Montage::Operators::Nil }) { |c| c == query_string }
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class Equal
4
+ def self.operator
5
+ "="
6
+ end
7
+
8
+ def self.montage_operator
9
+ ""
10
+ end
11
+
12
+ def self.==(value)
13
+ value =~ /[^!<>]=[^!<>]/
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class Gt
4
+ def self.operator
5
+ ">"
6
+ end
7
+
8
+ def self.montage_operator
9
+ "__gt"
10
+ end
11
+
12
+ def self.==(value)
13
+ value =~ /[^=<]>[^=<]/
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class Gte
4
+ def self.operator
5
+ ">="
6
+ end
7
+
8
+ def self.montage_operator
9
+ "__gte"
10
+ end
11
+
12
+ def self.==(value)
13
+ value =~ /[^<]>=[^<]/
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class Ilike
4
+ def self.operator
5
+ "ilike"
6
+ end
7
+
8
+ def self.montage_operator
9
+ "__icontains"
10
+ end
11
+
12
+ def self.==(value)
13
+ value =~ /\bilike\b/i
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class In
4
+ def self.operator
5
+ "in"
6
+ end
7
+
8
+ def self.montage_operator
9
+ "__in"
10
+ end
11
+
12
+ def self.==(value)
13
+ value =~ /in/i && !value.downcase.include?("not")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class Like
4
+ def self.operator
5
+ "like"
6
+ end
7
+
8
+ def self.montage_operator
9
+ "__contains"
10
+ end
11
+
12
+ def self.==(value)
13
+ value =~ /like/i && !value.downcase.include?("ilike")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class Lt
4
+ def self.operator
5
+ "<"
6
+ end
7
+
8
+ def self.montage_operator
9
+ "__lt"
10
+ end
11
+
12
+ def self.==(value)
13
+ value =~ /[^=>]<[^=>]/i
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class Lte
4
+ def self.operator
5
+ "<="
6
+ end
7
+
8
+ def self.montage_operator
9
+ "__lte"
10
+ end
11
+
12
+ def self.==(value)
13
+ value =~ /[^>]<=[^>]/i
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class Nil
4
+ def self.operator
5
+ nil
6
+ end
7
+
8
+ def self.montage_operator
9
+ nil
10
+ end
11
+
12
+ def self.==(value)
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class Not
4
+ def self.operator
5
+ "!="
6
+ end
7
+
8
+ def self.montage_operator
9
+ "__not"
10
+ end
11
+
12
+ def self.==(value)
13
+ value.include?("!=")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Montage
2
+ module Operators
3
+ class NotIn
4
+ def self.operator
5
+ "not in"
6
+ end
7
+
8
+ def self.montage_operator
9
+ "__notin"
10
+ end
11
+
12
+ def self.==(value)
13
+ value =~ /not in/i
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,107 @@
1
+ require 'montage/errors'
2
+ require 'montage/query_parser'
3
+ require 'montage/support'
4
+ require 'json'
5
+
6
+ module Montage
7
+ class Query
8
+ include Montage::Support
9
+
10
+ attr_accessor :query
11
+
12
+ def initialize
13
+ @query = { filter: {} }
14
+ end
15
+
16
+ # Defines the limit to apply to the query, defaults to nil
17
+ #
18
+ # Merges a hash:
19
+ # { limit: 10 }
20
+ #
21
+ # Returns self
22
+ #
23
+ def limit(max = nil)
24
+ clone.tap { |r| r.query.merge!(limit: max) }
25
+ end
26
+
27
+ # Defines the offset to apply to the query, defaults to nil
28
+ #
29
+ # Merges a hash:
30
+ # { offset: 10 }
31
+ #
32
+ # Returns a copy of self
33
+ #
34
+ def offset(value = nil)
35
+ clone.tap { |r| r.query.merge!(offset: value) }
36
+ end
37
+
38
+ # Defines the order clause for the query and merges it into the query hash
39
+ #
40
+ # Accepts either a string or a hash:
41
+ # order("foo asc") or
42
+ # order(:foo => :asc) or
43
+ # order(:foo => "asc")
44
+ #
45
+ # Defaults the direction to asc if no value is passed in for that, or if it is not a valid value
46
+ #
47
+ # Merges a hash:
48
+ # { order: "foo asc" }
49
+ #
50
+ # Returns a copy of self
51
+ #
52
+ def order(clause = {})
53
+ if clause.is_a?(Hash)
54
+ direction = clause.values.first.to_s
55
+ field = clause.keys.first.to_s
56
+ else
57
+ direction = clause.split(" ")[1]
58
+ field = clause.split(" ")[0]
59
+ direction = "asc" unless %w(asc desc).include?(direction)
60
+ end
61
+
62
+ clone.tap{ |r| r.query.merge!(order_by: field, ordering: direction) }
63
+ end
64
+
65
+ # Parses the SQL string passed into the method
66
+ #
67
+ # Raises an exception if it is not a valid query (at least three "words"):
68
+ # parse_string_clause("foo bar")
69
+ #
70
+ # Raises an exception if the operator given is not a valid operator
71
+ # parse_string_clause("foo * 'bar'")
72
+ #
73
+ # Returns a hash:
74
+ # parse_string_clause("foo <= 1")
75
+ # => { foo__lte: 1.0 }
76
+ #
77
+
78
+ # Adds a where clause to the query filter hash
79
+ #
80
+ # Accepts either a Hash or a String
81
+ # where(foo: 1)
82
+ # where("foo > 1")
83
+ #
84
+ # Merges a hash:
85
+ # { foo: 1 }
86
+ #
87
+ # Returns a copy of self
88
+ #
89
+ def where(clause)
90
+ clone.tap { |r| r.query[:filter].merge!(QueryParser.new(clause).parse) }
91
+ end
92
+
93
+ # Specifies and index to use on a query. RethinkDB isn't as smart as some other
94
+ # database engines when selecting a query plan, but it does let you specify
95
+ # which index to use
96
+ #
97
+ def index(field)
98
+ clone.tap { |r| r.query.merge!(index: field) }
99
+ end
100
+
101
+ # Parses the current query hash and returns a JSON string
102
+ #
103
+ def to_json
104
+ @query.to_json
105
+ end
106
+ end
107
+ end