1
00:00:04,540 --> 00:00:06,519
Alright so let's move on now to the

2
00:00:06,519 --> 00:00:08,440
insert function. So we're going to start

3
00:00:08,440 --> 00:00:09,910
off with the same code that we've used

4
00:00:09,910 --> 00:00:11,740
in the two other functions. We're going to

5
00:00:11,740 --> 00:00:14,139
check the URI and get a result back from

6
00:00:14,139 --> 00:00:15,969
the uriMatcher. So what I'm going to

7
00:00:15,969 --> 00:00:18,390
do is just take a copy of the code that

8
00:00:18,390 --> 00:00:21,130
we've used in the query function, and

9
00:00:21,130 --> 00:00:23,650
come down and we're going to start by

10
00:00:23,650 --> 00:00:26,260
pasting that over the TODO in our

11
00:00:26,260 --> 00:00:30,010
insert function. Now the code that uses

12
00:00:30,010 --> 00:00:31,869
this function will often need to know

13
00:00:31,869 --> 00:00:34,780
the ID of the new row, so this function

14
00:00:34,780 --> 00:00:38,800
returns a URI that includes the ID. Now

15
00:00:38,800 --> 00:00:40,899
the function accepts a URI without an ID

16
00:00:40,899 --> 00:00:43,899
and returns the same URI with an ID

17
00:00:43,899 --> 00:00:47,739
added. So let's start coding this, and one

18
00:00:47,739 --> 00:00:49,089
thing we are going to do slightly

19
00:00:49,089 --> 00:00:51,190
differently to the query method, is get a

20
00:00:51,190 --> 00:00:53,679
writable database object in each of

21
00:00:53,679 --> 00:00:55,210
these cases. So let's start by typing

22
00:00:55,210 --> 00:01:01,510
some code. So val recordId : Long and

23
00:01:01,510 --> 00:01:06,159
then val returnUri :

24
00:01:06,159 --> 00:01:11,700
Uri. Alright, so we now need to add a

25
00:01:11,700 --> 00:01:14,680
block here, a when match block, so I'm

26
00:01:14,680 --> 00:01:17,580
going to type when and parentheses match,

27
00:01:17,580 --> 00:01:21,070
then left and right curly braces. We want

28
00:01:21,070 --> 00:01:23,380
to go through and check firstly for TASKS.

29
00:01:23,380 --> 00:01:27,180
So TASKS, add the arrow as we normally do

30
00:01:27,180 --> 00:01:29,980
for a when, and then in there we're going

31
00:01:29,980 --> 00:01:33,610
to type val db equals AppDatabase dot

32
00:01:33,610 --> 00:01:37,330
getInstance, in parentheses context, and

33
00:01:37,330 --> 00:01:41,560
dot writableDatabase. I'm going to do

34
00:01:41,560 --> 00:01:44,230
exactly the same thing and take a copy

35
00:01:44,230 --> 00:01:49,840
OF those three lines for the TIMINGS, for

36
00:01:49,840 --> 00:01:55,000
TIMINGS as well. Alright. So in the query

37
00:01:55,000 --> 00:01:56,800
method we've got a readableDatabase

38
00:01:56,800 --> 00:01:59,140
from our AppDatabase. Here, for obvious

39
00:01:59,140 --> 00:02:00,909
reasons, because we're inserting data,

40
00:02:00,909 --> 00:02:03,040
inserting new rows, we're getting a

41
00:02:03,040 --> 00:02:05,590
writableDatabase instead. Now the get

42
00:02:05,590 --> 00:02:07,479
ReadableDatabase and getWritable

43
00:02:07,479 --> 00:02:09,758
Database functions can be quite slow, so

44
00:02:09,758 --> 00:02:12,010
we want to avoid calling them if an

45
00:02:12,010 --> 00:02:15,310
invalid URI's used. Now we do that in

46
00:02:15,310 --> 00:02:17,139
the query function by not calling get

47
00:02:17,139 --> 00:02:17,860
ReadableData

48
00:02:17,860 --> 00:02:20,860
base until after the switch. If the URI

49
00:02:20,860 --> 00:02:23,740
was invalid, an exception is thrown and

50
00:02:23,740 --> 00:02:25,960
the final bit of code isn't executed. In

51
00:02:25,960 --> 00:02:28,600
the insert method we need to use the db

52
00:02:28,600 --> 00:02:31,180
in each of our cases. Now it might look more

