|
2 | 2 |
|
3 | 3 | import datomic.Connection; |
4 | 4 | import datomic.Database; |
| 5 | +import datomic.Peer; |
| 6 | +import datomic.Util; |
5 | 7 |
|
6 | | -import java.util.*; |
| 8 | +import java.util.Scanner; |
| 9 | +import java.util.Collection; |
7 | 10 |
|
8 | | -import static datomic.Peer.*; |
9 | 11 | import static datomic.Util.read; |
10 | 12 | import static datomic.samples.Fns.scratchConnection; |
11 | 13 | import static datomic.samples.Schema.CARDINALITY_MANY; |
|
14 | 16 |
|
15 | 17 | public class Query { |
16 | 18 |
|
17 | | - /** |
18 | | - * Function intended for use inside a Datomic query |
19 | | - * |
20 | | - * @param db a database value |
21 | | - * @param e an entity id |
22 | | - * @param attr an attribute |
23 | | - * @param ifNot value to return if attribute absent |
24 | | - * @return attribute value, set of attribute values, or ifNot, depending |
25 | | - * on cardinality of the attribute, and whether any values are present |
26 | | - */ |
27 | | - public static Object maybe(Object db, Object e, Object attr, Object ifNot) { |
28 | | - Collection<List<Object>> result = query("[:find ?v " + |
29 | | - ":in $ ?e ?a " + |
30 | | - ":where [?e ?a ?v]]", db, e, attr); |
31 | | - if (result.isEmpty()) { |
32 | | - return ifNot; |
33 | | - } else { |
34 | | - Object card = cardinality(db, attr); |
35 | | - if (card.equals(CARDINALITY_ONE)) return result.iterator().next(); // only one in list |
36 | | - Set acc = new HashSet(); |
37 | | - for (Iterator<List<Object>> iterator = result.iterator(); iterator.hasNext(); ) { |
38 | | - acc.add(iterator.next()); |
39 | | - } |
40 | | - return Collections.unmodifiableSet(acc); |
41 | | - } |
42 | | - } |
| 19 | + public static void main(String[] args) { |
43 | 20 |
|
44 | | - public static String rules = |
45 | | - "[[[attr-in-namespace ?e ?ns2]\n" + |
46 | | - " [?e :db/ident ?a]\n" + |
47 | | - " [?e :db/valueType]\n" + |
48 | | - " [(namespace ?a) ?ns1]\n" + |
49 | | - " [(= ?ns1 ?ns2)]]]"; |
| 21 | + // Your connection information for local mbrainz 1968-1973 subset goes here. |
| 22 | + String uri = "datomic:free://localhost:4334/mbrainz-1968-1973"; |
50 | 23 |
|
51 | | - public static void main(String[] args) { |
52 | | - Connection conn = scratchConnection(); |
| 24 | + // Connect to transactor, get latest database value from storage. |
| 25 | + Connection conn = Peer.connect(uri); |
53 | 26 | Database db = conn.db(); |
54 | 27 |
|
55 | | - System.out.println("Maybe entity zero has a docstring..."); |
56 | | - System.out.println(maybe(db, 0, read(":db/doc"), "<docstring missing>")); |
57 | | - |
58 | | - System.out.println("\nMaybe entity zero has installed some atttributes"); |
59 | | - System.out.println(maybe(db, 0, read(":db.install/attribute"), "<no attributes installed>")); |
60 | | - |
61 | | - System.out.println("\nMaybe entity one has installed some attributes"); |
62 | | - System.out.println(maybe(db, 1, read(":db.install/attribute"), "<no attributes installed>")); |
63 | | - |
64 | | - System.out.println("\nMaybe we can call maybe from inside a query"); |
65 | | - System.out.println(q("[:find ?ident ?card" + |
66 | | - " :where [?e :db/ident ?ident]" + |
67 | | - " [(datomic.samples.Query/maybe $ ?e :db/cardinality \"<none>\") ?card]]", |
68 | | - db)); |
69 | | - |
70 | | - System.out.println("Look up attributes in the db namespace:"); |
71 | | - System.out.println(q( |
72 | | - "[:find ?e ?ident\n" + |
73 | | - " :in $ %\n" + |
74 | | - " :where\n" + |
75 | | - " (attr-in-namespace ?e \"db\")\n" + |
76 | | - " [?e :db/ident ?ident]]", |
77 | | - db, rules)); |
| 28 | + System.out.println("All releases in the database with release names."); |
| 29 | + Collection results = Peer.query("[:find ?release-name :where [_ :release/name ?release-name]]", db); |
| 30 | + System.out.println(results); |
| 31 | + pause(); |
| 32 | + |
| 33 | + System.out.println("Same as previous query, but with explicit db-var ($)."); |
| 34 | + results = Peer.query("[:find ?release-name :in $ :where [$ _ :release/name ?release-name]]", db); |
| 35 | + System.out.println(results); |
| 36 | + pause(); |
| 37 | + |
| 38 | + System.out.println("Query that finds releases by artist. Parameterized to accept artist name as an argument."); |
| 39 | + results = Peer.query("[:find ?release-name " + |
| 40 | + ":in $ ?artist-name " + |
| 41 | + ":where [?artist :artist/name ?artist-name] " + |
| 42 | + "[?release :release/artists ?artist] " + |
| 43 | + "[?release :release/name ?release-name]]", |
| 44 | + db, "John Lennon"); |
| 45 | + System.out.println(results); |
| 46 | + pause(); |
| 47 | + |
| 48 | + System.out.println("This query accepts a relation argument as a vector and destructures it within the :in."); |
| 49 | + results = Peer.query("[:find ?release " + |
| 50 | + " :in $ [?artist-name ?release-name] " + |
| 51 | + " :where [?artist :artist/name ?artist-name] " + |
| 52 | + " [?release :release/artists ?artist] " + |
| 53 | + " [?release :release/name ?release-name]]", |
| 54 | + db, Util.list("John Lennon", "Mind Games")); |
| 55 | + System.out.println(results); |
| 56 | + pause(); |
| 57 | + |
| 58 | + |
| 59 | + System.out.println("This query accepts a list of artist arguments and uses destructuring to satisfy the " + |
| 60 | + "query for each of them (union of results)."); |
| 61 | + results = Peer.query("[:find ?release-name " + |
| 62 | + ":in $ [?artist-name ...] " + |
| 63 | + ":where [?artist :artist/name ?artist-name] " + |
| 64 | + " [?release :release/artists ?artist] " + |
| 65 | + " [?release :release/name ?release-name]]", |
| 66 | + db, Util.list("Paul McCartney", "George Harrison")); |
| 67 | + pause(); |
| 68 | + |
| 69 | + System.out.println("This query accepts a list of relations, also a list, and destructures the arguments in " + |
| 70 | + "the :in clause."); |
| 71 | + results = Peer.query("[:find ?release " + |
| 72 | + ":in $ [[?artist-name ?release-name]] " + |
| 73 | + ":where [?artist :artist/name ?artist-name] " + |
| 74 | + " [?release :release/artists ?artist] " + |
| 75 | + " [?release :release/name ?release-name]]", |
| 76 | + db, Util.list(Util.list("John Lennon", "Mind Games"), |
| 77 | + Util.list("Paul McCartney", "Ram"))); |
| 78 | + System.out.println(results); |
| 79 | + pause(); |
| 80 | + |
| 81 | + System.out.println("This query returns a collection of relations, all artists and their releases."); |
| 82 | + results = Peer.query("[:find ?artist-name ?release-name " + |
| 83 | + ":where [?release :release/name ?release-name] " + |
| 84 | + " [?release :release/artists ?artist] " + |
| 85 | + " [?artist :artist/name ?artist-name]]", |
| 86 | + db); |
| 87 | + System.out.println(results); |
| 88 | + pause(); |
| 89 | + |
| 90 | + System.out.println("This query returns a list of releases by using a find specification."); |
| 91 | + results = Peer.query("[:find [?release-name ...]" + |
| 92 | + " :in $ ?artist-name " + |
| 93 | + " :where [?artist :artist/name ?artist-name] " + |
| 94 | + " [?release :release/artists ?artist] " + |
| 95 | + " [?release :release/name ?release-name]]", |
| 96 | + db, "John Lennon"); |
| 97 | + System.out.println(results); |
| 98 | + pause(); |
| 99 | + |
| 100 | + System.out.println("This query returns values from multiple attributes to provide artist's start date."); |
| 101 | + results = Peer.query("[:find [?year ?month ?day] " + |
| 102 | + " :in $ ?name " + |
| 103 | + " :where [?artist :artist/name ?name] " + |
| 104 | + " [?artist :artist/startDay ?day] " + |
| 105 | + " [?artist :artist/startMonth ?month] " + |
| 106 | + " [?artist :artist/startYear ?year]]", |
| 107 | + db, "John Lennon"); |
| 108 | + System.out.println(results); |
| 109 | + pause(); |
| 110 | + |
| 111 | + System.out.println("Return just the year of start date using a scalar find specification."); |
| 112 | + Long year = Peer.query("[:find ?year . " + |
| 113 | + " :in $ ?name " + |
| 114 | + " :where [?artist :artist/name ?name] " + |
| 115 | + " [?artist :artist/startYear ?year]]", |
| 116 | + db, "John Lennon"); |
| 117 | + System.out.println(year); |
| 118 | + pause(); |
| 119 | + |
| 120 | + System.out.println("Total number of artists without :artist/country attribute."); |
| 121 | + Integer res = Peer.query("[:find (count ?eid) . " + |
| 122 | + ":where [?eid :artist/name] " + |
| 123 | + "(not [?eid :artist/country])]", |
| 124 | + db); |
| 125 | + System.out.println(res); |
| 126 | + pause(); |
| 127 | + |
| 128 | + System.out.println("Number of artists missing either country or gender. "+ |
| 129 | + "(negation of conjunction reads 'not (clause1 and clause2)'"); |
| 130 | + res = Peer.query("[:find (count ?eid) . " + |
| 131 | + ":where [?eid :artist/name] " + |
| 132 | + "(not [?eid :artist/country] " + |
| 133 | + "[?eid :artist/gender])]", |
| 134 | + db); |
| 135 | + System.out.println(res); |
| 136 | + pause(); |
| 137 | + |
| 138 | + System.out.println("Use not-join to bind variable in subquery. Artists w/o releases in 1970."); |
| 139 | + res = Peer.query("[:find (count ?artist) . " + |
| 140 | + ":where [?artist :artist/name] " + |
| 141 | + "(not-join [?artist] " + |
| 142 | + " [?release :release/artists ?artist] " + |
| 143 | + " [?release :release/year 1970])]", |
| 144 | + db); |
| 145 | + System.out.println(res); |
| 146 | + pause(); |
| 147 | + |
| 148 | + System.out.println("Total of artists who are a group or female by use of 'or'."); |
| 149 | + res = Peer.query("[:find (count ?artist) . " + |
| 150 | + " :where (or [?artist :artist/type :artist.type/group] " + |
| 151 | + " (and [?artist :artist/type :artist.type/person] " + |
| 152 | + " [?artist :artist/gender :artist.gender/female]))]", |
| 153 | + db); |
| 154 | + System.out.println(res); |
| 155 | + pause(); |
| 156 | + |
| 157 | + System.out.println("Count of releases from Canadian artists or the year 1970 using 'or-join'"); |
| 158 | + res = Peer.query("[:find (count ?release) . " + |
| 159 | + " :where [?release :release/name] " + |
| 160 | + " (or-join [?release] " + |
| 161 | + " (and [?release :release/artists ?artist] " + |
| 162 | + " [?artist :artist/country :country/CA]) " + |
| 163 | + " [?release :release/year 1970])]", |
| 164 | + db); |
| 165 | + System.out.println(res); |
| 166 | + pause(); |
| 167 | + } |
| 168 | + |
| 169 | + private static final Scanner scanner = new Scanner(System.in); |
| 170 | + |
| 171 | + private static void pause() { |
| 172 | + if (System.getProperty("NOPAUSE") == null) { |
| 173 | + System.out.println("\nPress enter to continue..."); |
| 174 | + scanner.nextLine(); |
| 175 | + } |
78 | 176 | } |
79 | 177 | } |
0 commit comments