53
00:02:31,180 --> 00:02:32,410
natural to get the writable

54
00:02:32,410 --> 00:02:34,930
Database before the when, but that means

55
00:02:34,930 --> 00:02:36,910
we'll be calling getWritableDatabase

56
00:02:36,910 --> 00:02:39,130
before we've checked that the URI is

57
00:02:39,130 --> 00:02:41,320
valid. The other thing to note here, is

58
00:02:41,320 --> 00:02:43,450
that we're not using the TASK_ 

59
00:02:43,450 --> 00:02:46,720
DURATIONS URI values. The database

60
00:02:46,720 --> 00:02:48,880
view is only used for querying the

61
00:02:48,880 --> 00:02:51,880
database, not for writing to it. That

62
00:02:51,880 --> 00:02:53,500
means we don't need to include it in the

63
00:02:53,500 --> 00:02:57,160
insert, update or delete functions. Now as

64
00:02:57,160 --> 00:02:59,170
well as the URI, this function will

65
00:02:59,170 --> 00:03:01,870
receive a ContentValues object holding

66
00:03:01,870 --> 00:03:03,700
the values to insert. We'll look at

67
00:03:03,700 --> 00:03:05,739
ContentValues later. Firstly, what I'm

68
00:03:05,739 --> 00:03:08,620
going to do is add an else here and then I'm

69
00:03:08,620 --> 00:03:10,690
going to add the code for inserting into

70
00:03:10,690 --> 00:03:15,520
the two tables. So for our when, else, in

71
00:03:15,520 --> 00:03:17,320
that case with the arrow we're

72
00:03:17,320 --> 00:03:19,780
going to throw an IllegalArgument

73
00:03:19,780 --> 00:03:24,519
Exception, parentheses, we're going to put

74
00:03:24,519 --> 00:03:29,019
Unknown uri colon then a dollar

75
00:03:29,019 --> 00:03:30,310
sign uri, just so we've got something

76
00:03:30,310 --> 00:03:32,350
to show on the screen.

77
00:03:32,350 --> 00:03:35,650
And in terms of writing the database, or

78
00:03:35,650 --> 00:03:37,330
writing to the database, we're going to

79
00:03:37,330 --> 00:03:40,810
put recordId is equal to db.insert,

80
00:03:40,810 --> 00:03:43,060
and in parentheses it's going to be the

81
00:03:43,060 --> 00:03:45,430
name of our table. In this case it's Tasks

82
00:03:45,430 --> 00:03:48,450
Contract.TABLE_NAME comma

83
00:03:48,450 --> 00:03:54,790
null comma values. And for the TIMINGS what

84
00:03:54,790 --> 00:03:55,870
we're going to do is something very

85
00:03:55,870 --> 00:03:59,910
similar, recordId equals db.insert.

86
00:03:59,910 --> 00:04:02,850
This time it'll be the TimingsContract

87
00:04:02,850 --> 00:04:08,890
dot TABLE_NAME comma null comma values. So

88
00:04:08,890 --> 00:04:12,190
the insertion's done by the db's insert

89
00:04:12,190 --> 00:04:14,650
function. Now we give it the name of the

90
00:04:14,650 --> 00:04:16,478
table to insert into and the list of

91
00:04:16,478 --> 00:04:19,000
values to insert. So whatever the Content

92
00:04:19,000 --> 00:04:21,370
Values object is we're just passing that

93
00:04:21,370 --> 00:04:23,830
on to the database insert method. So if

94
00:04:23,830 --> 00:04:24,850
you have a quick look at the Content

95
00:04:24,850 --> 00:04:27,729
Values up here in the parameters, you can

96
00:04:27,729 --> 00:04:30,099
see here that it says "This class is used to

97
00:04:30,099 --> 00:04:31,389
store a set of values

98
00:04:31,389 --> 00:04:33,550
that the ContentResolver can process".

99
00:04:33,550 --> 00:04:36,069
It's very similar to a bundle, in fact,

100
00:04:36,069 --> 00:04:38,020
and we'll look at this in more detail

101
00:04:38,020 --> 00:04:40,900
when we come to create a ContentValues

102
00:04:40,900 --> 00:04:42,759
object, which we'll do when we use this

103
00:04:42,759 --> 00:04:45,689
insert function. So close that down, and

104
00:04:45,689 --> 00:04:47,919
remember that we changed the function

105
00:04:47,919 --> 00:04:49,930
signature earlier. There's no point

106
00:04:49,930 --> 00:04:51,639
trying to insert no values into the

107
00:04:51,639 --> 00:04:54,009
table, so we made the ContentValues

108
00:04:54,009 --> 00:04:57,159
parameter a non null type by removing

109
00:04:57,159 --> 00:04:59,080
the question mark. Now the second

110
00:04:59,080 --> 00:05:00,639
parameter here, which we're passing null

111
00:05:00,639 --> 00:05:02,919
to - you can see here the name is null

112
00:05:02,919 --> 00:05:05,319
ColumnHack - that's an interesting name,

113
00:05:05,319 --> 00:05:07,389
and if we have a look at the insert

114
00:05:07,389 --> 00:05:10,569
statement here. So open the documentation

115
00:05:10,569 --> 00:05:13,360
for that - it talks about what that is. So

116
00:05:13,360 --> 00:05:15,580
basically, if every column except the

117
00:05:15,580 --> 00:05:17,919
underscore ID column of course, can

118
00:05:17,919 --> 00:05:20,110
accept null values, then the values

119
00:05:20,110 --> 00:05:22,060
parameter might contain nothing but

120
00:05:22,060 --> 00:05:22,539
nulls.

121
00:05:22,539 --> 00:05:24,759
Now SQLite doesn't allow the SQL

122
00:05:24,759 --> 00:05:26,770
insert statement that will result from

123
00:05:26,770 --> 00:05:28,509
that. There'd be no column names

124
00:05:28,509 --> 00:05:30,909
specified and a statement wouldn't be

125
00:05:30,909 --> 00:05:32,979
valid SQL. So in that case you'd

126
00:05:32,979 --> 00:05:34,599
specify a column for this second

127
00:05:34,599 --> 00:05:36,729
parameter, just to make the SQL

128
00:05:36,729 --> 00:05:39,069
statement valid. But there's not a lot of

129
00:05:39,069 --> 00:05:41,020
point really inserting a completely null

130
00:05:41,020 --> 00:05:43,539
record most of the time, but it is

131
00:05:43,539 --> 00:05:45,819
possible, and if you needed to do it for

132
00:05:45,819 --> 00:05:47,919
some reason then you just specify one of

133
00:05:47,919 --> 00:05:50,770
your table columns for that argument. Now

134
00:05:50,770 --> 00:05:53,050
our tables won't accept a completely null

135
00:05:53,050 --> 00:05:55,539
record. The names column is set to be not

136
00:05:55,539 --> 00:05:57,430
null, so therefore we don't need to worry

137
00:05:57,430 --> 00:05:59,680
about this parameter and we can safely

138
00:05:59,680 --> 00:06:01,469
ignore it by passing null.

139
00:06:01,469 --> 00:06:05,319
Now if the insert works the db insert

140
00:06:05,319 --> 00:06:08,229
function will return the ID of the new

141
00:06:08,229 --> 00:06:11,500
row. So what we can do is make sure that

142
00:06:11,500 --> 00:06:13,960
it's not returned as -1, the

143
00:06:13,960 --> 00:06:15,279
value's not returned as -1,

144
00:06:15,279 --> 00:06:18,279
and then append it to the URI using a

145
00:06:18,279 --> 00:06:20,650
contractBuildUriFromId method, if

146
00:06:20,650 --> 00:06:22,870
that's the case. Now if the return value

147
00:06:22,870 --> 00:06:25,569
is -1 then the insert failed,

148
00:06:25,569 --> 00:06:27,610
and we saw that in the documentation for

149
00:06:27,610 --> 00:06:29,680
the db insert method. In that case we'll

150
00:06:29,680 --> 00:06:32,650
throw an exception, just briefly again, it

151
00:06:32,650 --> 00:06:34,599
talks about here "or -1 if an

152
00:06:34,599 --> 00:06:37,419
error occurred". So let's write the code

153
00:06:37,419 --> 00:06:40,539
for that. So under the recordId we're

154
00:06:40,539 --> 00:06:41,899
going to put if

155
00:06:41,899 --> 00:06:47,129
recordId is not equal to -1, then

156
00:06:47,129 --> 00:06:48,869
we're going, actually what we need to

157
00:06:48,869 --> 00:06:50,279
do there also - and I'll talk about this

158
00:06:50,279 --> 00:06:52,589
in a moment - we need to put the L 

159
00:06:52,589 --> 00:06:55,080
after the -1 to say that it's a

160
00:06:55,080 --> 00:06:57,270
Long. So if it's not equal to 

161
00:06:57,270 --> 00:06:59,869
-1 you're going to put returnUri

162
00:06:59,869 --> 00:07:05,669
equals TasksContract.buildUri

163
00:07:05,669 --> 00:07:09,569
FromId recordId. Then what we're going

164
00:07:09,569 --> 00:07:11,219
to do is have an else there, and the else

165
00:07:11,219 --> 00:07:14,309
will be else throw, in this case we're

166
00:07:14,309 --> 00:07:16,740
going to throw an SQL exception with the

167
00:07:16,740 --> 00:07:21,779
message "Fail to insert, Uri was

168
00:07:21,779 --> 00:07:26,099
Łuri". So that's essentially

169
00:07:26,099 --> 00:07:28,679
the logic there, and I'm going to take a copy

170
00:07:28,679 --> 00:07:31,949
of this code because it's very similar and I'll

171
00:07:31,949 --> 00:07:36,269
paste that for the TIMINGS, the TIMINGS

172
00:07:36,269 --> 00:07:37,979
code, and I'm going to change Tasks

173
00:07:37,979 --> 00:07:40,529
Contract here. That's going to be equal

174
00:07:40,529 --> 00:07:45,899
to TimingsContract. Now in relation to

175
00:07:45,899 --> 00:07:49,259
this -1L, Kotlin doesn't allow a

176
00:07:49,259 --> 00:07:51,479
comparison between long and int, which is

177
00:07:51,479 --> 00:07:53,339
why we have to compare our recordId to

178
00:07:53,339 --> 00:07:56,249
-1l, to specify the long value

179
00:07:56,249 --> 00:07:58,379
-1, and you saw that there was an

180
00:07:58,379 --> 00:08:00,899
error there if I left the L out. And as you

181
00:08:00,899 --> 00:08:02,789
saw the code for the TIMINGS case is

182
00:08:02,789 --> 00:08:04,469
almost identical. You just use the

183
00:08:04,469 --> 00:08:06,659
constants from TimingsContract instead

184
00:08:06,659 --> 00:08:08,279
of TasksContract. You can see that I've

185
00:08:08,279 --> 00:08:11,219
made those two changes to cater for the

186
00:08:11,219 --> 00:08:12,839
fact that that's different to the Tasks

187
00:08:12,839 --> 00:08:15,689
Contract for the tasks component. And

188
00:08:15,689 --> 00:08:18,300
just to finish off now we need to come

189
00:08:18,300 --> 00:08:21,179
down here. We need to return something so

190
00:08:21,179 --> 00:08:22,319
we're going to do some logging first. So

191
00:08:22,319 --> 00:08:25,979
Log.d parentheses TAG comma, and we'll

192
00:08:25,979 --> 00:08:31,009
type Exiting insert, returning $

193
00:08:31,009 --> 00:08:36,019
returnUri, and we're just going to return

194
00:08:36,019 --> 00:08:38,448
returnUri.

195
00:08:38,448 --> 00:08:42,779
that's essentially our insert method. The

196
00:08:42,779 --> 00:08:44,579
update method, which we'll start working

197
00:08:44,579 --> 00:08:47,009
on in the next video, is a mix of query and

198
00:08:47,009 --> 00:08:49,139
insert. It's code will be very similar to

199
00:08:49,139 --> 00:08:52,019
query but we won't return a cursor. Now

200
00:08:52,019 --> 00:08:54,059
when inserting, we're only inserting a

201
00:08:54,059 --> 00:08:55,440
single record at a time.

202
00:08:55,440 --> 00:08:57,449
When updating though, we may update the

203
00:08:57,449 --> 00:08:59,759
columns of a single row, or in fact we

204
00:08:59,759 --> 00:09:02,220
could update many rows at once. You might,

205
00:09:02,220 --> 00:09:03,779
for example, want to update the Sort

206
00:09:03,779 --> 00:09:06,480
Order column for all tasks with, say the same

207
00:09:06,480 --> 00:09:08,370
description. So we'll start working on

208
00:09:08,370 --> 00:09:10,500
writing that update function in the next

209
00:09:10,500 --> 00:09:12,740
video.

